13 #ifndef EMP_GAME_OTHELLO_H 14 #define EMP_GAME_OTHELLO_H 19 #include <unordered_map> 21 #include "../base/array.h" 22 #include "../base/assert.h" 23 #include "../base/vector.h" 24 #include "../tools/math.h" 41 template <
size_t BOARD_SIZE>
44 static constexpr
size_t NUM_CELLS = BOARD_SIZE * BOARD_SIZE;
46 using board_t = std::array<Player, NUM_CELLS>;
53 Index(
size_t x,
size_t y) : pos() { Set(x,y); }
56 operator size_t()
const {
return pos; }
57 size_t x()
const {
return pos % BOARD_SIZE; }
58 size_t y()
const {
return pos / BOARD_SIZE; }
59 void Set(
size_t x,
size_t y) { pos = (x<BOARD_SIZE && y<BOARD_SIZE) ? (x+y*BOARD_SIZE) : NUM_CELLS; }
60 bool IsValid()
const {
return pos < NUM_CELLS; }
65 case Facing::N: { faced_id.
Set(x() , y() - 1);
break; }
66 case Facing::S: { faced_id.
Set(x() , y() + 1);
break; }
68 case Facing::W: { faced_id.
Set(x() - 1, y() );
break; }
69 case Facing::NE: { faced_id.
Set(x() + 1, y() - 1);
break; }
70 case Facing::NW: { faced_id.
Set(x() - 1, y() - 1);
break; }
71 case Facing::SE: { faced_id.
Set(x() + 1, y() + 1);
break; }
72 case Facing::SW: { faced_id.
Set(x() - 1, y() + 1);
break; }
92 Othello_Game() : ALL_DIRECTIONS({ Facing::N, Facing::NE,
Facing::E, Facing::SE, Facing::S, Facing::SW, Facing::W, Facing::NW })
93 , neighbors(BuildNeighbors()), cur_player(Player::DARK), game_board() {
105 for (
size_t i = 0; i < NUM_CELLS; ++i) game_board[i] =
Player::NONE;
112 SetPos({BOARD_SIZE/2 - 1, BOARD_SIZE/2 - 1}, Player::LIGHT);
113 SetPos({BOARD_SIZE/2 - 1, BOARD_SIZE/2 }, Player::DARK);
114 SetPos({BOARD_SIZE/2, BOARD_SIZE/2 - 1}, Player::DARK);
115 SetPos({BOARD_SIZE/2, BOARD_SIZE/2 }, Player::LIGHT);
118 cur_player = Player::DARK;
128 return (player == Player::DARK) ? Player::LIGHT : Player::DARK;
137 if (neighbors.
size() == 0) {
139 for (
size_t posID = 0; posID < NUM_CELLS; ++posID) {
141 for (
Facing dir : ALL_DIRECTIONS) {
142 neighbors[GetNeighborIndex(posID, dir)] = pos.
CalcNeighbor(dir);
153 if (!
id.IsValid())
return Index();
154 return neighbors[GetNeighborIndex(
id, dir)];
160 return game_board[id];
169 if (!pos.
IsValid())
return false;
171 return HasValidFlips(player, pos);
181 const Player opponent = GetOpponent(player);
182 for (
Facing dir : ALL_DIRECTIONS) {
183 Index neighbor_pos = GetNeighbor(pos, dir);
185 while (neighbor_pos.
IsValid() && GetPosOwner(neighbor_pos) == opponent) {
187 neighbor_pos = GetNeighbor(neighbor_pos, dir);
192 else { prev_len = flip_list.
size(); }
199 size_t flip_count = 0;
200 const Player opponent = GetOpponent(player);
201 for (
Facing dir : ALL_DIRECTIONS) {
203 size_t dir_count = 0;
204 Index neighbor_pos = GetNeighbor(pos, dir);
205 while (neighbor_pos.
IsValid() && GetPosOwner(neighbor_pos) == opponent) {
207 neighbor_pos = GetNeighbor(neighbor_pos, dir);
210 if (neighbor_pos.
IsValid() && GetPosOwner(neighbor_pos) == player) { flip_count += dir_count; }
217 const Player opponent = GetOpponent(player);
218 for (
Facing dir : ALL_DIRECTIONS) {
219 Index neighbor_pos = GetNeighbor(pos, dir);
222 while (neighbor_pos.
IsValid() && GetPosOwner(neighbor_pos) == opponent) {
224 neighbor_pos = GetNeighbor(neighbor_pos, dir);
227 if (count && neighbor_pos.
IsValid() && GetPosOwner(neighbor_pos) == player) {
return true; }
237 for (
size_t i = 0; i < NUM_CELLS; ++i) {
238 if (IsValidMove(player, i)) valid_moves.
emplace_back(i);
249 for (
size_t i = 0; i < NUM_CELLS; ++i) {
250 if (IsValidMove(player, i))
return true;
258 return std::count(game_board.begin(), game_board.end(), player);
264 size_t frontier_size = 0;
265 for (
size_t i = 0; i < NUM_CELLS; ++i) {
267 if (IsAdjacentTo(i, player)) ++frontier_size;
270 return frontier_size;
275 for (
Facing dir : ALL_DIRECTIONS) {
276 Index nID = GetNeighbor(pos, dir);
278 if (GetPosOwner(nID) == owner)
return true;
286 game_board[pos] = player;
291 for (
auto x : ids) SetPos(x, player);
319 DoFlips(player, pos);
320 auto opp_moves = HasMoveOptions(GetOpponent(player));
321 if (opp_moves) { cur_player = GetOpponent(player);
return false; }
323 auto player_moves = HasMoveOptions(player);
324 if (player_moves) {
return true; }
333 auto flip_list = GetFlipList(player, pos);
334 for (
Index flip : flip_list) { SetPos(flip, player); }
338 void Print(std::ostream & os=std::cout, std::string dark_token =
"D",
339 std::string light_token =
"L", std::string open_space =
"O") {
341 unsigned char letter =
'A';
343 for (
size_t i = 0; i < BOARD_SIZE; ++i) os <<
char(letter + i) <<
" ";
346 for (
size_t y = 0; y < BOARD_SIZE; ++y) {
348 for (
size_t x = 0; x < BOARD_SIZE; ++x) {
349 Player space = GetPosOwner({x,y});
350 if (space == Player::DARK) { os << dark_token <<
" "; }
351 else if (space == Player::LIGHT) { os << light_token <<
" "; }
352 else { os << open_space <<
" "; }
Player
Definition: Othello.h:35
size_t GetNumCells() const
Definition: Othello.h:122
const board_t & GetBoard() const
Definition: Othello.h:164
Player GetOpponent(Player player) const
Get opponent ID of give player ID.
Definition: Othello.h:126
constexpr const double E
e
Definition: const.h:18
bool IsValidMove(Player player, Index pos)
Is given move valid?
Definition: Othello.h:167
Index(size_t _pos)
Definition: Othello.h:52
size_t GetFlipCount(Player player, Index pos)
Count the number of positions that would flip if we placed a piece at a specific location.
Definition: Othello.h:198
bool IsOver() const
Definition: Othello.h:174
size_t x() const
Definition: Othello.h:57
std::array< Player, NUM_CELLS > board_t
Definition: Othello.h:46
bool HasValidFlips(Player player, Index pos)
Are there any valid flips from this position?
Definition: Othello.h:216
Base class for all sizes of Othello games.
Definition: Othello.h:34
emp::vector< Index > neighbors
Definition: Othello.h:80
void SetPos(Index pos, Player player)
Set board position (ID) to given space value.
Definition: Othello.h:284
Player cur_player
Who is the current player set to move next?
Definition: Othello.h:83
Class for othello games of a specific size.
Definition: Othello.h:42
bool IsValidPlayer(Player player) const
Is the given player ID a valid player?
Definition: Othello.h:132
void Set(size_t x, size_t y)
Definition: Othello.h:59
static size_t GetNeighborIndex(Index pos, Facing dir)
Internal function for accessing the neighbors vector.
Definition: Othello.h:87
static constexpr Index GetIndex(size_t x, size_t y)
Definition: Othello.h:100
bool DoNextMove(Index pos)
Definition: Othello.h:309
Othello_Game()
Definition: Othello.h:92
size_t size() const
Definition: vector.h:151
void emplace_back(ARGS &&...args)
Definition: vector.h:219
void SetBoard(const this_t &other_othello)
Set current board to be the same as board from other othello game.
Definition: Othello.h:299
bool IsAdjacentTo(Index pos, Player owner)
Is position given by ID adjacent to the given owner?
Definition: Othello.h:274
auto BuildNeighbors()
Definition: Othello.h:134
emp::vector< Index > GetFlipList(Player player, Index pos)
Definition: Othello.h:178
Facing
Definition: Othello.h:36
size_t y() const
Definition: Othello.h:58
std::array< Facing, NUM_DIRECTIONS > ALL_DIRECTIONS
Definition: Othello.h:79
Index GetNeighbor(Index id, Facing dir) const
Definition: Othello.h:152
static constexpr size_t NUM_DIRECTIONS
Number of neighbors each board space has.
Definition: Othello.h:37
size_t CountFrontierPos(Player player)
Count the number of empty squares adjacent to a player's pieces (frontier size)
Definition: Othello.h:262
void SetPositions(emp::vector< Index > ids, Player player)
Set positions given by ids to be owned by the given player.
Definition: Othello.h:290
constexpr size_t GetBoardWidth() const
Definition: Othello.h:121
emp::vector< Index > GetMoveOptions(Player player)
Get a list of valid move options for given player.
Definition: Othello.h:234
void resize(size_t new_size)
Definition: vector.h:161
bool IsValid() const
Definition: Othello.h:60
bool HasMoveOptions(Player player)
Determine if there are any move options for given player.
Definition: Othello.h:247
~Othello_Game()
Definition: Othello.h:98
If we are in emscripten, make sure to include the header.
Definition: array.h:37
Index()
Definition: Othello.h:51
size_t pos
Definition: Othello.h:49
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
Player GetCurPlayer() const
Definition: Othello.h:123
board_t game_board
Game board.
Definition: Othello.h:84
emp::vector< Index > GetMoveOptions()
GetMoveOptions() without a specified player used current player.
Definition: Othello.h:244
void DoFlips(Player player, Index pos)
NOTE: does not check for move validity.
Definition: Othello.h:331
#define emp_assert(...)
Definition: assert.h:199
board_t & GetBoard()
Definition: Othello.h:163
void SetCurPlayer(Player player)
Set the current player.
Definition: Othello.h:302
void Print(std::ostream &os=std::cout, std::string dark_token="D", std::string light_token="L", std::string open_space="O")
Print board state to given ostream.
Definition: Othello.h:338
void SetBoard(const board_t &other_board)
Definition: Othello.h:296
void Reset()
Reset the board to the starting condition.
Definition: Othello.h:103
double GetScore(Player player)
Get the current score for a given player.
Definition: Othello.h:256
bool DoMove(Player player, Index pos)
Definition: Othello.h:315
Index(size_t x, size_t y)
Definition: Othello.h:53
Player GetPosOwner(Index id) const
Get the value (light, dark, or open) at a position on the board.
Definition: Othello.h:158
Index CalcNeighbor(Facing dir)
Definition: Othello.h:62
Index(const Index &_in)
Definition: Othello.h:54