#include "board.hpp" #include "bot.hpp" #include "zobrist.hpp" #include #include #include #include #include std::string toChar(PieceType type, bool white) { switch (type) { case NONE: return " "; case KING: return white ? "♚" : "♔"; case QUEEN: return white ? "♛" : "♕"; case ROOK: return white ? "♜" : "♖"; case BISHOP: return white ? "♝" : "♗"; case KNIGHT: return white ? "♞" : "♘"; case PAWN: return white ? "♟" : "♙"; default: assert(false && "Unknown piece"); return " "; } } Piece createPiece(PieceType type, bool color, bool moved) { Piece piece; piece.type = type; piece.color = color; piece.moved = moved; return piece; } void printBoard(Game *b) { std::string line = " +------------------------+\n"; std::string whiteLetters = " a b c d e f g h \n"; std::string blackLetters = " h g f e d c b a \n"; // const char *lightSquare = "\033[48;5;145m"; // // const char *darkSquare = "\033[48;5;28m"; // const char *lightSquare = "\033[48;5;240m"; // Dark gray // const char *darkSquare = "\033[48;5;22m"; // Forest green const char *lightSquare = "\033[48;5;245m"; // Medium gray const char *darkSquare = "\033[48;5;29m"; // Rich green const char *reset = "\033[0m"; std::cout << (b->turn ? whiteLetters : blackLetters); std::cout << line; if (b->turn) { for (int rank = 0; rank < 8; rank++) { std::printf("%d |", 8 - rank); for (int file = 0; file < 8; file++) { Piece piece = b->pieces[rank * 8 + file]; std::string symbol = toChar(piece.type, piece.color); const char *bg = ((rank + file) % 2 == 0) ? lightSquare : darkSquare; std::cout << bg << " " << symbol << " " << reset; } std::printf("| %d\n", 8 - rank); } } else { for (int rank = 7; rank >= 0; rank--) { std::printf("%d |", 8 - rank); for (int file = 7; file >= 0; file--) { Piece piece = b->pieces[rank * 8 + file]; std::string symbol = toChar(piece.type, piece.color); const char *bg = ((rank + file) % 2 == 0) ? lightSquare : darkSquare; std::cout << bg << " " << symbol << " " << reset; } std::printf("| %d\n", 8 - rank); } } std::cout << line; std::cout << (b->turn ? whiteLetters : blackLetters); std::println(); std::println("Turn: {}", b->turn ? "White" : "Black"); assert(b->castle != ""); std::println("Castling: {}", b->castle); std::println("Can enpassant: {}", b->canEnpassant ? "Yes" : "No"); std::println("Where enpassant: {}{}", (char)((int)b->enPassant.file + 'A'), 8 - (int)b->enPassant.rank); std::printf("Move clock: %d\n", b->MoveClock); std::printf("Half move clock: %d\n", b->halfMoveClock); std::printf("Board Eval: %f\n", EvaluateBoardForWhite(b)); } void PlayMove(Move move, Game *b) { // TODO: add all fide behavior Piece piece = b->pieces[PositionToIndex(move.From)]; Piece piece2 = b->pieces[PositionToIndex(move.To)]; if (piece2.type != NONE) { if (piece2.color == b->turn) { assert(false && "capturing friendly piece error"); } } piece.moved = true; if (piece.type == PAWN || piece2.type != NONE) { b->halfMoveClock = 0; } else { b->halfMoveClock++; } if (piece.type == PAWN && b->canEnpassant && move.To == b->enPassant) { Position capturedPawn = move.To; capturedPawn.rank += piece.color ? 1 : -1; b->pieces[PositionToIndex(capturedPawn)] = {false, NONE, false}; } b->canEnpassant = false; b->MoveClock++; if (piece.type == PAWN) { Position to = move.To; to.rank -= (piece.color ? -2 : 2); if (to == move.From) { b->canEnpassant = true; Position target = move.From; target.rank += piece.color ? -1 : 1; b->enPassant = target; }; } if (piece.type == PAWN && move.To.rank == (piece.color ? 0 : 7)) { // TODO parse the promote type from uci isntead of ignoreting it piece.type = move.promotion == NONE ? QUEEN : move.promotion; } if (b->halfMoveClock >= 50) { b->state = DRAW; } b->pieces[PositionToIndex(move.To)] = piece; b->pieces[PositionToIndex(move.From)] = {false, NONE, false}; b->turn = !b->turn; uint64_t key = GenerateZobristKey(b); b->ThreeFoldMap[key]++; if (b->ThreeFoldMap[key] >= 3) { b->state = DRAW; } }; int PositionToIndex(Position i) { return i.rank * 8 + i.file; } UndoMove MakeMove(Move move, Game *g) { UndoMove undo = {}; undo.from = move.From; undo.to = move.To; undo.movedPiece = g->pieces[PositionToIndex(move.From)]; undo.capturedPiece = g->pieces[PositionToIndex(move.To)]; undo.oldTurn = g->turn; undo.oldCanEnpassant = g->canEnpassant; undo.oldEnPassant = g->enPassant; undo.oldHalfMoveClock = g->halfMoveClock; undo.oldMoveClock = g->MoveClock; undo.oldState = g->state; undo.oldCaslte = g->castle; // play move Piece piece = g->pieces[PositionToIndex(move.From)]; Piece piece2 = g->pieces[PositionToIndex(move.To)]; if (piece2.type != NONE) { if (piece2.color == g->turn) { assert(false && "capturing friendly piece error"); } } piece.moved = true; // clock g->MoveClock++; if (piece.type == PAWN || piece2.type != NONE) { g->halfMoveClock = 0; } else { g->halfMoveClock++; } // Playing enpasstant 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, NONE, false}; undo.wasEnPassantCapture = true; undo.enPassantCapturedSquare = capturedPawn; undo.enPassantCapturedPiece = g->pieces[PositionToIndex(capturedPawn)]; } g->canEnpassant = false; // Adding enpassant if (piece.type == PAWN) { Position to = move.To; to.rank -= (piece.color ? -2 : 2); if (to == move.From) { g->canEnpassant = true; Position target = move.From; target.rank += piece.color ? -1 : 1; g->enPassant = target; }; } // Promotions if (piece.type == PAWN && move.To.rank == (piece.color ? 0 : 7)) { // TODO parse the promote type from uci isntead of ignoreting it piece.type = move.promotion == NONE ? QUEEN : move.promotion; } // setting the moves g->pieces[PositionToIndex(move.To)] = piece; g->pieces[PositionToIndex(move.From)] = {false, NONE, false}; // post move change // changing who turn it is g->turn = !g->turn; // 3 fold check uint64_t key = GenerateZobristKey(g); undo.zobristKey = key; g->ThreeFoldMap[key]++; if (g->ThreeFoldMap[key] >= 3) { g->state = DRAW; } if (g->halfMoveClock >= 50) { g->state = DRAW; } return undo; }; void UnMake(UndoMove undo, Game *g) { g->pieces[PositionToIndex(undo.from)] = undo.movedPiece; g->pieces[PositionToIndex(undo.to)] = undo.capturedPiece; if (undo.wasEnPassantCapture) { g->pieces[PositionToIndex(undo.enPassantCapturedSquare)] = undo.enPassantCapturedPiece; } g->turn = undo.oldTurn; g->canEnpassant = undo.oldCanEnpassant; g->enPassant = undo.oldEnPassant; g->halfMoveClock = undo.oldHalfMoveClock; g->MoveClock = undo.oldMoveClock; g->state = undo.oldState; g->castle = undo.oldCaslte; if (--g->ThreeFoldMap[undo.zobristKey] <= 0) { g->ThreeFoldMap.erase(undo.zobristKey); } };