| 
 | 1 | +#include "Board.h"  | 
 | 2 | +#include <iostream>  | 
 | 3 | +#include <algorithm>  | 
 | 4 | + | 
 | 5 | +Board::Board() {  | 
 | 6 | +    // Initialize empty board  | 
 | 7 | +    for (int i = 0; i < 8; i++) {  | 
 | 8 | +        for (int j = 0; j < 8; j++) {  | 
 | 9 | +            board[i][j] = nullptr;  | 
 | 10 | +        }  | 
 | 11 | +    }  | 
 | 12 | +}  | 
 | 13 | + | 
 | 14 | +void Board::initialize() {  | 
 | 15 | +    // Clear board  | 
 | 16 | +    for (int i = 0; i < 8; i++) {  | 
 | 17 | +        for (int j = 0; j < 8; j++) {  | 
 | 18 | +            board[i][j] = nullptr;  | 
 | 19 | +        }  | 
 | 20 | +    }  | 
 | 21 | +      | 
 | 22 | +    // Place black pieces (row 0-1)  | 
 | 23 | +    board[0][0] = std::make_unique<Rook>(Color::BLACK, Position(0, 0));  | 
 | 24 | +    board[0][1] = std::make_unique<Knight>(Color::BLACK, Position(0, 1));  | 
 | 25 | +    board[0][2] = std::make_unique<Bishop>(Color::BLACK, Position(0, 2));  | 
 | 26 | +    board[0][3] = std::make_unique<Queen>(Color::BLACK, Position(0, 3));  | 
 | 27 | +    board[0][4] = std::make_unique<King>(Color::BLACK, Position(0, 4));  | 
 | 28 | +    board[0][5] = std::make_unique<Bishop>(Color::BLACK, Position(0, 5));  | 
 | 29 | +    board[0][6] = std::make_unique<Knight>(Color::BLACK, Position(0, 6));  | 
 | 30 | +    board[0][7] = std::make_unique<Rook>(Color::BLACK, Position(0, 7));  | 
 | 31 | +      | 
 | 32 | +    for (int col = 0; col < 8; col++) {  | 
 | 33 | +        board[1][col] = std::make_unique<Pawn>(Color::BLACK, Position(1, col));  | 
 | 34 | +    }  | 
 | 35 | +      | 
 | 36 | +    // Place white pieces (row 6-7)  | 
 | 37 | +    for (int col = 0; col < 8; col++) {  | 
 | 38 | +        board[6][col] = std::make_unique<Pawn>(Color::WHITE, Position(6, col));  | 
 | 39 | +    }  | 
 | 40 | +      | 
 | 41 | +    board[7][0] = std::make_unique<Rook>(Color::WHITE, Position(7, 0));  | 
 | 42 | +    board[7][1] = std::make_unique<Knight>(Color::WHITE, Position(7, 1));  | 
 | 43 | +    board[7][2] = std::make_unique<Bishop>(Color::WHITE, Position(7, 2));  | 
 | 44 | +    board[7][3] = std::make_unique<Queen>(Color::WHITE, Position(7, 3));  | 
 | 45 | +    board[7][4] = std::make_unique<King>(Color::WHITE, Position(7, 4));  | 
 | 46 | +    board[7][5] = std::make_unique<Bishop>(Color::WHITE, Position(7, 5));  | 
 | 47 | +    board[7][6] = std::make_unique<Knight>(Color::WHITE, Position(7, 6));  | 
 | 48 | +    board[7][7] = std::make_unique<Rook>(Color::WHITE, Position(7, 7));  | 
 | 49 | +      | 
 | 50 | +    // Set king positions  | 
 | 51 | +    whiteKingPos = Position(7, 4);  | 
 | 52 | +    blackKingPos = Position(0, 4);  | 
 | 53 | +}  | 
 | 54 | + | 
 | 55 | +Piece* Board::getPiece(const Position& pos) const {  | 
 | 56 | +    if (!pos.isValid()) return nullptr;  | 
 | 57 | +    return board[pos.row][pos.col].get();  | 
 | 58 | +}  | 
 | 59 | + | 
 | 60 | +bool Board::isEmpty(const Position& pos) const {  | 
 | 61 | +    if (!pos.isValid()) return false;  | 
 | 62 | +    return board[pos.row][pos.col] == nullptr;  | 
 | 63 | +}  | 
 | 64 | + | 
 | 65 | +bool Board::hasEnemyPiece(const Position& pos, Color playerColor) const {  | 
 | 66 | +    if (!pos.isValid()) return false;  | 
 | 67 | +    Piece* piece = board[pos.row][pos.col].get();  | 
 | 68 | +    return piece != nullptr && piece->getColor() != playerColor;  | 
 | 69 | +}  | 
 | 70 | + | 
 | 71 | +bool Board::makeMove(const Position& from, const Position& to) {  | 
 | 72 | +    if (!from.isValid() || !to.isValid()) return false;  | 
 | 73 | +      | 
 | 74 | +    Piece* piece = getPiece(from);  | 
 | 75 | +    if (!piece) return false;  | 
 | 76 | +      | 
 | 77 | +    // Check if move is legal  | 
 | 78 | +    if (!isMoveLegal(from, to, piece->getColor())) {  | 
 | 79 | +        return false;  | 
 | 80 | +    }  | 
 | 81 | +      | 
 | 82 | +    // Capture enemy piece if present  | 
 | 83 | +    if (getPiece(to)) {  | 
 | 84 | +        board[to.row][to.col] = nullptr;  | 
 | 85 | +    }  | 
 | 86 | +      | 
 | 87 | +    // Move the piece  | 
 | 88 | +    board[to.row][to.col] = std::move(board[from.row][from.col]);  | 
 | 89 | +    board[to.row][to.col]->setPosition(to);  | 
 | 90 | +    board[to.row][to.col]->setHasMoved(true);  | 
 | 91 | +      | 
 | 92 | +    // Update king position if king moved  | 
 | 93 | +    if (board[to.row][to.col]->getType() == PieceType::KING) {  | 
 | 94 | +        if (board[to.row][to.col]->getColor() == Color::WHITE) {  | 
 | 95 | +            whiteKingPos = to;  | 
 | 96 | +        } else {  | 
 | 97 | +            blackKingPos = to;  | 
 | 98 | +        }  | 
 | 99 | +    }  | 
 | 100 | +      | 
 | 101 | +    return true;  | 
 | 102 | +}  | 
 | 103 | + | 
 | 104 | +bool Board::isKingInCheck(Color kingColor) const {  | 
 | 105 | +    Position kingPos = (kingColor == Color::WHITE) ? whiteKingPos : blackKingPos;  | 
 | 106 | +    Color enemyColor = (kingColor == Color::WHITE) ? Color::BLACK : Color::WHITE;  | 
 | 107 | +      | 
 | 108 | +    return isPositionUnderAttack(kingPos, enemyColor);  | 
 | 109 | +}  | 
 | 110 | + | 
 | 111 | +bool Board::isPositionUnderAttack(const Position& pos, Color attackerColor) const {  | 
 | 112 | +    // Check all pieces of the attacking color  | 
 | 113 | +    for (int row = 0; row < 8; row++) {  | 
 | 114 | +        for (int col = 0; col < 8; col++) {  | 
 | 115 | +            Piece* piece = board[row][col].get();  | 
 | 116 | +            if (piece && piece->getColor() == attackerColor) {  | 
 | 117 | +                std::vector<Position> moves = piece->getValidMoves(*this);  | 
 | 118 | +                for (const Position& move : moves) {  | 
 | 119 | +                    if (move == pos) {  | 
 | 120 | +                        return true;  | 
 | 121 | +                    }  | 
 | 122 | +                }  | 
 | 123 | +            }  | 
 | 124 | +        }  | 
 | 125 | +    }  | 
 | 126 | +    return false;  | 
 | 127 | +}  | 
 | 128 | + | 
 | 129 | +bool Board::wouldKingBeSafe(const Position& from, const Position& to, Color playerColor) const {  | 
 | 130 | +    // Create a temporary board state  | 
 | 131 | +    Board tempBoard;  | 
 | 132 | +      | 
 | 133 | +    // Copy current board state  | 
 | 134 | +    for (int row = 0; row < 8; row++) {  | 
 | 135 | +        for (int col = 0; col < 8; col++) {  | 
 | 136 | +            if (board[row][col]) {  | 
 | 137 | +                tempBoard.board[row][col] = board[row][col]->clone();  | 
 | 138 | +            }  | 
 | 139 | +        }  | 
 | 140 | +    }  | 
 | 141 | +    tempBoard.whiteKingPos = whiteKingPos;  | 
 | 142 | +    tempBoard.blackKingPos = blackKingPos;  | 
 | 143 | +      | 
 | 144 | +    // Make the move on temporary board  | 
 | 145 | +    if (tempBoard.board[to.row][to.col]) {  | 
 | 146 | +        tempBoard.board[to.row][to.col] = nullptr;  | 
 | 147 | +    }  | 
 | 148 | +    tempBoard.board[to.row][to.col] = std::move(tempBoard.board[from.row][from.col]);  | 
 | 149 | +    tempBoard.board[to.row][to.col]->setPosition(to);  | 
 | 150 | +      | 
 | 151 | +    // Update king position if king moved  | 
 | 152 | +    if (tempBoard.board[to.row][to.col]->getType() == PieceType::KING) {  | 
 | 153 | +        if (playerColor == Color::WHITE) {  | 
 | 154 | +            tempBoard.whiteKingPos = to;  | 
 | 155 | +        } else {  | 
 | 156 | +            tempBoard.blackKingPos = to;  | 
 | 157 | +        }  | 
 | 158 | +    }  | 
 | 159 | +      | 
 | 160 | +    // Check if king is in check after the move  | 
 | 161 | +    return !tempBoard.isKingInCheck(playerColor);  | 
 | 162 | +}  | 
 | 163 | + | 
 | 164 | +bool Board::isMoveLegal(const Position& from, const Position& to, Color playerColor) const {  | 
 | 165 | +    Piece* piece = getPiece(from);  | 
 | 166 | +    if (!piece || piece->getColor() != playerColor) return false;  | 
 | 167 | +      | 
 | 168 | +    // Check if the move is in the piece's valid moves  | 
 | 169 | +    std::vector<Position> validMoves = piece->getValidMoves(*this);  | 
 | 170 | +    bool isValidMove = false;  | 
 | 171 | +    for (const Position& move : validMoves) {  | 
 | 172 | +        if (move == to) {  | 
 | 173 | +            isValidMove = true;  | 
 | 174 | +            break;  | 
 | 175 | +        }  | 
 | 176 | +    }  | 
 | 177 | +      | 
 | 178 | +    if (!isValidMove) return false;  | 
 | 179 | +      | 
 | 180 | +    // Check if the move would leave the king in check  | 
 | 181 | +    return wouldKingBeSafe(from, to, playerColor);  | 
 | 182 | +}  | 
 | 183 | + | 
 | 184 | +std::vector<std::pair<Position, Position>> Board::getAllValidMoves(Color playerColor) const {  | 
 | 185 | +    std::vector<std::pair<Position, Position>> allMoves;  | 
 | 186 | +      | 
 | 187 | +    for (int row = 0; row < 8; row++) {  | 
 | 188 | +        for (int col = 0; col < 8; col++) {  | 
 | 189 | +            Piece* piece = board[row][col].get();  | 
 | 190 | +            if (piece && piece->getColor() == playerColor) {  | 
 | 191 | +                Position from(row, col);  | 
 | 192 | +                std::vector<Position> validMoves = piece->getValidMoves(*this);  | 
 | 193 | +                  | 
 | 194 | +                for (const Position& to : validMoves) {  | 
 | 195 | +                    if (isMoveLegal(from, to, playerColor)) {  | 
 | 196 | +                        allMoves.push_back({from, to});  | 
 | 197 | +                    }  | 
 | 198 | +                }  | 
 | 199 | +            }  | 
 | 200 | +        }  | 
 | 201 | +    }  | 
 | 202 | +      | 
 | 203 | +    return allMoves;  | 
 | 204 | +}  | 
 | 205 | + | 
 | 206 | +bool Board::isCheckmate(Color playerColor) const {  | 
 | 207 | +    // If not in check, it's not checkmate  | 
 | 208 | +    if (!isKingInCheck(playerColor)) return false;  | 
 | 209 | +      | 
 | 210 | +    // If there are any valid moves, it's not checkmate  | 
 | 211 | +    return getAllValidMoves(playerColor).empty();  | 
 | 212 | +}  | 
 | 213 | + | 
 | 214 | +bool Board::isStalemate(Color playerColor) const {  | 
 | 215 | +    // If in check, it's not stalemate  | 
 | 216 | +    if (isKingInCheck(playerColor)) return false;  | 
 | 217 | +      | 
 | 218 | +    // If there are no valid moves, it's stalemate  | 
 | 219 | +    return getAllValidMoves(playerColor).empty();  | 
 | 220 | +}  | 
 | 221 | + | 
 | 222 | +Position Board::getKingPosition(Color kingColor) const {  | 
 | 223 | +    return (kingColor == Color::WHITE) ? whiteKingPos : blackKingPos;  | 
 | 224 | +}  | 
 | 225 | + | 
 | 226 | +int Board::evaluatePosition() const {  | 
 | 227 | +    int score = 0;  | 
 | 228 | +      | 
 | 229 | +    for (int row = 0; row < 8; row++) {  | 
 | 230 | +        for (int col = 0; col < 8; col++) {  | 
 | 231 | +            Piece* piece = board[row][col].get();  | 
 | 232 | +            if (piece) {  | 
 | 233 | +                int pieceValue = piece->getValue();  | 
 | 234 | +                if (piece->getColor() == Color::WHITE) {  | 
 | 235 | +                    score += pieceValue;  | 
 | 236 | +                } else {  | 
 | 237 | +                    score -= pieceValue;  | 
 | 238 | +                }  | 
 | 239 | +            }  | 
 | 240 | +        }  | 
 | 241 | +    }  | 
 | 242 | +      | 
 | 243 | +    return score;  | 
 | 244 | +}  | 
 | 245 | + | 
 | 246 | +void Board::display() const {  | 
 | 247 | +    std::cout << "\n    a   b   c   d   e   f   g   h\n";  | 
 | 248 | +    std::cout << "  +---+---+---+---+---+---+---+---+\n";  | 
 | 249 | +      | 
 | 250 | +    for (int row = 0; row < 8; row++) {  | 
 | 251 | +        std::cout << 8 - row << " |";  | 
 | 252 | +        for (int col = 0; col < 8; col++) {  | 
 | 253 | +            Piece* piece = board[row][col].get();  | 
 | 254 | +            if (piece) {  | 
 | 255 | +                std::cout << " " << piece->getSymbol() << " |";  | 
 | 256 | +            } else {  | 
 | 257 | +                std::cout << "   |";  | 
 | 258 | +            }  | 
 | 259 | +        }  | 
 | 260 | +        std::cout << " " << 8 - row << "\n";  | 
 | 261 | +        std::cout << "  +---+---+---+---+---+---+---+---+\n";  | 
 | 262 | +    }  | 
 | 263 | +      | 
 | 264 | +    std::cout << "    a   b   c   d   e   f   g   h\n\n";  | 
 | 265 | +}  | 
 | 266 | + | 
 | 267 | +void Board::placePiece(std::unique_ptr<Piece> piece, const Position& pos) {  | 
 | 268 | +    if (pos.isValid()) {  | 
 | 269 | +        board[pos.row][pos.col] = std::move(piece);  | 
 | 270 | +    }  | 
 | 271 | +}  | 
 | 272 | + | 
 | 273 | +std::unique_ptr<Board> Board::clone() const {  | 
 | 274 | +    auto clonedBoard = std::make_unique<Board>();  | 
 | 275 | +      | 
 | 276 | +    for (int row = 0; row < 8; row++) {  | 
 | 277 | +        for (int col = 0; col < 8; col++) {  | 
 | 278 | +            if (board[row][col]) {  | 
 | 279 | +                clonedBoard->board[row][col] = board[row][col]->clone();  | 
 | 280 | +            }  | 
 | 281 | +        }  | 
 | 282 | +    }  | 
 | 283 | +      | 
 | 284 | +    clonedBoard->whiteKingPos = whiteKingPos;  | 
 | 285 | +    clonedBoard->blackKingPos = blackKingPos;  | 
 | 286 | +      | 
 | 287 | +    return clonedBoard;  | 
 | 288 | +}  | 
0 commit comments