ScummVM API documentation
checkers.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef MEDIASTATION_MINIGAMES_CHECKERS_H
23 #define MEDIASTATION_MINIGAMES_CHECKERS_H
24 
25 #include "common/array.h"
26 
27 #include "mediastation/actor.h"
28 #include "mediastation/mediascript/collection.h"
29 
30 namespace MediaStation {
31 
32 namespace CheckersMinigame {
33 
34 const int COLUMN_COUNT = 8;
35 const int ROW_COUNT = 8;
36 const int PLAYABLE_CELLS_PER_ROW = 4;
37 const int TOTAL_CELLS = COLUMN_COUNT * ROW_COUNT;
38 const int TOTAL_PLAYABLE_CELLS = ROW_COUNT * PLAYABLE_CELLS_PER_ROW;
39 
40 enum Side {
41  kUnoccupiedBySide = 0,
42  // "Black" is actually red in the game.
43  // Hades always plays black.
44  kBlackSide = 1,
45  kWhiteSide = 2
46 };
47 
48 enum CellClass {
49  kCellNormal,
50  kCellCorner,
51  kCellNearCorner,
52  kCellOuterCenter,
53  kCellCenter
54 };
55 
56 // Classification used by the positional evaluation score heuristic.
57 // Indexed by the standard linear playable-cell numbering.
58 static constexpr CellClass CELL_CLASSIFICATION[TOTAL_PLAYABLE_CELLS] = {
59  kCellCorner, kCellNearCorner, kCellNearCorner, kCellNormal,
60  kCellCorner, kCellNormal, kCellNormal, kCellNormal,
61  kCellNormal, kCellNormal, kCellNormal, kCellOuterCenter,
62  kCellOuterCenter, kCellCenter, kCellCenter, kCellNormal,
63  kCellNormal, kCellCenter, kCellCenter, kCellOuterCenter,
64  kCellOuterCenter, kCellNormal, kCellNormal, kCellNormal,
65  kCellNormal, kCellNormal, kCellNormal, kCellCorner,
66  kCellNormal, kCellNearCorner, kCellNearCorner, kCellCorner
67 };
68 
69 struct Cell {
70  // Scripts use pieceId to track which piece image to show where.
71  int pieceId = 0;
72  Side side = kUnoccupiedBySide;
73  bool isKing = false;
74 
75  bool isOccupied() const { return side != kUnoccupiedBySide; }
76  bool isMan() const { return isOccupied() && !isKing; }
77 };
78 
79 // The coordinates of a particular cell on the checkers board.
80 struct Pair {
81  int x = 0;
82  int y = 0;
83 
84  constexpr Pair() = default;
85  constexpr Pair(int x_, int y_) : x(x_), y(y_) {}
86 
87  Pair(int linearCellIndex); // notationToPair
88  int toLinearCellIndex() const; // pairToNotation
89 
90  bool isWithinBoard() const;
91  Pair operator+(const Pair &other) const;
92 };
93 
94 struct SideConstants {
95  Side opponent;
96  int homeRow;
97  CheckersMinigame::Pair validDirections[4];
98 };
99 
100 struct PieceCounts {
101  int totalBlackMen = 0;
102  int totalBlackKings = 0;
103  int totalWhiteMen = 0;
104  int totalWhiteKings = 0;
105 };
106 
107 struct Move {
108  Pair from;
109  Pair to;
110  Pair capture;
111  bool willCapture = false;
112  bool willBecomeKing = false;
113  int score = 0;
114  Common::Array<Move> nextJumps;
115 
116  Collection *asCollection() const; // moveToCollection
117 };
118 
119 enum CheckersCommand {
120  kCheckersCommandPiecesThatCanMove = 1,
121  kCheckersGetValidMoves = 2,
122  kCheckersNewGame = 3,
123  kCheckersFindBestMove = 4,
124  kCheckersTakeMove = 5,
125  kCheckersCommandDebugPrint = -2,
126  kCheckersCommandValidateBoard = -1
127 };
128 
129 // The full 8x8 checkers grid. Although only the dark squares are ever playable,
130 // every square is stored so that a Pair's (x, y) coordinates map directly onto
131 // the backing storage.
132 class Board : public Common::Array<Cell> {
133 public:
134  Cell &cellAt(const Pair &position);
135  const Cell &cellAt(const Pair &position) const;
136  Cell &cellAt(uint linearIndex);
137 };
138 
139 // A simple checkers engine that uses minimax with alpha/beta pruning.
140 class Checkers {
141 public:
142  Checkers(Collection *collection); // checkers_initBoard
143 
144  void setBoard(const Common::Array<int> &squares);
145  Common::Array<CheckersMinigame::Pair> piecesThatCanMove(Side side);
146  void getValidMovesForPiece(
147  const Pair &position, Common::Array<Move> &moves, bool capturesOnly); // movesOfPiece
148  bool calculateAndSortAllMovesForSide(Side side);
149  void prepareForBestMoveSearch(int depth);
150  bool searchForBestMove(int maxSearchTimeInMs);
151  Move &getCalculatedBestMove(); // bestMoveCalculated
152  bool validateBoard() const;
153  void printToDebug() const;
154 
155 private:
156  Board _board;
157  Common::Array<Move> _moves;
158  int _maxSearchDepth = 1;
159  Side _sideToMove = kUnoccupiedBySide;
160  Move _bestMove;
161 
162  const SideConstants &constantsForSide(Side side) const;
163  bool checkForJumps(const Board &board, Side side, const Pair *checkPosition, Common::Array<Move> &moves); // checkForJumps
164  bool checkForSlides(const Board &board, Side side, const Pair *checkPosition, Common::Array<Move> &moves);
165  void updateMovesThatKing(const Board &board, Common::Array<Move> &moves);
166  bool canMove(const Board &board, Side side);
167  void addMove(Common::Array<Move> &moves, const Pair &start, const Pair &end, const Pair *captured, bool becameKing);
168  void makeMove(Board &board, const Move &move);
169 
170  bool calculateAndSortMovesForSide(const Board &board, Side side, Common::Array<Move> &moves);
171  void calculatePointsForMoves(const Board &board, Common::Array<Move> &moves); // calculateMovePoints
172  int alphaBetaEvaluate(const Board &board, Move &parentMove, Side maximizingSide, Side sideToMove, int alpha, int beta, int ply, uint32 deadline);
173 
174  // This is the score that the minimax is optimizing.
175  int getTotalBoardScoreForSide(const Board &board, Side side);
176  int getWeightedSquareScoreForSide(const Board &board, Side side);
177  PieceCounts getPieceCounts(const Board &board);
178  void sortMovesByScore(Common::Array<Move> &moves);
179 };
180 
181 // Functor to allow sorting moves by their score.
183  bool operator()(const CheckersMinigame::Move &left, const CheckersMinigame::Move &right) const {
184  return left.score > right.score;
185  }
186 };
187 
188 } // End of namespace CheckersMinigame
189 
190 } // End of namespace MediaStation
191 
192 #endif
Definition: actor.h:34
Definition: array.h:52
Definition: checkers.h:80
Definition: checkers.h:69
Definition: collection.h:36
Out move(In first, In last, Out dst)
Definition: algorithm.h:109
Definition: checkers.h:107
Definition: checkers.h:132