|
|
const inside = (r, c) => r >= 0 && r < 8 && c >= 0 && c < 8;
|
|
|
const owner = (piece) => Math.abs(piece) - 1;
|
|
|
|
|
|
function movesFor(board, from, capturesOnly = false) {
|
|
|
const piece = board[from];
|
|
|
if (!piece) return [];
|
|
|
const r = Math.floor(from / 8),
|
|
|
c = from % 8;
|
|
|
const rows = piece < 0 ? [-1, 1] : owner(piece) === 0 ? [-1] : [1];
|
|
|
const moves = [];
|
|
|
if (piece < 0) {
|
|
|
for (const dr of rows)
|
|
|
for (const dc of [-1, 1]) {
|
|
|
let captured;
|
|
|
for (let distance = 1; ; distance++) {
|
|
|
const nr = r + distance * dr,
|
|
|
nc = c + distance * dc;
|
|
|
if (!inside(nr, nc)) break;
|
|
|
const to = nr * 8 + nc;
|
|
|
if (board[to]) {
|
|
|
if (captured !== undefined || owner(board[to]) === owner(piece))
|
|
|
break;
|
|
|
captured = to;
|
|
|
} else if (captured !== undefined) {
|
|
|
moves.push({ type: 'move', from, to, capture: captured });
|
|
|
} else if (!capturesOnly) {
|
|
|
moves.push({ type: 'move', from, to });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return moves;
|
|
|
}
|
|
|
for (const dr of rows)
|
|
|
for (const dc of [-1, 1]) {
|
|
|
const nr = r + dr,
|
|
|
nc = c + dc;
|
|
|
if (!inside(nr, nc)) continue;
|
|
|
const to = nr * 8 + nc;
|
|
|
if (!capturesOnly && !board[to]) moves.push({ type: 'move', from, to });
|
|
|
const jr = r + 2 * dr,
|
|
|
jc = c + 2 * dc;
|
|
|
if (
|
|
|
board[to] &&
|
|
|
owner(board[to]) !== owner(piece) &&
|
|
|
inside(jr, jc) &&
|
|
|
!board[jr * 8 + jc]
|
|
|
) {
|
|
|
moves.push({ type: 'move', from, to: jr * 8 + jc, capture: to });
|
|
|
}
|
|
|
}
|
|
|
return moves;
|
|
|
}
|
|
|
|
|
|
export const checkers = {
|
|
|
id: 'damas',
|
|
|
version: '2.0.0',
|
|
|
minPlayers: 2,
|
|
|
maxPlayers: 2,
|
|
|
create() {
|
|
|
return {
|
|
|
board: Array.from({ length: 64 }, (_, i) => {
|
|
|
const r = Math.floor(i / 8),
|
|
|
c = i % 8;
|
|
|
return (r + c) % 2 === 0 ? 0 : r < 3 ? 2 : r > 4 ? 1 : 0;
|
|
|
}),
|
|
|
turn: 0,
|
|
|
chain: null,
|
|
|
quietMoves: 0,
|
|
|
};
|
|
|
},
|
|
|
/** @returns {{type: string, from: number, to: number, capture?: number}[]} */
|
|
|
legal(state, seat) {
|
|
|
if (seat !== state.turn) return [];
|
|
|
if (state.chain !== null) return movesFor(state.board, state.chain, true);
|
|
|
const moves = state.board.flatMap((piece, i) =>
|
|
|
piece && owner(piece) === seat ? movesFor(state.board, i) : [],
|
|
|
);
|
|
|
const captures = moves.filter((m) => m.capture !== undefined);
|
|
|
return captures.length ? captures : moves;
|
|
|
},
|
|
|
apply(state, action, seat) {
|
|
|
const legal = this.legal(state, seat).find(
|
|
|
(m) =>
|
|
|
m.type === action.type && m.from === action.from && m.to === action.to,
|
|
|
);
|
|
|
if (!legal)
|
|
|
throw new Error(
|
|
|
'Movimiento ilegal. Recuerda que la captura es obligatoria.',
|
|
|
);
|
|
|
const board = [...state.board];
|
|
|
const piece = board[legal.from];
|
|
|
board[legal.from] = 0;
|
|
|
board[legal.to] = piece;
|
|
|
if (legal.capture !== undefined) board[legal.capture] = 0;
|
|
|
const crowned = piece > 0 && (seat === 0 ? legal.to < 8 : legal.to >= 56);
|
|
|
if (crowned) board[legal.to] = -piece;
|
|
|
const chain =
|
|
|
legal.capture !== undefined &&
|
|
|
!crowned &&
|
|
|
movesFor(board, legal.to, true).length
|
|
|
? legal.to
|
|
|
: null;
|
|
|
const next = {
|
|
|
board,
|
|
|
turn: chain !== null ? seat : 1 - seat,
|
|
|
chain,
|
|
|
quietMoves:
|
|
|
legal.capture !== undefined || crowned ? 0 : state.quietMoves + 1,
|
|
|
};
|
|
|
let result = null;
|
|
|
if (chain === null && !this.legal(next, next.turn).length)
|
|
|
result = { winner: seat, reason: 'sin movimientos disponibles' };
|
|
|
else if (next.quietMoves >= 80)
|
|
|
result = { winner: null, reason: '40 turnos sin captura ni coronación' };
|
|
|
return {
|
|
|
state: next,
|
|
|
label: `${legal.from + 1}${legal.capture !== undefined ? ' × ' : ' → '}${legal.to + 1}`,
|
|
|
result,
|
|
|
sound: result
|
|
|
? 'finish'
|
|
|
: crowned
|
|
|
? 'promotion'
|
|
|
: legal.capture !== undefined
|
|
|
? 'capture'
|
|
|
: 'move',
|
|
|
};
|
|
|
},
|
|
|
view(state) {
|
|
|
return state;
|
|
|
},
|
|
|
};
|