feat: generate correctly moves in SAN notaion

This commit is contained in:
Cozma Rares
2023-08-03 01:02:42 +03:00
parent 4b1488b427
commit abda45d393
2 changed files with 86 additions and 11 deletions
+22 -4
View File
@@ -16,13 +16,31 @@ const History: React.FC<{
const bg = idk % 2 == 0 ? "bg-zinc-600" : "";
if (idx % 2 == 0)
history.push(<span className={`px-2 ${bg}`}>{idk}.</span>);
history.push(<span className={bg}>{san}</span>);
history.push(
<span key={idx} className={`px-2 ${bg}`}>
{idk}.
</span>
);
history.push(
<span key={idx + san} className={bg}>
{san}
</span>
);
});
if (history.length % 3)
history.push(
<span
key="__history-last__"
className={((history.length + 1) / 3) % 2 == 0 ? "bg-zinc-600" : ""}
></span>
);
return (
<div className="bg-zinc-800 rounded-lg text-white grid grid-rows-[1fr,auto]">
<div className="p-4 min-w-[10rem] h-fit max-h-full overflow-auto grid grid-cols-[auto,1fr,1fr] gap-y-2 text-center [&>:nth-child(3n)]:rounded-r-md [&>:nth-child(3n-2)]:rounded-l-md">
<div className="bg-zinc-800 rounded-lg text-white grid grid-rows-[auto,1fr,auto]">
<div className="text-xl text-center my-1 mx-4 border-b ">History</div>
{/* FIX: scroll*/}
<div className="p-4 min-w-[10rem] h-fit overflow-scroll grid grid-cols-[auto,1fr,1fr] gap-y-2 text-center [&>:nth-child(3n)]:rounded-r-md [&>:nth-child(3n-2)]:rounded-l-md">
{history}
</div>
<div className="bg-black grid auto-cols-fr grid-flow-col gap-5 p-4 rounded-b-lg">
+64 -7
View File
@@ -68,6 +68,7 @@ export const MOVE_FLAGS = Object.freeze({
export type MoveFlag = (typeof MOVE_FLAGS)[keyof typeof MOVE_FLAGS];
export type InternalMove = {
piece: Piece;
from: Square;
to: Square;
promotion?: PiecePromotionType;
@@ -341,6 +342,7 @@ function generatePawnMoves(
PIECE_PROMOTION.forEach((piece) =>
moves.push({
piece: { type: PIECE.PAWN, color },
from: fromAlgebraic,
to: toAlgebraic,
promotion: piece,
@@ -357,6 +359,7 @@ function generatePawnMoves(
generatePromotionMoves(position, nextPosition, MOVE_FLAGS.NORMAL);
else {
moves.push({
piece: { type: PIECE.PAWN, color },
from: algebraic(position),
to: algebraic(nextPosition),
flags: MOVE_FLAGS.NORMAL,
@@ -367,6 +370,7 @@ function generatePawnMoves(
if (board[jumpPosition] == null)
moves.push({
piece: { type: PIECE.PAWN, color },
from: algebraic(position),
to: algebraic(jumpPosition),
flags: MOVE_FLAGS.PAWN_JUMP,
@@ -390,6 +394,7 @@ function generatePawnMoves(
generatePromotionMoves(position, attackPosition, MOVE_FLAGS.CAPTURE);
else
moves.push({
piece: { type: PIECE.PAWN, color },
from: algebraic(position),
to: algebraic(attackPosition),
flags: isPiece ? MOVE_FLAGS.CAPTURE : MOVE_FLAGS.EN_PASSANT,
@@ -423,12 +428,14 @@ export function generatePieceMoves(
if (attackedPiece == null)
moves.push({
piece,
from: algebraic(position),
to: algebraic(nextPosition),
flags: MOVE_FLAGS.NORMAL,
});
else if (attackedPiece.color != piece.color)
moves.push({
piece,
from: algebraic(position),
to: algebraic(nextPosition),
flags: MOVE_FLAGS.CAPTURE,
@@ -451,6 +458,7 @@ export function generatePieceMoves(
if (attackedPiece == null) {
moves.push({
piece,
from: algebraic(position),
to: algebraic(nextPosition),
flags: MOVE_FLAGS.NORMAL,
@@ -463,6 +471,7 @@ export function generatePieceMoves(
if (attackedPiece.color != piece.color)
moves.push({
piece,
from: algebraic(position),
to: algebraic(nextPosition),
flags: MOVE_FLAGS.CAPTURE,
@@ -570,6 +579,7 @@ export default class Chess {
canCastleThrough(kingsKnightPosition, otherColor)
)
this._moves.push({
piece: { type: PIECE.KING, color },
from: algebraic(kingPosition),
to: algebraic(kingsKnightPosition),
flags: MOVE_FLAGS.K_CASTLE,
@@ -582,6 +592,7 @@ export default class Chess {
canCastleThrough(queensKnightPosition, otherColor)
)
this._moves.push({
piece: { type: PIECE.KING, color },
from: algebraic(kingPosition),
to: algebraic(queensBishopPosition),
flags: MOVE_FLAGS.Q_CASTLE,
@@ -762,10 +773,11 @@ export default class Chess {
const myColor = this._turn;
const theirColor = swapColor(this._turn);
this._history.push({
fen: this.getFEN(),
san: this._generateSan(move),
});
if (this._enableProcessMoves)
this._history.push({
fen: this.getFEN(),
san: this._generateSan(move),
});
this._board[squareIndex(move.to)] =
move.flags & MOVE_FLAGS.PROMOTION
@@ -773,7 +785,7 @@ export default class Chess {
type: move.promotion as PieceType,
color: myColor,
}
: this._board[squareIndex(move.from)];
: move.piece;
this._board[squareIndex(move.from)] = null;
let keepEpSquare = false;
@@ -830,9 +842,54 @@ export default class Chess {
this._processBoardState();
}
// TODO: implement
private _sanDisambiguator(ambiguousMove: InternalMove) {
let ambiguities = 0,
sameFile = 0,
sameRank = 0;
this._moves.forEach((move) => {
if (
move.piece.type == ambiguousMove.piece.type &&
move.piece.color == ambiguousMove.piece.color &&
move.to == ambiguousMove.to &&
move.from != ambiguousMove.from
) {
ambiguities++;
if (move.from[1] == ambiguousMove.from[1]) sameRank++;
if (move.from[0] == ambiguousMove.from[0]) sameFile++;
}
});
let disambiguated = "";
if (sameRank * sameFile > 0) disambiguated = ambiguousMove.from;
else if (sameFile > 0) disambiguated = ambiguousMove.from[1];
else if (sameRank > 0) disambiguated = ambiguousMove.from[0];
else if (ambiguities > 0) disambiguated = ambiguousMove.from[0];
return disambiguated;
}
private _generateSan(move: InternalMove) {
return `${move.from} ${move.to}`;
const pieceType =
move.piece.type == PIECE.PAWN ? "" : move.piece.type.toUpperCase();
let san = "";
if (move.flags & MOVE_FLAGS.K_CASTLE) san = "O-O";
else if (move.flags & MOVE_FLAGS.Q_CASTLE) san = "O-O-O";
else if (move.flags & MOVE_FLAGS.CAPTURE)
san = pieceType + this._sanDisambiguator(move) + "x" + move.to;
else san = pieceType + this._sanDisambiguator(move) + move.to;
if (move.promotion) san += `= ${move.promotion.toUpperCase()} `;
const chess = Chess._load(this.getFEN(), false);
chess._makeMove(move);
if (chess.isCheckMate()) san += "#";
else if (chess.isCheck()) san += "+";
return san;
}
makeMove(move: Move) {