From 1d6a6717ba088c3b89d50021f2bf6656eb564533 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 29 Jul 2026 16:18:52 +0200 Subject: implementing castling --- src/board.cpp | 127 +++++++++++++++++++++++++++++++++++++++----------------- src/board.hpp | 20 ++++++--- src/fen.cpp | 24 +++++++---- src/moves.cpp | 3 +- src/uci.cpp | 2 - src/zobrist.cpp | 8 ++-- 6 files changed, 125 insertions(+), 59 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index cbad8cb..ce116a1 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -1,13 +1,11 @@ #include "board.hpp" #include "zobrist.hpp" #include -#include -Piece createPiece(PieceType type, bool color, bool moved) { +Piece createPiece(PieceType type, bool color) { Piece piece; piece.type = type; piece.color = color; - piece.moved = moved; return piece; } @@ -30,7 +28,11 @@ UndoMove MakeMove(Move move, Game *g) { undo.oldMoveClock = g->MoveClock; undo.oldState = g->state; - undo.oldCaslte = g->castle; + + undo.OldwhiteCastleKing = g->whiteCastleKing; + undo.OldwhiteCastleQueen = g->whiteCastleQueen; + undo.OldblackCastleKing = g->blackCastleKing; + undo.OldblackCastleQueen = g->blackCastleQueen; // play move @@ -42,7 +44,6 @@ UndoMove MakeMove(Move move, Game *g) { assert(false && "capturing friendly piece error"); } } - piece.moved = true; // clock g->MoveClock++; @@ -56,7 +57,7 @@ UndoMove MakeMove(Move move, Game *g) { if (piece.type == PAWN && g->canEnpassant && move.To == g->enPassant) { Position capturedPawn = move.To; capturedPawn.rank += piece.color ? 1 : -1; - g->pieces[PositionToIndex(capturedPawn)] = {false, NONEPIECE, false}; + g->pieces[PositionToIndex(capturedPawn)] = {false, NONEPIECE}; undo.wasEnPassantCapture = true; undo.enPassantCapturedSquare = capturedPawn; @@ -82,42 +83,19 @@ UndoMove MakeMove(Move move, Game *g) { // TODO parse the promote type from uci isntead of ignoreting it piece.type = move.promotion == NONEPIECE ? QUEEN : move.promotion; } - assert(g->castle != ""); // caslte if (piece.type == KING && move.From.rank == (piece.color ? 0 : 7) && - g->castle != "-" && (move.From.file + 2 == move.To.file || move.From.file - 2 == move.To.file)) { - bool caslteSide = - (move.From.file > move.To.file); // 0 queen side, 1 king side - char castleCharacter = - (caslteSide ? (piece.color ? 'K' : 'k') : (piece.color ? 'Q' : 'q')); - std::string newCastleString = ""; - if (g->castle.contains('Q') && 'Q' != castleCharacter) { - newCastleString += 'Q'; - }; - if (g->castle.contains('K') && 'K' != castleCharacter) { - newCastleString += 'K'; - }; - if (g->castle.contains('q') && 'q' != castleCharacter) { - newCastleString += 'q'; - }; - if (g->castle.contains('k') && 'k' != castleCharacter) { - newCastleString += 'k'; - }; - if (newCastleString == "") { - newCastleString = "-"; - }; - g->castle = newCastleString; - + undo.wasCastle = true; + undo.CastledSide = (move.To.file > move.From.file); if (move.From.file + 2 == move.To.file) { Position rook_pos = move.To; rook_pos.file += 1; Piece rook = g->pieces[PositionToIndex(rook_pos)]; - g->pieces[PositionToIndex(rook_pos)] = {false, NONEPIECE, false}; - rook.moved = true; + g->pieces[PositionToIndex(rook_pos)] = {false, NONEPIECE}; rook_pos = move.From; rook_pos.file -= 1; g->pieces[PositionToIndex(rook_pos)] = rook; @@ -126,17 +104,61 @@ UndoMove MakeMove(Move move, Game *g) { Position rook_pos = move.To; rook_pos.file -= 1; Piece rook = g->pieces[PositionToIndex(rook_pos)]; - g->pieces[PositionToIndex(rook_pos)] = {false, NONEPIECE, false}; - rook.moved = true; + g->pieces[PositionToIndex(rook_pos)] = {false, NONEPIECE}; rook_pos = move.From; rook_pos.file += 1; g->pieces[PositionToIndex(rook_pos)] = rook; } }; - // setting the moves + // removing caslte rights + if (piece.type == KING) { + if (piece.color) { + g->whiteCastleKing = false; + g->whiteCastleQueen = false; + } else { + g->blackCastleKing = false; + g->blackCastleQueen = false; + } + } + + // this part was written by ai + if (piece.type == ROOK) { + if (piece.color) { // White + if (move.From.rank == 7 && move.From.file == 0) // a1 + g->whiteCastleQueen = false; + + if (move.From.rank == 7 && move.From.file == 7) // h1 + g->whiteCastleKing = false; + } else { // Black + if (move.From.rank == 0 && move.From.file == 0) // a8 + g->blackCastleQueen = false; + + if (move.From.rank == 0 && move.From.file == 7) // h8 + g->blackCastleKing = false; + } + } + + // this part is also written with ai + if (piece2.type == ROOK) { + if (piece2.color) { // White rook captured + if (move.To.rank == 7 && move.To.file == 0) // a1 + g->whiteCastleQueen = false; + + if (move.To.rank == 7 && move.To.file == 7) // h1 + g->whiteCastleKing = false; + } else { // Black rook captured + if (move.To.rank == 0 && move.To.file == 0) // a8 + g->blackCastleQueen = false; + + if (move.To.rank == 0 && move.To.file == 7) // h8 + g->blackCastleKing = false; + } + } + + // playing the moves g->pieces[PositionToIndex(move.To)] = piece; - g->pieces[PositionToIndex(move.From)] = {false, NONEPIECE, false}; + g->pieces[PositionToIndex(move.From)] = {false, NONEPIECE}; // changing who turn it is g->turn = !g->turn; @@ -178,9 +200,36 @@ void UnMakeMove(UndoMove undo, Game *g) { g->state = undo.oldState; - g->castle = undo.oldCaslte; + g->whiteCastleKing = undo.OldwhiteCastleKing; + g->whiteCastleQueen = undo.OldwhiteCastleQueen; + g->blackCastleKing = undo.OldblackCastleKing; + g->blackCastleQueen = undo.OldblackCastleQueen; - if (--g->ThreeFoldMap[undo.zobristKey] <= 0) { - g->ThreeFoldMap.erase(undo.zobristKey); + if (undo.wasCastle) { + if (undo.CastledSide) { + // rook f-file -> h-file + Position rookFrom = undo.to; + rookFrom.file -= 1; // f1/f8 + + Position rookTo = undo.to; + rookTo.file += 1; // h1/h8 + + g->pieces[PositionToIndex(rookTo)] = g->pieces[PositionToIndex(rookFrom)]; + g->pieces[PositionToIndex(rookFrom)] = {false, NONEPIECE}; + } else { + // rook d-file -> a-file + Position rookFrom = undo.to; + rookFrom.file += 1; // d1/d8 + + Position rookTo = undo.to; + rookTo.file -= 2; // a1/a8 + + g->pieces[PositionToIndex(rookTo)] = g->pieces[PositionToIndex(rookFrom)]; + g->pieces[PositionToIndex(rookFrom)] = {false, NONEPIECE}; + } } + g->ThreeFoldMap[undo.zobristKey] -= 1; + if (g->ThreeFoldMap[undo.zobristKey] <= 0) { + g->ThreeFoldMap.erase(undo.zobristKey); + }; }; diff --git a/src/board.hpp b/src/board.hpp index 4f04783..2e8cb82 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -2,7 +2,6 @@ #define SRC_BOARD_H_ #include -#include #include enum PieceType { @@ -26,7 +25,6 @@ enum GameState { struct Piece { bool color = 0; PieceType type = NONEPIECE; - bool moved = false; }; struct Position { @@ -42,7 +40,10 @@ struct TranspositionsEntry { struct Game { Piece pieces[64]; bool turn = 1; // 1 white; 0 black - std::string castle = ""; + bool whiteCastleKing = false; + bool whiteCastleQueen = false; + bool blackCastleKing = false; + bool blackCastleQueen = false; uint8_t halfMoveClock = 0; uint16_t MoveClock = 0; Position enPassant; @@ -75,13 +76,22 @@ struct UndoMove { bool oldTurn; bool oldCanEnpassant; Position oldEnPassant; - std::string oldCaslte; + + bool OldwhiteCastleKing; + bool OldwhiteCastleQueen; + bool OldblackCastleKing; + bool OldblackCastleQueen; + int oldHalfMoveClock; int oldMoveClock; uint64_t zobristKey; GameState oldState; + + // castling + bool wasCastle = false; + bool CastledSide = false; // 0 for queen side, 1 for king side }; -Piece createPiece(PieceType type, bool color, bool moved = false); +Piece createPiece(PieceType type, bool color); int PositionToIndex(Position i); UndoMove MakeMove(Move move, Game *g); diff --git a/src/fen.cpp b/src/fen.cpp index 7597143..4b8686e 100644 --- a/src/fen.cpp +++ b/src/fen.cpp @@ -13,8 +13,6 @@ void setBoardFen(std::string fen, Game *b) { int file = 0; int rank = 0; - std::string castle = ""; - enum parserState { POSITION, TURN, @@ -53,15 +51,26 @@ void setBoardFen(std::string fen, Game *b) { } if (state == CASTLE) { if (fen[i] == '-') { - castle = "-"; + b->blackCastleKing = false; + b->blackCastleQueen = false; + b->whiteCastleKing = false; + b->whiteCastleQueen = false; continue; } - if (toupper(fen[i]) == 'K') { - castle += fen[i]; + if (fen[i] == 'K') { + b->whiteCastleKing = true; continue; } - if (toupper(fen[i]) == 'Q') { - castle += fen[i]; + if (fen[i] == 'Q') { + b->whiteCastleQueen = true; + continue; + } + if (fen[i] == 'k') { + b->blackCastleKing = true; + continue; + } + if (fen[i] == 'q') { + b->blackCastleQueen = true; continue; } } @@ -135,5 +144,4 @@ void setBoardFen(std::string fen, Game *b) { } break; } - b->castle = castle.empty() ? "-" : castle; } diff --git a/src/moves.cpp b/src/moves.cpp index edf6c1e..008020d 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -1,13 +1,14 @@ #include #include #include +#include #include #include #include "board.hpp" #include "moves.hpp" -void GenerateKnightMoves(Game *b, int from, std::vector &moves) { +void GenerateKnightMoves(Game *b, int from, std::vector &moves) { Piece knight = b->pieces[from]; if (knight.type != KNIGHT) { assert(false && "Calling generate knight moves on non knight"); diff --git a/src/uci.cpp b/src/uci.cpp index 310d31c..8a7ad9a 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -83,7 +83,6 @@ Game initBoard( b.canEnpassant = false; b.state = TURN; b.turn = true; - b.castle = ""; b.halfMoveClock = 0; b.MoveClock = 0; b.Transpositions = transPositions; @@ -91,7 +90,6 @@ Game initBoard( Piece EmptyPiece = { false, NONEPIECE, - false, }; for (int i = 0; i < 64; i++) { b.pieces[i] = EmptyPiece; diff --git a/src/zobrist.cpp b/src/zobrist.cpp index 05d4cf2..cfc7769 100644 --- a/src/zobrist.cpp +++ b/src/zobrist.cpp @@ -49,16 +49,16 @@ uint64_t GenerateZobristKey(Game *b) { // castling int castle = 0; - if (b->castle.find('K') != std::string::npos) + if (b->whiteCastleKing) castle |= 1; - if (b->castle.find('Q') != std::string::npos) + if (b->whiteCastleQueen) castle |= 2; - if (b->castle.find('k') != std::string::npos) + if (b->blackCastleKing) castle |= 4; - if (b->castle.find('q') != std::string::npos) + if (b->blackCastleQueen) castle |= 8; key ^= CastleKeys[castle]; -- cgit v1.2.3