// © 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 "Piece.hpp" Piece::~Piece() { return; } // 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 // so this is just a stub that does nothing. it doesn't matter // because only the derived class versions should be called. std::vector Piece::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; return moveList; } std::vector King::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; const int directions[8][2] = { {-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]; if(r >= 0 && r < 8 && f >= 0 && f < 8) { const auto &target = board.boardGrid[r][f]; // examine the target square auto ra = static_cast(r); auto fi = static_cast(f); Square targetSquare = {ra, fi}; 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; } } } // How to check for check: // go through moveList.to, then check all directions to see if an enemy piece is threatening // If a piece of opposite colour is detected: // - Determine the piece type // - Determine the direction we are looking at (diagonal or not) // - If that piece can attack in that direction, it would be check, so remove this move from moveList for(auto &moves : moveList) { Square startSquare = moves.to; // get the potential move to square for(auto &dir : directions) { // now go through all directions int r = startSquare.rank + dir[0]; int f = startSquare.file + dir[1]; bool diagonal = (abs(dir[0]) + abs(dir[1]) == 2) ? 1 : 0; // check if diagonal while(r >= 0 && r < 8 && f >= 0 && f < 8) { auto &target = board.boardGrid[r][f]; // check what's at the square we're examining if(target && target->getColour() != this->getColour()) { // is it occupied & an enemy? if((target->getPieceType() == QUEEN || target->getPieceType() == BISHOP) && diagonal) { // we are being attacked diagonally on this square, so remove it //moves.to.rank = 255; moves.to.file = 255; // mark as invalid??? } } } } } return moveList; } std::vector Rook::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; const int directions[4][2] = { {-1, 0}, // Up {1, 0}, // Down {0, -1}, // Left {0, 1} // Right }; 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) { const auto& target = board.boardGrid[r][f]; auto ra = static_cast(r); auto fi = static_cast(f); Square targetSquare = {ra, fi}; if(!target) { moveList.push_back({from, targetSquare}); } else if(target && target->getColour() != this->getColour()) { moveList.push_back({from, targetSquare}); break; } else break; r += dir[0]; f += dir[1]; } } return moveList; } std::vector Queen::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; return moveList; } std::vector Knight::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; return moveList; } std::vector Bishop::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; return moveList; } std::vector Pawn::getLegalMoves(const Square &from, const Board &board) const { std::vector moveList; const int directions[2][4][2] = { { // black {-1, 0}, // Up {-2, 0}, // 2up first move {-1, 1}, // attack to right {-1, -1} // attack to left }, { // white {1, 0}, // down {2, 0}, // 2down first move {1, 1}, // attack to right {1, -1} // attack to left } }; if(this->getColour() == PIECE_BLACK) { // go through black options for(auto &dir : directions[0]) { int r = from.rank + dir[0]; int f = from.file + dir[1]; if(r >= 0 && r < 8 && f >= 0 && f < 8) { // no need for a while loop as we only have finite moves in limited directions const auto& target = board.boardGrid[r][f]; auto ra = static_cast(r); auto fi = static_cast(f); Square targetSquare = {ra, fi}; if(dir[0] == -2 && !this->checkIfMoved()) { // then 2 is potentially legal if(!target && !(board.boardGrid[r + 1][f])) // check both squares for pieces of any colour moveList.push_back({from, targetSquare}); else continue; } else if(abs(dir[1]) == 1) { // attempted capture (diagonal) if(target && target->getColour() != this->getColour()) { // legal capture moveList.push_back({from, targetSquare}); } else continue; } else { // normal one square forward if(!target) moveList.push_back({from, targetSquare}); } // now check if we are on 8th rank, for promotion } } } else if(this->getColour() == PIECE_WHITE) { for(auto &dir : directions[1]) { // go through white options int r = from.rank + dir[0]; int f = from.file + dir[1]; if(r >= 0 && r < 8 && f >= 0 && f < 8) { // no need for a while loop as we only have finite moves in limited directions const auto& target = board.boardGrid[r][f]; auto ra = static_cast(r); auto fi = static_cast(f); Square targetSquare = {ra, fi}; if(dir[0] == 2 && !this->checkIfMoved()) { // then 2 is potentially legal if(!target && !(board.boardGrid[r - 1][f])) moveList.push_back({from, targetSquare}); else continue; } else if(abs(dir[1]) == 1) { // attempted capture (diagonal) if(target && target->getColour() != this->getColour()) { // can only move there if it's a capture // legal capture moveList.push_back({from, targetSquare}); } else continue; } else { // normal one square forward if(!target) moveList.push_back({from, targetSquare}); } // now check if we are on 8th rank, for promotion } } } return moveList; }