aboutsummaryrefslogtreecommitdiff
path: root/src/board
diff options
context:
space:
mode:
authorAdam <adammegarules1@gmail.com>2026-07-29 20:16:13 +0200
committerAdam <adammegarules1@gmail.com>2026-07-29 20:16:13 +0200
commit53e58af35c46140a05b3ce4dcec9e425ca359529 (patch)
treed4531fddfbcfaa50d920a5598ade3ec535de8340 /src/board
parentd528a20684570fb70f0e6b13a78bc6504a1edd89 (diff)
new folder structer
Diffstat (limited to 'src/board')
-rw-r--r--src/board/board.cpp247
-rw-r--r--src/board/board.hpp101
-rw-r--r--src/board/fen.cpp147
-rw-r--r--src/board/fen.hpp9
4 files changed, 504 insertions, 0 deletions
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 <cassert>
+
+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 <cstdint>
+#include <unordered_map>
+
+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<uint64_t, int> ThreeFoldMap;
+ std::unordered_map<uint64_t, TranspositionsEntry> *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 <cctype>
+#include <cstdlib>
+#include <print>
+#include <string>
+
+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 <string>
+
+#include "board.hpp"
+
+void setBoardFen(std::string fen, Game *b);
+#endif /* SRC_FEN_H_ */