From 8e909214fd424c2b236fe8da13f188cfe58d5503 Mon Sep 17 00:00:00 2001 From: Cong <work.congpham.com> Date: Mon, 18 Mar 2024 12:58:00 +0100 Subject: [PATCH] Initial Commits --- .DS_Store | Bin 0 -> 6148 bytes .vscode/settings.json | 64 +-- src/Bishop.cpp | 31 -- src/Bishop.h | 20 - src/Board.cpp | 47 -- src/Board.h | 83 --- src/Chess.cpp | 65 +++ src/Chess.h | 134 +++++ src/Game.cpp | 1183 ++++++++++++++++++++++++++++++++++++++++ src/Game.h | 65 +++ src/Knight.cpp | 35 -- src/Knight.h | 20 - src/Piece.cpp | 38 -- src/Piece.h | 75 --- src/Rook.cpp | 15 - src/Rook.h | 20 - src/Square.cpp | 38 -- src/Square.h | 66 --- src/includes.h | 14 + src/user_interface.cpp | 50 ++ src/user_interface.h | 18 + 21 files changed, 1531 insertions(+), 550 deletions(-) create mode 100644 .DS_Store delete mode 100644 src/Bishop.cpp delete mode 100644 src/Bishop.h delete mode 100644 src/Board.cpp delete mode 100644 src/Board.h create mode 100644 src/Chess.cpp create mode 100644 src/Chess.h create mode 100644 src/Game.cpp create mode 100644 src/Game.h delete mode 100644 src/Knight.cpp delete mode 100644 src/Knight.h delete mode 100644 src/Piece.cpp delete mode 100644 src/Piece.h delete mode 100644 src/Rook.cpp delete mode 100644 src/Rook.h delete mode 100644 src/Square.cpp delete mode 100644 src/Square.h create mode 100644 src/includes.h create mode 100644 src/user_interface.cpp create mode 100644 src/user_interface.h diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4bb39329d0fbb8a0696f1c42de3a39821ebe65d3 GIT binary patch literal 6148 zcmeHK%WA_w3>?)i1bWG_$Nh!=!4lFh=npiGF9lOW)7*W_Z+G-au`z|5dI%Covpbf& z_8cq=fb7ow3$O*Sp)2B|VQqR{ePs{9JQ79kaU8mF9Jqv1H<>0j=<tEh{xq-ea3(pR zpVKXR9Po|9oNP#rI9@3|w!sNsOX{Yl$)r>u6-WhAfmGoB70^aa+dMgDOa)SbRNz+u z{XP`BVhx-e?bE?vBLJ}_ZN|0D62zheu?9|#WN6~0L@$*XF~rNsm&mJulcSeIV)&3a zSz<yFJDvA0mJX?o8B>8&V5vak+pYHhSNb3G|FS4|sX!`lR|-hGf7|c)O3_<aFQ>h> u(BJ7-W3Ht$SSu!4E9OR9@$)RN=$hAS;N)oK<gJ{TKLV;tS}O1#3j6>X`6Xxo literal 0 HcmV?d00001 diff --git a/.vscode/settings.json b/.vscode/settings.json index a57998e..0cba2e6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,65 +1,5 @@ { "files.associations": { - "__bit_reference": "cpp", - "__config": "cpp", - "__debug": "cpp", - "__errc": "cpp", - "__functional_base": "cpp", - "__hash_table": "cpp", - "__locale": "cpp", - "__mutex_base": "cpp", - "__node_handle": "cpp", - "__nullptr": "cpp", - "__split_buffer": "cpp", - "__string": "cpp", - "__threading_support": "cpp", - "__tuple": "cpp", - "algorithm": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "complex": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "exception": "cpp", - "functional": "cpp", - "initializer_list": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "istream": "cpp", - "iterator": "cpp", - "limits": "cpp", - "locale": "cpp", - "memory": "cpp", - "mutex": "cpp", - "new": "cpp", - "optional": "cpp", - "ostream": "cpp", - "ratio": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "unordered_map": "cpp", - "utility": "cpp", - "vector": "cpp" - }, - "C_Cpp.dimInactiveRegions": false + "iostream": "cpp" + } } \ No newline at end of file diff --git a/src/Bishop.cpp b/src/Bishop.cpp deleted file mode 100644 index c7eeabb..0000000 --- a/src/Bishop.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "Bishop.h" -#include <iostream> -using namespace std; - -Bishop:: Bishop(PieceColor color, Position pos) -{ - this->color = color; - this->pos = pos; - this->type = "B"; -} - -Bishop::~Bishop() -{ -} - -bool Bishop::isValidMove(Position newPos) -{ - if (newPos.x < 0 || newPos.x > 7 || newPos.y < 0 || newPos.y > 7) - { - return false; - } - if (newPos.x == pos.x || newPos.y == pos.y) - { - return false; - } - if (abs(newPos.x - pos.x) == abs(newPos.y - pos.y)) - { - return true; - } - return false; -} diff --git a/src/Bishop.h b/src/Bishop.h deleted file mode 100644 index 5af7345..0000000 --- a/src/Bishop.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _BISHOP_H_ -#define _BISHOP_H_ -#include "Piece.h" - -class Bishop : public Piece -{ - public: - /** - * @brief Default constructor for Bishop class. - */ - Bishop(PieceColor color, Position pos); - - /** - * @brief Destructor for Bishop class. - */ - ~Bishop(); - bool isValidMove(Position newPos); -}; - -#endif \ No newline at end of file diff --git a/src/Board.cpp b/src/Board.cpp deleted file mode 100644 index 9af8245..0000000 --- a/src/Board.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "Board.h" -#include "Square.h" -#include <iostream> -using namespace std; - -Board::Board() -{ - for (int i = 0; i < 8; i++) - { - for (int j = 0; j < 8; j++) - { - squares[i][j] = new Square(i, j); - } - } -} - -Board::~Board() -{ - for (int i = 0; i < 8; i++) - { - for (int j = 0; j < 8; j++) - { - delete squares[i][j]; - } - delete squares[i]; - } - delete squares; -} - -Board* Board::getBoard() -{ - if (board == nullptr) - { - board = new Board(); - } - return board; -} - -Square* Board::getSquare(int x, int y) const -{ - return squares[x][y]; -} - -bool Board::isClearVertical(Square& start, Square& end) const -{ - Square* -} \ No newline at end of file diff --git a/src/Board.h b/src/Board.h deleted file mode 100644 index 3831561..0000000 --- a/src/Board.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _BOARD_H -#define _BOARD_H - -#include <ostream> -#include "Square.h" - -/** - * @class Board - * @brief Represents a chess board. - * - * The Board class represents a chess board consisting of 64 squares. - * It provides methods to access and manipulate the squares on the board. - */ -class Board -{ - private: - Square* squares[8][8]; /**< 2D array of Square pointers representing the squares on the board. */ - static Board* board; /**< Pointer to the singleton instance of the Board class. */ - - public: - /** - * @brief Default constructor. - */ - Board(); - - /** - * @brief Destructor. - */ - ~Board(); - - /** - * @brief Get the singleton instance of the Board class. - * @return Pointer to the Board instance. - */ - static Board* getBoard(); - - /** - * @brief Get the square at the specified position on the board. - * @param x The x-coordinate of the square. - * @param y The y-coordinate of the square. - * @return Pointer to the Square object at the specified position. - */ - Square* getSquare(int x, int y) const; - - /** - * @brief Check if the vertical path between two squares is clear. - * @param start Pointer to the starting square. - * @param end Pointer to the ending square. - * @return True if the vertical path is clear, false otherwise. - */ - bool isClearVertical(Square& start, Square& end) const; - - /** - * @brief Check if the horizontal path between two squares is clear. - * @param start Pointer to the starting square. - * @param end Pointer to the ending square. - * @return True if the horizontal path is clear, false otherwise. - */ - bool isClearHorizontal(Square& start, Square& end) const; - - /** - * @brief Check if the diagonal path between two squares is clear. - * @param start Pointer to the starting square. - * @param end Pointer to the ending square. - * @return True if the diagonal path is clear, false otherwise. - */ - bool isClearDiagonal(Square& start, Square& end) const; - - /** - * @brief Check if the given square is in the end row of the board. - * @param s Pointer to the square to check. - * @return True if the square is in the end row, false otherwise. - */ - bool isEndRow(Square& s) const; - - /** - * @brief Print the board to the specified output stream. - * @param outStream The output stream to print the board to. - */ - void afficher(std::ostream& outStream) const; -}; - -#endif \ No newline at end of file diff --git a/src/Chess.cpp b/src/Chess.cpp new file mode 100644 index 0000000..205e136 --- /dev/null +++ b/src/Chess.cpp @@ -0,0 +1,65 @@ +#include "includes.h" +#include "Chess.h" + +int Chess::getPieceColor( char chPiece ) +{ + return ( isupper( chPiece ) ? WHITE_PIECE : BLACK_PIECE ); +} + +bool Chess::isWhitePiece( char chPiece ) +{ + return ( getPieceColor( chPiece ) == WHITE_PIECE ? true : false); +} + +bool Chess::isBlackPiece( char chPiece ) +{ + return ( getPieceColor( chPiece ) == BLACK_PIECE ? true : false); +} + +string Chess::describePiece( char chPiece ) +{ + string strPiece; + switch( chPiece ) + { + case 'P': + strPiece = "White Pawn"; + break; + case 'p': + strPiece = "Black Pawn"; + break; + case 'N': + strPiece = "White Knight"; + break; + case 'n': + strPiece = "Black Knight"; + break; + case 'B': + strPiece = "White Bishop"; + break; + case 'b': + strPiece = "Black Bishop"; + break; + case 'R': + strPiece = "White Rook"; + break; + case 'r': + strPiece = "Black Rook"; + break; + case 'Q': + strPiece = "White Queen"; + break; + case 'q': + strPiece = "Black Queen"; + break; + case 'K': + strPiece = "White King"; + break; + case 'k': + strPiece = "Black King"; + break; + default: + strPiece = "Empty"; + break; + } + return strPiece; +} \ No newline at end of file diff --git a/src/Chess.h b/src/Chess.h new file mode 100644 index 0000000..b7d5556 --- /dev/null +++ b/src/Chess.h @@ -0,0 +1,134 @@ +#ifndef _CHESS_H_ +#define _CHESS_H_ + +#include "includes.h" + +/** + * @brief The Chess class represents a chess game. + */ +class Chess +{ + public: + /** + * @brief Get the color of a chess piece. + * + * @param chPiece The character representation of the chess piece. + * @return int The color of the chess piece (0 for white, 1 for black). + */ + static int getPieceColor( char chPiece ); + + /** + * @brief Check if a chess piece is white. + * + * @param chPiece The character representation of the chess piece. + * @return bool True if the chess piece is white, false otherwise. + */ + static bool isWhitePiece( char chPiece ); + + /** + * @brief Check if a chess piece is black. + * + * @param chPiece The character representation of the chess piece. + * @return bool True if the chess piece is black, false otherwise. + */ + static bool isBlackPiece( char chPiece ); + + /** + * @brief Describe a chess piece. + * + * @param chPiece The character representation of the chess piece. + * @return std::string The description of the chess piece. + */ + static string describePiece( char chPiece ); + + + enum PieceColor + { + WHITE_PIECE = 0, + BLACK_PIECE = 1 + }; + + enum Player + { + WHITE_PLAYER = 0, + BLACK_PLAYER = 1 + }; + + enum Side + { + QUEEN_SIDE = 2, + KING_SIDE = 3 + }; + + enum Direction + { + HORIZONTAL = 0, + VERTICAL, + DIAGONAL, + L_SHAPE + }; + + struct Position + { + int iRow; + int iColumn; + }; + + struct EnPassant + { + bool bApplied; + Position PawnCaptured; + }; + + struct Castling + { + bool bApplied; + Position rook_before; + Position rook_after; + }; + + struct Promotion + { + bool bApplied; + char chBefore; + char chAfter; + }; + + struct IntendedMove + { + char chPiece; + Position from; + Position to; + }; + + struct Attacker + { + Position pos; + Direction dir; + }; + + struct UnderAttack + { + bool bUnderAttack; + int iNumAttackers; + Attacker attacker[9]; //maximum theoretical number of attackers + }; + + const char initial_board[8][8] = + { + // This represents the pieces on the board. + // Keep in mind that pieces[0][0] represents A1 + // pieces[1][1] represents B2 and so on. + // Letters in CAPITAL are white + { 'R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R' }, + { 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P' }, + { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, + { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, + { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, + { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, + { 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' }, + { 'r', 'n', 'b', 'q', 'k', 'b', 'n', 'r' }, + }; +}; + +#endif diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 0000000..1da5328 --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,1183 @@ +#include "Game.h" +#include "user_interface.h" + +Game::Game() +{ + m_CurrentTurn = WHITE_PLAYER; + m_bGameFinished = false; + memcpy( board, initial_board, sizeof(char) * 8 * 8); + + m_bCastlingKingSideAllowed[WHITE_PLAYER] = true; + m_bCastlingQueenSideAllowed[WHITE_PLAYER] = true; + m_bCastlingKingSideAllowed[BLACK_PLAYER] = true; + m_bCastlingQueenSideAllowed[BLACK_PLAYER] = true; +} + +Game::~Game() +{ + +} + +void Game::movePiece( Position present, Position future, EnPassant* S_enPassant, Castling* S_castling, Promotion* S_promotion ) +{ + char chPiece = getPieceAtPosition( present); + char chCapturedPiece = getPieceAtPosition( future ); + + if (0x20 != chCapturedPiece) + { + if (getPieceColor(chCapturedPiece) == WHITE_PIECE ) + { + white_captured.push_back(chCapturedPiece); + } + else + { + black_captured.push_back(chCapturedPiece); + } + } + else if (S_enPassant -> bApplied) + { + char chCapturedEP = getPieceAtPosition( S_enPassant -> PawnCaptured ); + if (getPieceColor(chCapturedEP) == WHITE_PIECE ) + { + white_captured.push_back(chCapturedEP); + } + else + { + black_captured.push_back(chCapturedEP); + } + + board[S_enPassant -> PawnCaptured.iRow][S_enPassant -> PawnCaptured.iColumn] = 0x20; + } + board[present.iRow][present.iColumn] = 0x20; + + if(S_promotion -> bApplied == true) + { + board[future.iRow][future.iColumn] = S_promotion -> chAfter; + } + else + { + board[future.iRow][future.iColumn] = chPiece; + } + if (S_castling -> bApplied == true) + { + char chPiece = getPieceAtPosition( S_castling -> rook_before ); + board[S_castling -> rook_before.iRow][S_castling -> rook_before.iColumn] = 0x20; + board[S_castling -> rook_after.iRow][S_castling -> rook_after.iColumn] = chPiece; + } + + if(toupper(chPiece) == 'K') + { + m_bCastlingKingSideAllowed[getCurrentTurn()] = false; + m_bCastlingQueenSideAllowed[getCurrentTurn()] = false; + } + else if (toupper(chPiece) == 'R') + { + if (present.iColumn == 0) + { + m_bCastlingQueenSideAllowed[getCurrentTurn()] = false; + } + else if (present.iColumn == 7) + { + m_bCastlingKingSideAllowed[getCurrentTurn()] = false; + } + } + changeTurns(); +} + +bool Game::castlingAllowed( Side iSide, int iColor ) +{ + if (iSide == KING_SIDE) + { + return m_bCastlingKingSideAllowed[iColor]; + } + else + { + return m_bCastlingQueenSideAllowed[iColor]; + } +} + +char Game::getPieceAtPosition(Position pos) +{ + return board[pos.iRow][pos.iColumn]; +} + +char Game::getPieceAtPosition(int iRow, int iColumn) +{ + return board[iRow][iColumn]; +} + +char Game::getPiece_considerMove(int iRow, int iColumn, IntendedMove* intended_move) +{ + char chPiece; + if (intended_move == nullptr) + { + chPiece = getPieceAtPosition(iRow, iColumn); + } + else + { + if(intended_move -> from.iRow == iRow && intended_move -> from.iColumn == iColumn) + { + chPiece = EMPTY_SQUARE; + } + else if (intended_move->to.iRow == iRow && intended_move->to.iColumn == iColumn) + { + chPiece = intended_move->chPiece; + } + else + { + chPiece = getPieceAtPosition(iRow, iColumn); + } + } + return chPiece; +} + +Chess::UnderAttack Game::isUnderAttack(int iRow, int iColumn, int iColor, IntendedMove* pintended_move) +{ + UnderAttack attack = {0}; + // Direction: Horizontal + { + //Right way + for (int i = iColumn + 1;i<8;i++) + { + char chPieceFound = getPiece_considerMove(iRow, i, pintended_move); + if (EMPTY_SQUARE == chPieceFound) + { + continue; + } + + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = iRow; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = i; + attack.attacker[attack.iNumAttackers-1].dir = HORIZONTAL; + break; + } + else + { + break; + } + } + //Left way + for (int i = iColumn - 1;i>=0;i--) + { + char chPieceFound = getPiece_considerMove(iRow, i, pintended_move); + if (EMPTY_SQUARE == chPieceFound) + { + continue; + } + + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = iRow; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = i; + attack.attacker[attack.iNumAttackers-1].dir = HORIZONTAL; + break; + } + else + { + break; + } + } + } + // Vertical + { + //Way up + for (int i= iRow +1; i<8; i++) + { + char chPieceFound = getPiece_considerMove(i, iColumn, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = iColumn; + attack.attacker[attack.iNumAttackers-1].dir = VERTICAL; + break; + } + else + { + break; + } + } + //Way down + for (int i=iRow - 1;i>=0;i--) + { + char chPieceFound = getPiece_considerMove(i, iColumn, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = iColumn; + attack.attacker[attack.iNumAttackers-1].dir = VERTICAL; + break; + } + else + { + break; + } + } + } + // Diagonal + { + // up-right + for (int i = iRow + 1, j = iColumn + 1 ; i<8 && j<8; i++, j++) + { + char chPieceFound = getPiece_considerMove(i, j, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if ((toupper(chPieceFound) == 'P') && (i == iRow + 1) && (j == iColumn + 1) && (iColor == WHITE_PIECE)) + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else + { + break; + } + } + // up-left + { + for (int i = iRow + 1, j = iColumn -1 ; i<8 && j>0; i++, j--) + { + char chPieceFound = getPiece_considerMove(i, j, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if ((toupper(chPieceFound) == 'P') && (i == iRow + 1) && (j == iColumn - 1) && (iColor == WHITE_PIECE)) + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else + { + break; + } + } + } + // down-right + { + for (int i = iRow - 1, j = iColumn + 1; i > 0 && j < 8; i--, j++) + { + char chPieceFound = getPiece_considerMove(i, j, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if(getPieceColor(chPieceFound) == iColor) + { + break; + } + else if ((toupper(chPieceFound) == 'P') && (i == iRow - 1) && (j == iColumn + 1) && (iColor == BLACK_PIECE)) + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else + { + break; + } + } + } + // down-left + { + for (int i = iRow - 1, j = iColumn - 1; i > 0 && j > 0; i--, j--) + { + char chPieceFound = getPiece_considerMove(i, j, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if(getPieceColor(chPieceFound) == iColor) + { + break; + } + else if ((toupper(chPieceFound) == 'P') && (i == iRow - 1) && (j == iColumn - 1) && (iColor == BLACK_PIECE)) + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = i; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = j; + attack.attacker[attack.iNumAttackers-1].dir = DIAGONAL; + break; + } + else + { + break; + } + } + } + } + // L_Shaped + { + Position knight_moves[8] = { {1,-2}, {2, -1}, {2, 1}, {1, 2}, + {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2} }; + for (int i=0;i<8;i++) + { + int iRowToTest = iRow + knight_moves[i].iRow; + int iColumnToTest = iColumn + knight_moves[i].iColumn; + + if (iRowToTest < 0 || iRowToTest > 7 || iColumnToTest < 0 || iColumnToTest > 7) + { + // not exists + continue; + } + + char chPieceFound = getPiece_considerMove(iRowToTest, iColumnToTest, pintended_move); + if (chPieceFound == EMPTY_SQUARE) + { + // empty + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + // same color + continue; + } + else if ((toupper(chPieceFound) == 'N')) + { + attack.bUnderAttack = true; + attack.iNumAttackers++; + + attack.attacker[attack.iNumAttackers-1].pos.iRow = iRowToTest; + attack.attacker[attack.iNumAttackers-1].pos.iColumn = iColumnToTest; + attack.attacker[attack.iNumAttackers-1].dir = L_SHAPE; + } + } + } + return attack; +} +bool Game::isReachable(int iRow, int iColumn, int iColor) +{ + bool bReachable = false; + // Horizontal + { + // Right way + for (int i = iColumn + 1; i<8; i++) + { + char chPieceFound = getPieceAtPosition(iRow, i); + if (EMPTY_SQUARE == chPieceFound) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + bReachable = true; + break; + } + else + { + break; + } + } + // Left way + for (int i= iColumn - 1 ; i>=0;i--) + { + char chPieceFound = getPieceAtPosition(iRow, i); + if (EMPTY_SQUARE == chPieceFound) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + bReachable = true; + break; + } + else + { + break; + } + } + } + // Vertical + { + //Way up + for (int i= iRow+1; i<8; i++) + { + char chPieceFound = getPieceAtPosition(i, iColumn); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if(getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'P' && getPieceColor(chPieceFound) == BLACK_PIECE && (i == iRow +1)) + { + bReachable = true; + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + bReachable = true; + break; + } + else + { + break; + } + } + // Way down + for (int i= iRow - 1 ; i>= 0; i--) + { + char chPieceFound = getPieceAtPosition(i, iColumn); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'P' && getPieceColor(chPieceFound) == WHITE_PIECE && (i == iRow - 1)) + { + bReachable = true; + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'R') + { + bReachable = true; + break; + } + else + { + break; + } + } + } + // Diagonal + { + // up-right + for (int i = iRow+1, j = iColumn + 1; i < 8 && j < 8;i++, j++) + { + char chPieceFound = getPieceAtPosition(i, j); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + bReachable = true; + break; + } + else + { + break; + } + } + // up-left + for (int i = iRow + 1, j = iColumn - 1; i < 8 && j > 0; i++, j--) + { + char chPieceFound = getPieceAtPosition(i, j); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + bReachable = true; + break; + } + else + { + break; + } + } + // down-right + for(int i = iRow - 1, j = iColumn + 1; i > 0 && j < 8; i--, j++) + { + char chPieceFound = getPieceAtPosition(i, j); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + bReachable = true; + break; + } + else + { + break; + } + } + // down-left + for (int i = iRow - 1, j = iColumn - 1; i > 0 && j > 0; i--, j--) + { + char chPieceFound = getPieceAtPosition(i, j); + if (chPieceFound == EMPTY_SQUARE) + { + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + break; + } + else if (toupper(chPieceFound) == 'Q' || toupper(chPieceFound) == 'B') + { + bReachable = true; + break; + } + else + { + break; + } + } + } + // L_SHAPED + { + Position knight_moves[8] = { {1,-2}, {2, -1}, {2, 1}, {1, 2}, + {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2} }; + for (int i=0;i<8;i++) + { + int iRowToTest = iRow + knight_moves[i].iRow; + int iColumnToTest = iColumn + knight_moves[i].iColumn; + + if (iRowToTest < 0 || iRowToTest > 7 || iColumnToTest < 0 || iColumnToTest > 7) + { + // not exists + continue; + } + + char chPieceFound = getPieceAtPosition(iRowToTest, iColumnToTest); + if (chPieceFound == EMPTY_SQUARE) + { + // empty + continue; + } + if (getPieceColor(chPieceFound) == iColor) + { + // same color + continue; + } + else if ((toupper(chPieceFound) == 'N')) + { + bReachable = true; + break; + } + } + } + return bReachable; +} + +bool Game::isSquareOccupied(int iRow, int iColumn) +{ + bool bOccupied = false; + if (0x20 != getPieceAtPosition(iRow, iColumn)) + { + bOccupied = true; + } + return bOccupied; +} + +bool Game::isPathFree(Position startingPos, Position finishingPos, int iDirection) +{ + bool bFree = false; + + switch(iDirection) + { + case Chess::HORIZONTAL: + { + // If it's a horizontal move, we assume that the startingPos.iRow == finishingPos.iRow + // If the piece wants to mive from column 0 to column 7, we must check if columns 1-6 are free + if (startingPos.iColumn == finishingPos.iColumn) + { + cout << "Error: Movement is horizontal but column is the same " << endl; + } + + // moving to the right + else if (startingPos.iColumn < finishingPos.iColumn) + { + // setting bFree as initially true, only inside the cases, gurantees that the path is checked + bFree = true; + + for (int i = startingPos.iColumn + 1; i < finishingPos.iColumn; i++) + { + if (isSquareOccupied( startingPos.iRow, i)) + { + bFree = false; + cout << "Horizontal path to the right is not clear" << endl; + } + } + } + // moving to the left + else // if (startingPos.iColumn > finishingPos.iColumn) + { + bFree = true; + for (int i = startingPos.iColumn - 1; i > finishingPos.iColumn; i--) + { + if (isSquareOccupied( startingPos.iRow, i)) + { + bFree = false; + cout << "Horizontal path to the left is not clear" << endl; + } + } + } + } + break; + + case Chess::VERTICAL: + { + // If it's a vertical move, we assume that the startingPos.iColumn == finishingPos.iColumn + // If the piece wants to move from row 0 to row 7, we must check if rows 1-6 are free + if (startingPos.iRow == finishingPos.iRow) + { + cout << "Error: Movement is vertical but row is the same " << endl; + } + + // moving up + else if (startingPos.iRow < finishingPos.iRow) + { + bFree = true; + for (int i = startingPos.iRow + 1; i < finishingPos.iRow; i++) + { + if (isSquareOccupied( i, startingPos.iColumn)) + { + bFree = false; + cout << "Vertical path up is not clear" << endl; + } + } + } + // moving down + else // if (startingPos.iRow > finishingPos.iRow) + { + bFree = true; + for (int i = startingPos.iRow - 1; i > finishingPos.iRow; i--) + { + if (isSquareOccupied( i, startingPos.iColumn)) + { + bFree = false; + cout << "Vertical path down is not clear" << endl; + } + } + } + } + break; + + case Chess::DIAGONAL: + { + //Moving up and right + if ((finishingPos.iRow > startingPos.iRow) && (finishingPos.iColumn > startingPos.iColumn)) + { + bFree = true; + for (int i = 1;i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isSquareOccupied( startingPos.iRow + i, startingPos.iColumn + i)) + { + bFree = false; + cout << "Diagonal path up and right is not clear" << endl; + } + } + } + // moving up and left + else if ((finishingPos.iRow > startingPos.iRow) && (finishingPos.iColumn < startingPos.iColumn)) + { + bFree = true; + for (int i = 1;i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isSquareOccupied( startingPos.iRow + i, startingPos.iColumn - i)) + { + bFree = false; + cout << "Diagonal path up and left is not clear" << endl; + } + } + } + // moving down and right + else if ((finishingPos.iRow < startingPos.iRow) && (finishingPos.iColumn > startingPos.iColumn)) + { + bFree = true; + for (int i = 1;i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isSquareOccupied( startingPos.iRow - i, startingPos.iColumn + i)) + { + bFree = false; + cout << "Diagonal path down and right is not clear" << endl; + } + } + } + // moving down and left + else if ((finishingPos.iRow < startingPos.iRow) && (finishingPos.iColumn < startingPos.iColumn)) + { + bFree = true; + for (int i = 1;i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isSquareOccupied( startingPos.iRow - i, startingPos.iColumn - i)) + { + bFree = false; + cout << "Diagonal path down and left is not clear" << endl; + } + } + } + else + { + cout << "Error: Invalid diagonal movement" << endl; + } + } + break; + } + return bFree; +} + +bool Game::canBeBlocked(Position startingPos, Position finishingPos, int iDirection) +{ + bool bBlocked = false; + Chess::UnderAttack blocker = {0}; + switch(iDirection) + { + case Chess::HORIZONTAL: + { + if(startingPos.iColumn == finishingPos.iColumn) + { + cout << "Error: Movement is horizontal but column is the same" << endl; + } + // moving to the right + else if (startingPos.iColumn < finishingPos.iColumn) + { + for (int i = startingPos.iColumn + 1; i < finishingPos.iColumn; i++) + { + if (isReachable(startingPos.iRow, i, getOpponentColor())) + { + bBlocked = true; + } + } + } + // moving to the left + else // if (startingPos.iColumn > finishingPos.iColumn) + { + for (int i = startingPos.iColumn - 1; i > finishingPos.iColumn; i--) + { + if (isReachable(startingPos.iRow, i, getOpponentColor())) + { + bBlocked = true; + } + } + } + } + break; + + case Chess::VERTICAL: + { + if (startingPos.iRow == finishingPos.iRow) + { + cout << "Error: Movement is vertical but row is the same" << endl; + } + // moving up + else if (startingPos.iRow < finishingPos.iRow) + { + for (int i = startingPos.iRow + 1 ; i<finishingPos.iRow; i++) + { + if (isReachable(i, startingPos.iColumn, getOpponentColor())) + { + bBlocked = true; + } + } + } + // moving down + else // if (startingPos.iRow > finishingPos.iRow) + { + for (int i = startingPos.iRow - 1; i > finishingPos.iRow; i--) + { + if (isReachable(i, startingPos.iColumn, getOpponentColor())) + { + bBlocked = true; + } + } + } + } + break; + + case Chess::DIAGONAL: + { + // up and right + if ((finishingPos.iRow > startingPos.iRow) && (finishingPos.iColumn > startingPos.iColumn)) + { + for (int i = 1; i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isReachable(startingPos.iRow + i, startingPos.iColumn + i, getOpponentColor())) + { + bBlocked = true; + } + } + } + // up and left + else if ((finishingPos.iRow > startingPos.iRow) && (finishingPos.iColumn < startingPos.iColumn)) + { + for (int i = 1; i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isReachable(startingPos.iRow + i, startingPos.iColumn - i, getOpponentColor())) + { + bBlocked = true; + } + } + } + // down and right + else if ((finishingPos.iRow < startingPos.iRow) && (finishingPos.iColumn > startingPos.iColumn)) + { + for (int i = 1; i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isReachable(startingPos.iRow - i, startingPos.iColumn + i, getOpponentColor())) + { + bBlocked = true; + } + } + } + // down and left + else if ((finishingPos.iRow < startingPos.iRow) && (finishingPos.iColumn < startingPos.iColumn)) + { + for (int i = 1; i < abs(finishingPos.iRow - startingPos.iRow); i++) + { + if (isReachable(startingPos.iRow - i, startingPos.iColumn - i, getOpponentColor())) + { + bBlocked = true; + } + } + } + else + { + cout << "Error: Invalid diagonal movement" << endl; + } + } + } + return bBlocked; +} + +bool Game::isCheckMate() +{ + bool bCheckMate = false; + // 1, is the king in check? + if (playerKingInCheck() == false) + { + bCheckMate = false; + } + // 2, Can the king move to another square? + Chess::Position king_moves[8] = { {1,-1}, {1,0}, {1,1}, {0,1}, + {-1,1}, {-1,0}, {-1,-1}, {0,-1} }; + + Chess::Position king = findKing(getCurrentTurn()); + for (int i=0;i<8;i++) + { + int iRowToTest = king.iRow + king_moves[i].iRow; + int iColumnToTest = king.iColumn + king_moves[i].iColumn; + + if (iRowToTest < 0 || iRowToTest > 7 || iColumnToTest < 0 || iColumnToTest > 7) + { + continue; + } + + if (getPieceAtPosition(iRowToTest, iColumnToTest) != EMPTY_SQUARE) + { + continue; + } + + Chess::IntendedMove intended_move; + intended_move.chPiece = getPieceAtPosition(king.iRow, king.iColumn); + intended_move.from.iRow = king.iRow; + intended_move.from.iColumn = king.iColumn; + intended_move.to.iRow = iRowToTest; + intended_move.to.iColumn = iColumnToTest; + + Chess::UnderAttack king_moved = isUnderAttack(iRowToTest, iColumnToTest, getCurrentTurn(), &intended_move); + if (king_moved.bUnderAttack == false) + { + // this means there's at least one pos when the king move would not be under attack + return false; + } + } + // 3, Can the attacking piece be captured? Or be blocked? + Chess::UnderAttack king_attacked = isUnderAttack(king.iRow, king.iColumn, getCurrentTurn()); + if (king_attacked.iNumAttackers == 1) + { + // Can the attacking piece be captured? + Chess::UnderAttack king_attacker = {0}; + king_attacker = isUnderAttack(king_attacked.attacker[0].pos.iRow, king_attacked.attacker[0].pos.iColumn, getOpponentColor()); + if (king_attacker.bUnderAttack == true) + { + // this means the attacking piece can be captured, so it's not a checkmate + return false; + } + else + { + // Can the attacking piece be blocked? + char chAttacker = getPieceAtPosition(king_attacked.attacker[0].pos); + switch(toupper(chAttacker)) + { + // if it's a pawn, there's no space in between the king and the pawn + case 'P': + // if it's a knight, it can't be blocked, this is checkmate + case 'N': + { + bCheckMate = true; + } + break; + + case 'B': + { + if (canBeBlocked(king_attacked.attacker[0].pos, king, Chess::DIAGONAL) == false) + { + bCheckMate = true; + } + } + break; + + case 'R': + { + if (canBeBlocked(king_attacked.attacker[0].pos, king, king_attacked.attacker[0].dir) == false) + { + bCheckMate = true; + } + } + break; + + case 'Q': + { + if (canBeBlocked(king_attacked.attacker[0].pos, king, king_attacked.attacker[0].dir) == false) + { + bCheckMate = true; + } + } + break; + + default: + { + cout << "Error: Invalid piece" << endl; + } + break; + } + } + } + else + { + bCheckMate = true; + } + m_bGameFinished = bCheckMate; + return bCheckMate; +} + +bool Game::isKingInCheck(int iColor, IntendedMove* pintended_move) +{ + bool bCheck = false; + Position king = {0}; + //Must check if the intended move is to move the king itself + if (pintended_move != nullptr && toupper(pintended_move -> chPiece) == 'K') + { + king.iRow = pintended_move -> to.iRow; + king.iColumn = pintended_move -> to.iColumn; + } + else + { + king = findKing(iColor); + } + + UnderAttack king_attacked = isUnderAttack(king.iRow, king.iColumn, iColor, pintended_move); + if (king_attacked.bUnderAttack == true) + { + bCheck = true; + } + return bCheck; +} + +bool Game::playerKingInCheck(IntendedMove* intended_move) +{ + return isKingInCheck(getCurrentTurn(), intended_move); +} + +bool Game::wouldKingBeInCheck(char chPiece, Position present, Position future, EnPassant* S_enPassant) +{ + IntendedMove intended_move; + + intended_move.chPiece = chPiece; + intended_move.from = present; + intended_move.to = future; + return playerKingInCheck(&intended_move); +} + +Chess::Position Game::findKing(int iColor) +{ + char chToLook = (iColor == WHITE_PIECE) ? 'K' : 'k'; + Position king = {0}; + for (int i=0;i<8;i++) + { + for (int j=0;j<8;j++) + { + if (getPieceAtPosition(i,j) == chToLook) + { + king.iRow = i; + king.iColumn = j; + } + } + } + return king; +} + +void Game::changeTurns(void) +{ + if (m_CurrentTurn == WHITE_PIECE) + { + m_CurrentTurn = BLACK_PIECE; + } + else + { + m_CurrentTurn = WHITE_PIECE; + } +} + +bool Game::isFinished(void) +{ + return m_bGameFinished; +} + +int Game::getCurrentTurn(void) +{ + return m_CurrentTurn; +} + +int Game::getOpponentColor(void) +{ + return (m_CurrentTurn == WHITE_PIECE) ? BLACK_PIECE : WHITE_PIECE; +} + +void Game::parseMove(string move, Position* pFrom, Position* pTo, char* chPromoted) +{ + pFrom->iColumn = move[0]; + pFrom->iRow = move[1]; + pTo->iColumn = move[3]; + pTo->iRow = move[4]; + + pFrom ->iColumn -= 'A'; + pTo ->iColumn -= 'A'; + + pFrom ->iRow -= '1'; + pTo ->iRow -= '1'; + + if (chPromoted != nullptr) + { + if(move[5] == '=') + { + *chPromoted = move[6]; + } + else + { + *chPromoted = EMPTY_SQUARE; + } + } +} \ No newline at end of file diff --git a/src/Game.h b/src/Game.h new file mode 100644 index 0000000..ef23c57 --- /dev/null +++ b/src/Game.h @@ -0,0 +1,65 @@ +#ifndef _GAME_H_ +#define _GAME_H_ +#include "includes.h" +#include "Chess.h" + +class Game : public Chess +{ + public: + Game(); + + ~Game(); + + void movePiece( Position present, Position future, EnPassant* S_enPassant, Castling* S_castling, Promotion* S_promotion ); + + bool castlingAllowed( Side iSide, int iColor ); + + char getPieceAtPosition( Position pos ); + + char getPieceAtPosition( int iRow, int iColumn ); + + char getPiece_considerMove( int iRow, int iColumn, IntendedMove* intended_move = nullptr ); + + UnderAttack isUnderAttack( int iRow, int iColumn, int iColor, IntendedMove* pintended_move = nullptr ); + + bool isReachable( int iRow, int iColumn, int iColor ); + + bool isSquareOccupied( int iRow, int iColumn); + + bool isPathFree( Position startingPos, Position finishingPos, int iDirection ); + + bool canBeBlocked( Position startingPos, Position finishinPos, int iDirection ); + + bool isCheckMate(); + + bool isKingInCheck( int iColor, IntendedMove* intended_move = nullptr ); + + bool playerKingInCheck( IntendedMove* intended_move = nullptr ); + + bool wouldKingBeInCheck( char chPiece, Position present, Position future, EnPassant* S_enPassant ); + + Position findKing( int iColor ); + + void changeTurns( void ); + + bool isFinished( void ); + + int getCurrentTurn( void ); + + int getOpponentColor( void ); + + void parseMove(string move, Position* pFrom, Position* pTo, char* chPromoted = nullptr ); + + // Save the captured pieces + vector<char> white_captured; + vector<char> black_captured; + + private: + char board[8][8]; + bool m_bCastlingKingSideAllowed[2]; + bool m_bCastlingQueenSideAllowed[2]; + int m_CurrentTurn; + bool m_bGameFinished; + +}; +#endif \ No newline at end of file diff --git a/src/Knight.cpp b/src/Knight.cpp deleted file mode 100644 index cede3d2..0000000 --- a/src/Knight.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "Knight.h" -#include <iostream> -using namespace std; - -Knight::Knight(PieceColor color, Position pos) -{ - this->color = color; - this->pos = pos; - this->type = "N"; -} - -Knight::~Knight() -{ -} - -bool Knight::isValidMove(Position newPos) -{ - if (newPos.x < 0 || newPos.x > 7 || newPos.y < 0 || newPos.y > 7) - { - return false; - } - if (newPos.x == pos.x || newPos.y == pos.y) - { - return false; - } - if (abs(newPos.x - pos.x) == 2 && abs(newPos.y - pos.y) == 1) - { - return true; - } - if (abs(newPos.x - pos.x) == 1 && abs(newPos.y - pos.y) == 2) - { - return true; - } - return false; -} \ No newline at end of file diff --git a/src/Knight.h b/src/Knight.h deleted file mode 100644 index b3d9e26..0000000 --- a/src/Knight.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _KNIGHT_H -#define _KNIGHT_H -#include "Piece.h" - -class Knight : public Piece -{ - public: - /** - * @brief Default constructor for Knight class. - */ - Knight(PieceColor color, Position pos); - - /** - * @brief Destructor for Knight class. - */ - ~Knight(); - bool isValidMove(Position newPos); -}; - -#endif \ No newline at end of file diff --git a/src/Piece.cpp b/src/Piece.cpp deleted file mode 100644 index 68ec406..0000000 --- a/src/Piece.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "Piece.h" -#include <iostream> -#include <string> -using namespace std; - -// constructor -Piece::Piece() -{ - type = " "; -} - -// destructor -Piece::~Piece() -{ -} - -void Piece::draw() const -{ - if (color == PieceColor::BLACK) - { - cout << "B"; - } - else - { - cout << "W"; - } - cout << type; -} - -void Piece::setPosition(Position pos) -{ - this->pos = pos; -} - -PieceColor Piece::getColor() -{ - return color; -} \ No newline at end of file diff --git a/src/Piece.h b/src/Piece.h deleted file mode 100644 index 06af0ff..0000000 --- a/src/Piece.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _PIECE_H_ -#define _PIECE_H_ -#include <string> - -/** - * @enum PieceColor - * @brief Enum class representing the color of a chess piece. - */ -enum class PieceColor -{ - WHITE, ///< White color - BLACK ///< Black color -}; - -struct Position -{ - int x; ///< The x-coordinate of the position - int y; ///< The y-coordinate of the position -}; - - -/** - * @class Piece - * @brief Class representing a chess piece. - */ -class Piece -{ - protected: - std::string type; ///< The type of the piece - PieceColor color; ///< The color of the piece - Position pos; ///< The position of the piece on the board - public: - /** - * @brief Default constructor for Piece class. - */ - Piece(); - - /** - * @brief Destructor for Piece class. - */ - ~Piece(); - - /** - * @brief Draws the piece on the board. - */ - void draw() const; - - /** - * @brief Sets the position of the piece on the board. - * @param pos The new position of the piece. - */ - void setPosition(Position pos); - - /** - * @brief Get the Position object - * - * @return Position - */ - Position getPosition(); - - /** - * @brief Gets the color of the piece. - * @return The color of the piece. - */ - PieceColor getColor(); - - /** - * @brief Checks if a move to a new position is valid for the piece. - * @param newPos The new position to move to. - * @return True if the move is valid, false otherwise. - */ - virtual bool isValidMove(Position newPos) = 0; -}; - -#endif \ No newline at end of file diff --git a/src/Rook.cpp b/src/Rook.cpp deleted file mode 100644 index c216f3c..0000000 --- a/src/Rook.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Rook.h" -#include <iostream> -using namespace std; - -Rook::Rook(PieceColor color, Position pos) -{ - this->color = color; - this->pos = pos; - this->type = "R"; -} - -Rook::~Rook() -{ -} - diff --git a/src/Rook.h b/src/Rook.h deleted file mode 100644 index 3bcb289..0000000 --- a/src/Rook.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _ROOK_H -#define _ROOK_H -#include "Piece.h" - -class Rook : public Piece -{ - public: - /** - * @brief Default constructor for Rook class. - */ - Rook(PieceColor color, Position pos); - - /** - * @brief Destructor for Rook class. - */ - ~Rook(); - bool isValidMove(Position newPos); -}; - -#endif \ No newline at end of file diff --git a/src/Square.cpp b/src/Square.cpp deleted file mode 100644 index baa7650..0000000 --- a/src/Square.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "Square.h" -#include "Piece.h" - -Square::Square(int x, int y) -{ - x = x; - y = y; - piece = nullptr; -} - -Square::~Square() -{ -} - -void Square::setPieceOccupying(Piece* piece) -{ - piece = piece; -} - -int Square::getX() const -{ - return x; -} - -int Square::getY() const -{ - return y; -} - -bool Square::occupied() const -{ - return piece != nullptr; -} - -Piece* Square::getPieceOccupying() const -{ - return piece; -} \ No newline at end of file diff --git a/src/Square.h b/src/Square.h deleted file mode 100644 index a729826..0000000 --- a/src/Square.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _SQUARE_H -#define _SQUARE_H - -class Piece; - -/** - * @class Square - * @brief Represents a square on a chessboard. - */ -class Square -{ - private: - int x; /**< The x-coordinate of the square. */ - int y; /**< The y-coordinate of the square. */ - Piece* piece; /**< The piece occupying the square. */ - - public: - /** - * @brief Constructs a Square object with the given coordinates. - * @param x The x-coordinate of the square. - * @param y The y-coordinate of the square. - */ - Square(int x, int y); - - /** - * @brief Constructs a Square object with default coordinates (0, 0). - */ - Square(); - - /** - * @brief Destroys the Square object. - */ - ~Square(); - - /** - * @brief Sets the piece occupying the square. - * @param piece A pointer to the Piece object. - */ - void setPieceOccupying(Piece* piece); - - /** - * @brief Gets the x-coordinate of the square. - * @return The x-coordinate. - */ - int getX() const; - - /** - * @brief Gets the y-coordinate of the square. - * @return The y-coordinate. - */ - int getY() const; - - /** - * @brief Checks if the square is occupied by a piece. - * @return True if the square is occupied, false otherwise. - */ - bool occupied() const; - - /** - * @brief Gets the piece occupying the square. - * @return A pointer to the Piece object. - */ - Piece* getPieceOccupying() const; -}; - -#endif \ No newline at end of file diff --git a/src/includes.h b/src/includes.h new file mode 100644 index 0000000..7e4bd4d --- /dev/null +++ b/src/includes.h @@ -0,0 +1,14 @@ +#ifndef _INCLUDES_H +#define _INCLUDES_H +#include <stdio.h> +#include <iostream> +#include <iomanip> +#include <string> +#include <deque> +#include <vector> +#include <fstream> +#include <chrono> + +#include <string> +using namespace std; +#endif \ No newline at end of file diff --git a/src/user_interface.cpp b/src/user_interface.cpp new file mode 100644 index 0000000..df1ea90 --- /dev/null +++ b/src/user_interface.cpp @@ -0,0 +1,50 @@ +#include "user_interface.h" +#include "Game.h" +void clearScreen(void) +{ + system("cls"); +} + +void printMenu(void) +{ + cout << "Commands: (N)ew game, (M)ove, (Q)uit" << endl; +} + +void printMessage(string msg) +{ + cout << msg << endl; +} + +void printLine(int iLine, int iColor1, int iColor2, Game& game) +{ + int CELL = 6; + for(int subLine = 0; subLine < CELL/2; subLine++) + { + for (int iPair = 0; iPair < 4; iPair++) + { + for (int subColumn = 0; subColumn < CELL; subColumn++) + { + if (subLine == 1 && subColumn == 3) + { + cout << char(game.getPieceAtPosition(iLine, iPair*2) != 0x20 ? game.getPieceAtPosition(iLine, iPair*2) : iColor1); + } + else cout << char(iColor1); + } + for (int subColumn = 0; subColumn < CELL; subColumn++) + { + if (subLine == 1 && subColumn == 3) + { + cout << char(game.getPieceAtPosition(iLine, iPair*2+1) != 0x20 ? game.getPieceAtPosition(iLine, iPair*2+1) : iColor2); + } + else cout << char(iColor2); + } + } + if ( 1 == subLine ) + { + cout << " " << iLine+1; + } + cout << "\n"; + + } + +} \ No newline at end of file diff --git a/src/user_interface.h b/src/user_interface.h new file mode 100644 index 0000000..5e43bd4 --- /dev/null +++ b/src/user_interface.h @@ -0,0 +1,18 @@ +#ifndef _USER_INTERFACE_H_ +#define _USER_INTERFACE_H_ +#include "Chess.h" + +#define WHITE_SQUARE 0xDB +#define BLACK_SQUARE 0xFF +#define EMPTY_SQUARE 0x20 + +void createNextMessage( string msg ); +void appendToNextMessage( string msg ); +void clearScreen( void );; +void printMenu( void ); +void printMessage( string msg ); +void printLine( int iLine, int iColor1, int iColor2, Game& game ); +void printSituation( Game& game ); +void printBoard(Game& game); + +#endif \ No newline at end of file -- GitLab