From 53e58af35c46140a05b3ce4dcec9e425ca359529 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 29 Jul 2026 20:16:13 +0200 Subject: new folder structer --- src/board/board.cpp | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/board/board.hpp | 101 +++++++++++++++++++++ src/board/fen.cpp | 147 +++++++++++++++++++++++++++++++ src/board/fen.hpp | 9 ++ 4 files changed, 504 insertions(+) create mode 100644 src/board/board.cpp create mode 100644 src/board/board.hpp create mode 100644 src/board/fen.cpp create mode 100644 src/board/fen.hpp (limited to 'src/board') diff --git a/src/board/board.cpp b/src/board/board.cpp new file mode 100644 index 0000000..a76ec42 --- /dev/null +++ b/src/board/board.cpp @@ -0,0 +1,247 @@ +#include "board.hpp" +#include "../moves.hpp" +#include "zobrist/zobrist.hpp" +#include + +Piece createPiece(PieceType type, bool color) { + Piece piece; + piece.type = type; + piece.color = color; + return piece; +} + +int PositionToIndex(Position i) { return i.rank * 8 + i.file; } + +Position FindKing(Game *b, bool white) { + for (int i = 0; i < 64; i++) { + Piece piece = b->pieces[i]; + + if (piece.type == KING && piece.color == white) { + return IndexToPosition(i); + } + } + + assert(false && "King not found"); + return {0, 0}; +} +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.OldwhiteCastleKing = g->whiteCastleKing; + undo.OldwhiteCastleQueen = g->whiteCastleQueen; + undo.OldblackCastleKing = g->blackCastleKing; + undo.OldblackCastleQueen = g->blackCastleQueen; + + // play move + Piece piece = g->pieces[PositionToIndex(move.From)]; + Piece piece2 = g->pieces[PositionToIndex(move.To)]; + + if (piece2.type != NONEPIECE) { + if (piece2.color == g->turn) { + assert(false && "capturing friendly piece error"); + } + } + + // clock + g->MoveClock++; + if (piece.type == PAWN || piece2.type != NONEPIECE) { + 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, NONEPIECE}; + + 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 == NONEPIECE ? QUEEN : move.promotion; + } + + // caslte + if (piece.type == KING && move.From.rank == (piece.color ? 0 : 7) && + (move.From.file + 2 == move.To.file || + move.From.file - 2 == move.To.file)) { + + 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}; + rook_pos = move.From; + rook_pos.file -= 1; + g->pieces[PositionToIndex(rook_pos)] = rook; + } + 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}; + rook_pos = move.From; + rook_pos.file += 1; + g->pieces[PositionToIndex(rook_pos)] = rook; + } + }; + + // 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}; + + // 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 UnMakeMove(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->whiteCastleKing = undo.OldwhiteCastleKing; + g->whiteCastleQueen = undo.OldwhiteCastleQueen; + g->blackCastleKing = undo.OldblackCastleKing; + g->blackCastleQueen = undo.OldblackCastleQueen; + + 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/board.hpp b/src/board/board.hpp new file mode 100644 index 0000000..7d0cb3f --- /dev/null +++ b/src/board/board.hpp @@ -0,0 +1,101 @@ +#ifndef SRC_BOARD_H_ +#define SRC_BOARD_H_ + +#include +#include + +enum PieceType { + NONEPIECE, + PAWN, + KNIGHT, + BISHOP, + ROOK, + QUEEN, + KING, +}; + +enum GameState { + TURN, + WHITE_WON, + BLACK_WON, + STALEMATE, + DRAW, +}; + +struct Piece { + bool color = 0; + PieceType type = NONEPIECE; +}; + +struct Position { + uint8_t rank = 0; + uint8_t file = 0; + + bool operator==(const Position &) const = default; +}; +struct TranspositionsEntry { + int depth; + float Eval; +}; +struct Game { + Piece pieces[64]; + bool turn = 1; // 1 white; 0 black + bool whiteCastleKing = false; + bool whiteCastleQueen = false; + bool blackCastleKing = false; + bool blackCastleQueen = false; + uint8_t halfMoveClock = 0; + uint16_t MoveClock = 0; + Position enPassant; + bool canEnpassant = 0; + GameState state = TURN; + std::unordered_map ThreeFoldMap; + std::unordered_map *Transpositions = nullptr; +}; + +struct Move { + Position From; + Position To; + + PieceType promotion = NONEPIECE; + bool operator==(const Move &other) const { + return From == other.From && To == other.To && promotion == other.promotion; + } +}; +struct UndoMove { + Piece movedPiece; + Piece capturedPiece; + + Position from; + Position to; + + bool wasEnPassantCapture = false; + Position enPassantCapturedSquare; + Piece enPassantCapturedPiece; + + bool oldTurn; + bool oldCanEnpassant; + Position oldEnPassant; + + 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); + +int PositionToIndex(Position i); +UndoMove MakeMove(Move move, Game *g); +void UnMakeMove(UndoMove undo, Game *g); + +Position FindKing(Game *b, bool white); +#endif /* SRC_BOARD_H_ */ diff --git a/src/board/fen.cpp b/src/board/fen.cpp new file mode 100644 index 0000000..4b8686e --- /dev/null +++ b/src/board/fen.cpp @@ -0,0 +1,147 @@ +#include "fen.hpp" +#include "board.hpp" +#include +#include +#include +#include + +bool WHITE = true; +bool BLACK = false; + +void setBoardFen(std::string fen, Game *b) { + // example fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 + int file = 0; + int rank = 0; + + enum parserState { + POSITION, + TURN, + CASTLE, + ENPASSANT, + CLOCK1, + CLOCK2, + }; + parserState state = POSITION; + + for (uint i = 0; i < fen.length(); i++) { + if (fen[i] == ' ') { + if (state == POSITION) { + state = TURN; + continue; + } + if (state == TURN) { + state = CASTLE; + continue; + } + if (state == CASTLE) { + state = ENPASSANT; + continue; + } + if (state == ENPASSANT) { + state = CLOCK1; + continue; + } + if (state == CLOCK1) { + state = CLOCK2; + continue; + } + } + if (state == ENPASSANT) { + continue; + } + if (state == CASTLE) { + if (fen[i] == '-') { + b->blackCastleKing = false; + b->blackCastleQueen = false; + b->whiteCastleKing = false; + b->whiteCastleQueen = false; + continue; + } + if (fen[i] == 'K') { + b->whiteCastleKing = true; + continue; + } + if (fen[i] == 'Q') { + b->whiteCastleQueen = true; + continue; + } + if (fen[i] == 'k') { + b->blackCastleKing = true; + continue; + } + if (fen[i] == 'q') { + b->blackCastleQueen = true; + continue; + } + } + if (state == TURN) { + if (toupper(fen[i]) == 'W') { + b->turn = WHITE; + continue; + } + if (toupper(fen[i]) == 'B') { + b->turn = BLACK; + continue; + } + } + if (state == POSITION) { + if (isdigit(fen[i])) { + int move = fen[i] - '0'; + file += move; + if (file > 8) { + std::println("Fatal: file was to big"); + exit(1); + return; // malformed rank + } + continue; + } + if (fen[i] == '/') { + file = 0; + rank++; + if (rank >= 8) { + std::println("Fatal: rank was to big"); + exit(1); + return; // malformed rank + } + continue; + }; + if (toupper(fen[i]) == 'N') { + Piece piece = createPiece(KNIGHT, isupper(fen[i])); + b->pieces[rank * 8 + file] = piece; + file++; + continue; + }; + if (toupper(fen[i]) == 'R') { + Piece piece = createPiece(ROOK, isupper(fen[i])); + b->pieces[rank * 8 + file] = piece; + file++; + continue; + } + if (toupper(fen[i]) == 'Q') { + Piece piece = createPiece(QUEEN, isupper(fen[i])); + b->pieces[rank * 8 + file] = piece; + file++; + continue; + } + if (toupper(fen[i]) == 'B') { + Piece piece = createPiece(BISHOP, isupper(fen[i])); + b->pieces[rank * 8 + file] = piece; + file++; + continue; + } + if (toupper(fen[i]) == 'P') { + Piece piece = createPiece(PAWN, isupper(fen[i])); + b->pieces[rank * 8 + file] = piece; + file++; + continue; + } + if (toupper(fen[i]) == 'K') { + Piece piece = createPiece(KING, isupper(fen[i])); + b->pieces[rank * 8 + file] = piece; + file++; + continue; + } + } + break; + } +} diff --git a/src/board/fen.hpp b/src/board/fen.hpp new file mode 100644 index 0000000..406f5fe --- /dev/null +++ b/src/board/fen.hpp @@ -0,0 +1,9 @@ +#ifndef SRC_FEN_H_ +#define SRC_FEN_H_ + +#include + +#include "board.hpp" + +void setBoardFen(std::string fen, Game *b); +#endif /* SRC_FEN_H_ */ -- cgit v1.2.3