Browse Source

Updated checkers

Vsevolod Levitan 10 months ago
parent
commit
5880662ee0

+ 57 - 19
Checkers/Checkers/CheckerBoard.cpp

@@ -2,12 +2,10 @@
 #include <iostream>
 
 
-void CheckerBoard::placeChecker(CheckerPosition position, CheckerPiece checker) {
-    board[position.x][position.y] = checker;
+CheckerBoard::CheckerBoard() {
+    lastMove = "NONE";
 }
 
-CheckerBoard::CheckerBoard() {}
-
 CheckerBoard CheckerBoard::loadFromFile(string filename) {
     CheckerBoard board = CheckerBoard();
 
@@ -59,7 +57,21 @@ void CheckerBoard::setCheckerAt(CheckerPosition pos, CheckerPiece checker)
 void CheckerBoard::moveChecker(CheckerPosition from, CheckerPosition to) {
     CheckerPiece checker = getCheckerAt(from);
     setCheckerAt(from, CheckerPiece::NONE);
+    int cx = to.x - from.x > 0 ? 1 : -1;
+    int cy = to.y - from.y > 0 ? 1 : -1;
+    int sx = from.x + cx;
+    int sy = from.y + cy;
+
+    while (sx != to.x)
+    {
+        setCheckerAt(CheckerPosition(sx, sy), CheckerPiece::NONE);
+        sx += cx;
+        sy += cy;
+    }
     setCheckerAt(to, checker);
+
+    if (checker == CheckerPiece::WHITE && to.y == BOARD_SIZE - 1) setCheckerAt(to, CheckerPiece::WHITE_KING);
+    else  if (checker == CheckerPiece::BLACK && to.y == 0) setCheckerAt(to, CheckerPiece::BLACK_KING);
 }
 
 void CheckerBoard::print() const
@@ -148,11 +160,12 @@ void CheckerBoard::generateMovesForPiece(CheckerPosition pos, std::vector<Checke
 
     for (auto& dir : directions) {
         CheckerPosition newpos(pos.x + dir[0], pos.y + dir[1]);
+        CheckerPosition cpos(pos.x + 2 * dir[0], pos.y + 2 * dir[1]);
 
         if (isValidMove(pos, newpos, piece)) {
             CheckerBoard newBoard = *this;
             newBoard.moveChecker(pos, newpos);
-            newBoard.move = pos.to_num_string() + " -> " + newpos.to_num_string();
+            newBoard.lastMove = pos.to_num_string() + " -> " + newpos.to_num_string();
             newBoard.moveOldPos = pos;
             newBoard.moveNewPos = newpos;
 
@@ -161,17 +174,41 @@ void CheckerBoard::generateMovesForPiece(CheckerPosition pos, std::vector<Checke
             }
 
             moves.push_back(newBoard);
-        }
 
-        CheckerPosition cpos(pos.x + 2 * dir[0], pos.y + 2 * dir[1]);
-        if (isValidCapture(pos, newpos, cpos, piece)) {
+            CheckerPosition cpos(pos.x + 2 * dir[0], pos.y + 2 * dir[1]);
+            if (isValidCapture(pos, newpos, cpos, piece)) {
+                CheckerBoard newBoard = *this;
+                CheckerPiece checker = newBoard.getCheckerAt(pos);
+
+                newBoard.lastMove = pos.to_num_string() + " -> " + newpos.to_num_string();
+                newBoard.moveOldPos = pos;
+                newBoard.moveNewPos = newpos;
+
+                newBoard.setCheckerAt(newpos, CheckerPiece::NONE);
+                newBoard.setCheckerAt(pos, CheckerPiece::NONE);
+                newBoard.setCheckerAt(cpos, checker);
+
+                if ((piece == WHITE && newpos.y == BOARD_SIZE - 1) || (piece == BLACK && cpos.y == 0)) {
+                    newBoard.setCheckerAt(cpos, (piece == WHITE) ? WHITE_KING : BLACK_KING);
+                }
+
+                moves.push_back(newBoard);
+                //generateAdditionalCaptures(cpos, newBoard, moves);
+            }
+        }
+        else if (isValidCapture(pos, newpos, cpos, piece)) {
             CheckerBoard newBoard = *this;
             CheckerPiece checker = newBoard.getCheckerAt(pos);
+
+            newBoard.lastMove = pos.to_num_string() + " -> " + newpos.to_num_string();
+            newBoard.moveOldPos = pos;
+            newBoard.moveNewPos = newpos;
+
             newBoard.setCheckerAt(newpos, CheckerPiece::NONE);
             newBoard.setCheckerAt(pos, CheckerPiece::NONE);
             newBoard.setCheckerAt(cpos, checker);
 
-            if ((piece == WHITE && newpos.y == BOARD_SIZE-1) || (piece == BLACK && cpos.y == 0)) {
+            if ((piece == WHITE && newpos.y == BOARD_SIZE - 1) || (piece == BLACK && cpos.y == 0)) {
                 newBoard.setCheckerAt(cpos, (piece == WHITE) ? WHITE_KING : BLACK_KING);
             }
 
@@ -211,8 +248,8 @@ bool CheckerBoard::isValidMove(CheckerPosition oldPos, CheckerPosition newPos, C
         {
             CheckerPiece between = getCheckerAt(CheckerPosition(sx, sy));
 
-            if (isWhite && !(between == CheckerPiece::BLACK || between == CheckerPiece::BLACK_KING)) return false;
-            if (!isWhite && !(between == CheckerPiece::WHITE || between == CheckerPiece::WHITE_KING)) return true;
+            if (isWhite && !(between == CheckerPiece::BLACK || between == CheckerPiece::BLACK_KING || between == CheckerPiece::NONE)) return false;
+            if (!isWhite && !(between == CheckerPiece::WHITE || between == CheckerPiece::WHITE_KING || between == CheckerPiece::NONE)) return false;
 
             sx += cx;
             sy += cy;
@@ -220,14 +257,20 @@ bool CheckerBoard::isValidMove(CheckerPosition oldPos, CheckerPosition newPos, C
     }
     else
     {
-        if (abs(dx) == 2)
+        if (isWhite && dy == -1) return false;
+        else if (!isWhite && dy == 1) return false;
+        else if (abs(dx) == 2)
         {
             CheckerPiece between = getCheckerAt(CheckerPosition(oldPos.x + cx, oldPos.y + cy));
+            if (between == CheckerPiece::NONE) return false;
+            if (getCheckerAt(newPos) != CheckerPiece::NONE) return false;
             if (isWhite && !(between == CheckerPiece::BLACK || between == CheckerPiece::BLACK_KING)) return false;
-            if (!isWhite && !(between == CheckerPiece::WHITE || between == CheckerPiece::WHITE_KING)) return true;
+            if (!isWhite && !(between == CheckerPiece::WHITE || between == CheckerPiece::WHITE_KING)) return false;
         }
         else if (abs(dx) > 2) return false;
     }
+
+    return true;
 }
 
 void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard& currentBoard, std::vector<CheckerBoard>& moves) const {
@@ -240,9 +283,6 @@ void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard&
         if (isValidCapture(pos, npos, cpos, piece)) {
             CheckerBoard newBoard = currentBoard;
 
-            wcout << "OldBoard: " << endl;
-            newBoard.print();
-
             newBoard.setCheckerAt(cpos, newBoard.getCheckerAt(pos));
             newBoard.setCheckerAt(pos, CheckerPiece::NONE);
             newBoard.setCheckerAt(npos, CheckerPiece::NONE);
@@ -251,9 +291,6 @@ void CheckerBoard::generateAdditionalCaptures(CheckerPosition pos, CheckerBoard&
                 newBoard.setCheckerAt(cpos, (piece == WHITE) ? WHITE_KING : BLACK_KING);
             }
 
-            wcout << "NewBoard: " << endl;
-            newBoard.print();
-
             moves.push_back(newBoard);
             generateAdditionalCaptures(cpos, newBoard, moves);
         }
@@ -265,6 +302,7 @@ bool CheckerBoard::isValidCapture(CheckerPosition pos, CheckerPosition newPos, C
     CheckerPiece newC = getCheckerAt(newPos);
     CheckerPiece cC = getCheckerAt(cpos);
     if (!cpos.isValid()) return false;
+    if (cC != CheckerPiece::NONE) return false;
     if (newC == CheckerPiece::NONE) return false;
 
     if (piece == WHITE && (newC == BLACK || newC == BLACK_KING)) return true;

+ 1 - 8
Checkers/Checkers/CheckerBoard.h

@@ -17,20 +17,13 @@ const int BOARD_SIZE = 8;
 /// </summary>
 class CheckerBoard {
 public:
-    std::string move = "";
+    std::string lastMove = "";
     CheckerPosition moveOldPos = CheckerPosition(-1, -1);
     CheckerPosition moveNewPos = CheckerPosition(-1, -1);
     CheckerPiece board[BOARD_SIZE][BOARD_SIZE];
 
     CheckerBoard();
 
-    /// <summary>
-    /// Place a checker on the board
-    /// </summary>
-    /// <param name="checker">Checker instance</param>
-    /// <param name="color">Color of the checker (black or white)</param>
-    void placeChecker(CheckerPosition position, CheckerPiece checker);
-
     /// <summary>
     /// Load checkerboard from file
     /// </summary>

+ 1 - 1
Checkers/Checkers/CheckersAI.cpp

@@ -25,7 +25,7 @@ CheckerBoard CheckersAI::findBestMove(const CheckerBoard& board, int depth) {
         }
         if (alpha >= beta) break;
     }
-    wcout << "Best move: " << bestMove.move.c_str() << endl;
+    wcout << "Best move: " << bestMove.lastMove.c_str() << endl;
 
     return bestMove;
 }

+ 15 - 0
Checkers/Checkers/CheckersAI.h

@@ -6,10 +6,25 @@ class CheckersAI {
 public:
     CheckersAI(bool isWhite) : isWhite(isWhite) {}
 
+    /// <summary>
+    /// Find best possible move on the given board
+    /// </summary>
+    /// <param name="board">The board setup</param>
+    /// <param name="depth">Minimax search depth</param>
+    /// <returns>Updated board</returns>
     CheckerBoard findBestMove(const CheckerBoard& board, int depth);
 
 private:
     bool isWhite;
 
+    /// <summary>
+    /// Recursively find best performing move
+    /// </summary>
+    /// <param name="board">The board setup</param>
+    /// <param name="depth">Search depth</param>
+    /// <param name="alpha">Alpha value</param>
+    /// <param name="beta">Beta value</param>
+    /// <param name="isMaximizing">Seek for maximum value, otherwise seek for minimum</param>
+    /// <returns>Evaluated score</returns>
     int minimax(CheckerBoard board, int depth, int alpha, int beta, bool isMaximizing);
 };

BIN
Checkers/Checkers/README.docx


+ 11 - 1
Checkers/Checkers/main.cpp

@@ -24,12 +24,22 @@ int main()
         if (whiteTurn) {
             wcout << "White: ";
             CheckerBoard bestMove = whiteAI.findBestMove(board, 7);
+            if (bestMove.lastMove == "NONE")
+            {
+                wcout << "White forfeit";
+                return 0;
+            }
             board.applyMove(bestMove);
         }
         // Раскомментировать для игры ИИ против ИИ
         /*else {
             wcout << "Black: ";
             CheckerBoard bestMove = blackAI.findBestMove(board, 7);
+            if (bestMove.lastMove == "NONE")
+            {
+                wcout << "Black forfeit";
+                return 0;
+            }
             board.applyMove(bestMove);
         }*/
         // Раскомментировать для игры Человек против ИИ
@@ -51,7 +61,7 @@ int main()
                 int cx = newPos.x + dx;
                 int cy = newPos.y + dy;
 
-                if (!board.isValidMove(pos, newPos, board.getCheckerAt(pos)) && !board.isValidCapture(pos, newPos, CheckerPosition(cx, cy), board.getCheckerAt(pos)))
+                if (!board.isValidMove(pos, newPos, board.getCheckerAt(pos))/* && !board.isValidCapture(pos, newPos, CheckerPosition(cx, cy), board.getCheckerAt(pos))*/)
                 {
                     wcout << "Wrong position" << endl;
                     continue;