import { INVALID_MOVE } from "boardgame.io/core";
function IsVictory(cells) {
const positions = [
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11],
[12, 13, 14, 15],
[0, 4, 8, 12],
[1, 5, 9, 13],
[2, 6, 10, 14],
[3, 7, 11, 15],
[0, 1, 4, 5],
[1, 2, 5, 6],
[2, 3, 6, 7],
[4, 5, 8, 9],
[5, 6, 9, 10],
[6, 7, 10, 11],
[8, 9, 12, 13],
[9, 10, 13, 14],
[10, 11, 14, 15],
];
const isRowComplete = (row) => {
const symbols = row.map((i) => cells[i]);
return symbols.every((i) => i !== null && i === symbols[0]);
};
return positions.map(isRowComplete).some((i) => i === true);
}
const UnshuffledDeck = [
"A1",
"A2",
"A3",
"A4",
"B1",
"B2",
"B3",
"B4",
"C1",
"C2",
"C3",
"C4",
"D1",
"D2",
"D3",
"D4",
];
const BORDER_TILE_IDS = [0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15];
function validMove(cell, id, lastPlayedTile) {
if (lastPlayedTile === null) {
return BORDER_TILE_IDS.includes(id);
}
return cell[0] === lastPlayedTile[0] || cell[1] === lastPlayedTile[1];
}
function unclaimed(tile) {
return !(tile === 0 || tile === 1);
}
export const Okiya = {
minPlayers: 2,
maxPlayers: 2,
turn: {
minMoves: 1,
maxMoves: 1
},
ai: {
enumerate: (G, ctx) => {
let moves = [];
for (let i = 0; i < 16; i++) {
if (unclaimed(G.cells[i]) && validMove(G.cells[i], i, G.lastPlayed)) {
moves.push({ move: "clickCell", args: [i] });
}
}
return moves;
},
},
setup: ({ctx, random}) => ({
cells: random.Shuffle(UnshuffledDeck),
lastPlayed: null,
}),
moves: {
clickCell({ G, playerID }, id) {
if (unclaimed(G.cells[id]) && validMove(G.cells[id], id, G.lastPlayed)) {
G.lastPlayed = G.cells[id];
G.cells[id] = playerID;
} else {
return INVALID_MOVE;
}
},
},
endIf: ({G, ctx}) => {
if (IsVictory(G.cells)) {
return { winner: ctx.currentPlayer, stalemate: false, draw: false };
}
if (G.cells.filter(unclaimed).length === 0) {
return { draw: true };
}
let numMoves = Okiya.ai.enumerate(G, ctx).length;
if (numMoves === 0) {
return {
winner: ctx.currentPlayer,
stalemate: true,
};
}
},
};