// © 2025 A.M. Rowsell // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is "Incompatible With Secondary Licenses", as // defined by the Mozilla Public License, v. 2.0. #include "inc/Board.hpp" #include "inc/strFuncs.hpp" /* * This is how the chessboard is organized in memory * This handy dandy chart should help me from getting totally * confused! * * FILE 0 1 2 3 4 5 6 7 * 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' * +-----+-----+-----+-----+-----+-----+-----+-----+ * RANK 0 | A1 | B1 | C1 | D1 | E1 | F1 | G1 | H1 | boardGrid[0][0] to boardGrid[0][7] * RANK 1 | A2 | B2 | C2 | D2 | E2 | F2 | G2 | H2 | boardGrid[1][0] to boardGrid[1][7] * RANK 2 | A3 | B3 | C3 | D3 | E3 | F3 | G3 | H3 | ... * RANK 3 | A4 | B4 | C4 | D4 | E4 | F4 | G4 | H4 | * RANK 4 | A5 | B5 | C5 | D5 | E5 | F5 | G5 | H5 | * RANK 5 | A6 | B6 | C6 | D6 | E6 | F6 | G6 | H6 | * RANK 6 | A7 | B7 | C7 | D7 | E7 | F7 | G7 | H7 | * RANK 7 | A8 | B8 | C8 | D8 | E8 | F8 | G8 | H8 | boardGrid[7][0] to boardGrid[7][7] * +-----+-----+-----+-----+-----+-----+-----+-----+ * */ Board::Board() { boardGrid.resize(8); for(int i = 0; i < 8; i++) boardGrid[i].resize(8); } Board::~Board() { } void Board::setupInitialPosition() { // set up the board grid with smart pointers // initialize each square with a Piece or nullptr playerTurn = PL_WHITE; for(int i = 0; i < 8; i++) { switch(i) { case 0: // white back rank boardGrid[i][0] = std::make_unique(PIECE_WHITE); boardGrid[i][1] = std::make_unique(PIECE_WHITE); boardGrid[i][2] = std::make_unique(PIECE_WHITE); boardGrid[i][3] = std::make_unique(PIECE_WHITE); boardGrid[i][4] = std::make_unique(PIECE_WHITE); boardGrid[i][5] = std::make_unique(PIECE_WHITE); boardGrid[i][6] = std::make_unique(PIECE_WHITE); boardGrid[i][7] = std::make_unique(PIECE_WHITE); break; case 1: // white pawn rank for(int j = 0; j <= 8; j++) boardGrid[i][j] = std::make_unique(PIECE_WHITE); break; case 2: case 3: case 4: case 5: for(int j = 0; j <= 8; j++) boardGrid[i][j] = nullptr; break; case 6: // black pawn rank for(int j = 0; j <= 8; j++) boardGrid[i][j] = std::make_unique(PIECE_BLACK); break; case 7: // black back rank boardGrid[i][0] = std::make_unique(PIECE_BLACK); boardGrid[i][1] = std::make_unique(PIECE_BLACK); boardGrid[i][2] = std::make_unique(PIECE_BLACK); boardGrid[i][3] = std::make_unique(PIECE_BLACK); boardGrid[i][4] = std::make_unique(PIECE_BLACK); boardGrid[i][5] = std::make_unique(PIECE_BLACK); boardGrid[i][6] = std::make_unique(PIECE_BLACK); boardGrid[i][7] = std::make_unique(PIECE_BLACK); default: break; } } return; } int Board::setupFromFEN(std::string strFEN) { std::vector splitFEN = split(strFEN, ' '); if(splitFEN.size() != 6) // a valid FEN *must* contain 6 fields return -1; // ====== START OF FIELD 1 ====== std::vector splitField1 = split(splitFEN[0], '/'); int rank = 0, file = 0; int skip = 0; bool wKingPlaced = false, bKingPlaced = false; for(auto &ranks : splitField1) { for(auto &sym : ranks) { switch(sym) { case 'R': // white rook boardGrid[rank][file] = std::make_unique(PIECE_WHITE); break; case 'r': // black rook boardGrid[rank][file] = std::make_unique(PIECE_BLACK); break; case 'N': // white knight boardGrid[rank][file] = std::make_unique(PIECE_WHITE); break; case 'n': // black knight boardGrid[rank][file] = std::make_unique(PIECE_BLACK); break; case 'B': // white bishop boardGrid[rank][file] = std::make_unique(PIECE_WHITE); break; case 'b': // black bishop boardGrid[rank][file] = std::make_unique(PIECE_BLACK); break; case 'Q': // white queen boardGrid[rank][file] = std::make_unique(PIECE_WHITE); break; case 'q': // black queen; boardGrid[rank][file] = std::make_unique(PIECE_BLACK); break; case 'K': // white king if(wKingPlaced) { // invalid FEN, more than 1 white king return -1; } else { boardGrid[rank][file] = std::make_unique(PIECE_WHITE); wKingPlaced = true; } break; case 'k': // black king if(bKingPlaced) { // invalid FEN, more than 1 black king return -1; } else { boardGrid[rank][file] = std::make_unique(PIECE_BLACK); bKingPlaced = true; } break; case 'P': // white pawn boardGrid[rank][file] = std::make_unique(PIECE_WHITE); break; case 'p': // black pawn boardGrid[rank][file] = std::make_unique(PIECE_BLACK); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': 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); break; } default: // invalid character? return -1; break; } file++; if(file > 7) { file = 0; break; } } rank++; if(rank > 7) break; } // ======= END OF FIELD 1 ====== // ======= START OF FIELD 2 ====== std::string w = "w"; std::string b = "b"; if(splitFEN[1] == w) playerTurn = PL_WHITE; else if(splitFEN[1] == b) playerTurn = PL_BLACK; else { // invalid FEN return -1; } // ====== END OF FIELD 2 ====== // ====== START OF FIELD 3 ====== std::string k = "k", K = "K", q = "q", Q = "Q"; if(splitFEN[2] == "-") { // nobody can castle, either side // locate Kings and set appropriate variables // canCastleKS, canCastleQS } if(splitFEN[2].find(k) != std::string::npos) { // black king can castle kingside } if(splitFEN[2].find(K) != std::string::npos) { // white king can castle kingside } if(splitFEN[2].find(q) != std::string::npos) { // black king can castle queenside } if(splitFEN[2].find(Q) != std::string::npos) { // white king can castle queenside } return 0; } void Board::movePiece(Square from, Square to) { return; } void Board::deserializeBoard(uint64_t incomingBoard) { uint8_t boardRows[8]; for(int i = 0; i < 8; i++) boardRows[i] = (incomingBoard >> (8 * i)) & 0xFF; // how do we then figure out what has moved? return; } std::unique_ptr &Board::getPieceAt(Square square) { return boardGrid[square.rank][square.file]; }