From e5a124d1935137f0777d50b7c1f4455699f88d2f Mon Sep 17 00:00:00 2001 From: "A.M. Rowsell" Date: Sat, 30 Aug 2025 18:45:04 -0400 Subject: [PATCH 1/2] FEN: major portion of FEN import is working and tested --- Board.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/Board.cpp b/Board.cpp index 68f61bf..86cf960 100644 --- a/Board.cpp +++ b/Board.cpp @@ -97,6 +97,7 @@ int Board::setupFromFEN(std::string strFEN) { std::vector splitField1 = split(splitFEN[0], '/'); int rank = 0, file = 0; int skip = 0; + Square whiteKing, blackKing; bool wKingPlaced = false, bKingPlaced = false; for(auto &ranks : splitField1) { for(auto &sym : ranks) { @@ -104,34 +105,42 @@ int Board::setupFromFEN(std::string strFEN) { case 'R': // white rook boardGrid[rank][file] = std::make_unique(PIECE_WHITE); + file++; break; case 'r': // black rook boardGrid[rank][file] = std::make_unique(PIECE_BLACK); + file++; break; case 'N': // white knight boardGrid[rank][file] = std::make_unique(PIECE_WHITE); + file++; break; case 'n': // black knight boardGrid[rank][file] = std::make_unique(PIECE_BLACK); + file++; break; case 'B': // white bishop boardGrid[rank][file] = std::make_unique(PIECE_WHITE); + file++; break; case 'b': // black bishop boardGrid[rank][file] = std::make_unique(PIECE_BLACK); + file++; break; case 'Q': // white queen boardGrid[rank][file] = std::make_unique(PIECE_WHITE); + file++; break; case 'q': // black queen; boardGrid[rank][file] = std::make_unique(PIECE_BLACK); + file++; break; case 'K': // white king @@ -141,6 +150,10 @@ int Board::setupFromFEN(std::string strFEN) { } else { boardGrid[rank][file] = std::make_unique(PIECE_WHITE); wKingPlaced = true; + // store king position for later + whiteKing.file = file; + whiteKing.rank = rank; + file++; } break; case 'k': @@ -151,15 +164,21 @@ int Board::setupFromFEN(std::string strFEN) { } else { boardGrid[rank][file] = std::make_unique(PIECE_BLACK); bKingPlaced = true; + // store king position for later + blackKing.file = file; + blackKing.rank = rank; + file++; } break; case 'P': // white pawn boardGrid[rank][file] = std::make_unique(PIECE_WHITE); + file++; break; case 'p': // black pawn boardGrid[rank][file] = std::make_unique(PIECE_BLACK); + file++; break; case '1': case '2': @@ -171,11 +190,10 @@ int Board::setupFromFEN(std::string strFEN) { case '8': { std::string skipStr(1, sym); skip = atoi(skipStr.c_str()); - skip--; // fix off by 1 error - do { - boardGrid[rank][file] = nullptr; // remove reference - file = (file < 8) ? file + 1 : 0; - } while(--skip); + //skip--; // fix off by 1 error + while(skip--) { + boardGrid[rank][file++] = nullptr; // remove reference + } break; } default: @@ -183,7 +201,6 @@ int Board::setupFromFEN(std::string strFEN) { return -1; break; } - file++; if(file > 7) { file = 0; break; @@ -208,23 +225,47 @@ int Board::setupFromFEN(std::string strFEN) { // ====== END OF FIELD 2 ====== // ====== START OF FIELD 3 ====== std::string k = "k", K = "K", q = "q", Q = "Q"; + auto &bKing = this->getPieceAt(blackKing); + auto &wKing = this->getPieceAt(whiteKing); if(splitFEN[2] == "-") { // nobody can castle, either side - // locate Kings and set appropriate variables - // canCastleKS, canCastleQS + bKing->setCastleKS(false); + bKing->setCastleQS(false); + wKing->setCastleKS(false); + wKing->setCastleQS(false); } if(splitFEN[2].find(k) != std::string::npos) { // black king can castle kingside + bKing->setCastleKS(true); } if(splitFEN[2].find(K) != std::string::npos) { // white king can castle kingside + wKing->setCastleKS(true); } if(splitFEN[2].find(q) != std::string::npos) { // black king can castle queenside + bKing->setCastleQS(true); } if(splitFEN[2].find(Q) != std::string::npos) { // white king can castle queenside + wKing->setCastleQS(true); } + // ====== END OF FIELD 3 ====== + // ====== START OF FIELD 4 ====== + // if a pawn has just moved and can be attacked enPassant, it will be listed here + + +#ifdef DEBUG + for(auto &ranks : boardGrid) { + for(auto &files : ranks) { + if(files) + std::cout << files->getPieceName() << " "; + else + std::cout << "E "; + } + std::cout << "\n"; + } +#endif return 0; } From 6773da28fbd9d716a8eac75ca6b1dc692c998994 Mon Sep 17 00:00:00 2001 From: "A.M. Rowsell" Date: Sat, 30 Aug 2025 18:46:18 -0400 Subject: [PATCH 2/2] Piece: expanding getLegalMoves for Queen/Knight/Bishop --- Piece.cpp | 53 +++++++++++++++++++++++++++++++++++- inc/Board.hpp | 2 ++ inc/Piece.hpp | 12 +++++++- nbproject/configurations.xml | 8 ++++-- 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Piece.cpp b/Piece.cpp index ccfd82a..a9d81ad 100644 --- a/Piece.cpp +++ b/Piece.cpp @@ -12,6 +12,9 @@ Piece::~Piece() { return; } +// TODO: Add operator overload for << to allow easy printing +// TODO: Test getPieceAt() function to see if it works as intended + // because the Piece class is instantiated in another class using // unique_ptr, non-pure virtual functions apparently *must* // have definitions, or the linker freaks out @@ -164,7 +167,7 @@ std::vector Rook::getLegalMoves(const Square &from, Board &board) const { {0, -1}, // Left {0, 1} // Right }; - for(auto& dir : directions) { + for(auto &dir : directions) { int r = from.rank + dir[0]; int f = from.file + dir[1]; while(r >= 0 && r < 8 && f >= 0 && f < 8) { @@ -188,16 +191,64 @@ std::vector Rook::getLegalMoves(const Square &from, Board &board) const { std::vector Queen::getLegalMoves(const Square &from, Board &board) const { std::vector moveList; + std::vector> directions = { + {-1, 0}, // Up + {-1, -1}, // up-left + {-1, 1}, // up-right + {1, 0}, // Down + {1, -1}, // down-left + {1, 1}, // down-right + {0, -1}, // Left + {0, 1} // Right + }; + for(auto &dir : directions) { + // establish r/f for square to check + int r = from.rank + dir[0]; + int f = from.file + dir[1]; + auto ra = static_cast(r); + auto fi = static_cast(f); + Square targetSquare = {ra, fi}; + while(r >= 0 && r < 8 && f >= 0 && f < 8) { + const auto &target = board.boardGrid[r][f]; // examine the target square + if(!target) { // if square is empty (NULL) + moveList.push_back({from, targetSquare}); // then it's potentially a legal move + } else if(target && target->getColour() != this->getColour()) { // if it's occupied with a piece of opposite colour + moveList.push_back({from, targetSquare}); // then again it's potentially legal + break; + } else { + // otherwise it's one of our pieces + break; + } + r += dir[0]; + f += dir[1]; + } + } return moveList; } std::vector Knight::getLegalMoves(const Square &from, Board &board) const { std::vector moveList; + std::vector> directions = { + {-1, -2}, + {-1, 2}, + {-2, -1}, + {-2, 1}, + {1, -2}, + {1, 2}, + {2, -1}, + {2, 1} + }; return moveList; } std::vector Bishop::getLegalMoves(const Square &from, Board &board) const { std::vector moveList; + std::vector> directions = { + {-1, -1}, // up-left + {-1, 1}, // up-right + {1, -1}, // down-left + {1, 1}, // down-right + }; return moveList; } diff --git a/inc/Board.hpp b/inc/Board.hpp index 599b29e..286437f 100644 --- a/inc/Board.hpp +++ b/inc/Board.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "Piece.hpp" @@ -32,6 +33,7 @@ public: std::vector>> boardGrid; Board(); virtual ~Board(); + void setupInitialPosition(); std::unique_ptr &getPieceAt(Square square); void movePiece(Square from, Square to); diff --git a/inc/Piece.hpp b/inc/Piece.hpp index 15132dd..af0d3cf 100644 --- a/inc/Piece.hpp +++ b/inc/Piece.hpp @@ -8,7 +8,6 @@ #ifndef PIECE_HPP #define PIECE_HPP -#pragma once #include #include @@ -115,6 +114,13 @@ class King : public Piece { else return false; } + + void setCastleQS(bool canCastle) { + canCastleQS = canCastle; + } + void setCastleKS(bool canCastle) { + canCastleKS = canCastle; + } protected: bool canCastleQS = true; bool canCastleKS = true; @@ -179,6 +185,10 @@ class Pawn : public Piece { pieceType = PAWN; } virtual std::vector getLegalMoves(const Square &from, Board &board) const override; + void promote(const Square &promotionSquare, Board &board, PieceType promoteTo); +protected: + bool vulnEnPassant = false; + bool firstMove = true; }; #endif // PIECE_HPP diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 28d6976..bda203e 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -4,10 +4,10 @@ - Board.hpp - Piece.hpp - NeoPixel.hpp inc/strFuncs.hpp + inc/Board.hpp + inc/NeoPixel.hpp + inc/Piece.hpp +