Empirical
Mancala.h
Go to the documentation of this file.
1 // This file is part of Empirical, https://github.com/devosoft/Empirical
2 // Copyright (C) Michigan State University, 2016-2017.
3 // Released under the MIT Software license; see doc/LICENSE
4 //
5 //
6 // A simple Malcala game state handler.
7 
8 #ifndef EMP_GAME_MANCALA_H
9 #define EMP_GAME_MANCALA_H
10 
11 #include <fstream>
12 #include <iostream>
13 #include <iomanip>
14 #include <unordered_map>
15 
16 #include "../base/array.h"
17 #include "../base/assert.h"
18 #include "../base/vector.h"
19 #include "../tools/math.h"
20 
21 namespace emp {
22 
23  class Mancala {
24  private:
26 
27  side_t boardA; // Current board state for side A.
28  side_t boardB; // Current board state for side B.
29  bool over = false; // Has the game ended?
30  size_t is_A_turn; // Which player goes next?
31 
32  void TestOver() {
33  bool side_A_empty = true;
34  bool side_B_empty = true;
35 
36  for (size_t i = 0; i < 6; i++) {
37  if (boardA[i] > 0) { side_A_empty = false; }
38  if (boardB[i] > 0) { side_B_empty = false; }
39  }
40 
41  over = ( (is_A_turn && side_A_empty) || (!is_A_turn && side_B_empty));
42  }
43 
44  public:
45  using move_t = size_t;
46 
47  Mancala(bool A_first=true) : boardA(), boardB(), over(false), is_A_turn(true) {
48  Reset(A_first);
49  }
50  ~Mancala() { ; }
51 
52  void Reset(bool A_first=true) {
53  for (size_t i = 0; i < 6; i++) { boardA[i] = 4; boardB[i] = 4; }
54  boardA[6] = boardB[6] = 0;
55  over = false;
56  is_A_turn = A_first;
57  }
58 
59  size_t GetA(size_t i) const { return boardA[i]; }
60  size_t GetB(size_t i) const { return boardB[i]; }
61 
62  const side_t & GetSideA() const { return boardA; }
63  const side_t & GetSideB() const { return boardB; }
64  const side_t & GetCurSide() const { return is_A_turn ? boardA : boardB; }
65  const side_t & GetOtherSide() const { return is_A_turn ? boardB : boardA; }
66  side_t & GetSideA() { return boardA; }
67  side_t & GetSideB() { return boardB; }
68  side_t & GetCurSide() { return is_A_turn ? boardA : boardB; }
69  side_t & GetOtherSide() { return is_A_turn ? boardB : boardA; }
70 
71  std::unordered_map<int, double> AsInput(size_t player_id) const {
72  std::unordered_map<int, double> input_map;
73  size_t offset = (player_id == 0) ? 0 : 7;
74  for (size_t i = 0; i < 7; i++) {
75  input_map[(int)(i+offset)] = (double) boardA[i];
76  input_map[(int)(i+7-offset)] = (double) boardB[i];
77  }
78 
79  return input_map;
80  }
81 
82  // Returns bool indicating whether player can go again
83  bool DoMove(move_t cell) {
84  emp_assert(cell < 6); // You cannot choose a cell out of bounds.
85 
86  side_t & cur_board = GetCurSide();
87  side_t & other_board = GetOtherSide();
88 
89  emp_assert(cur_board[cell] != 0); // You cannot choose an empty cell.
90 
91  size_t stone_count = cur_board[cell];
92  size_t cur_cell = cell;
93 
94  cur_board[cell] = 0;
95 
96  while (stone_count > 0) {
97  cur_cell = (cur_cell+1) % 13; // 6 pits on either side + 1 allowed home.
98  if (cur_cell < 7) cur_board[cur_cell]++;
99  else other_board[cur_cell-7]++;
100  stone_count--;
101  }
102 
103  // Go again if you ended in your store
104  if (cur_cell == 6) {
105  TestOver();
106  return true;
107  }
108 
109  // If you didn't end in your home, see if you captured!
110  // You must be on your side of the board...
111  // and the only cell in the last pit is the one you just put there.
112  if (cur_cell < 6 && cur_board[cur_cell] == 1) {
113  size_t clear_pos = 5 - cur_cell;
114  cur_board[6] += other_board[clear_pos];
115  other_board[clear_pos] = 0;
116  }
117 
118  is_A_turn = (size_t) !is_A_turn;
119  TestOver();
120  return false;
121  }
122 
123  // Setup a DoMove from either player's viewpoint.
124  bool DoMove(size_t player, move_t cell) {
125  emp_assert(player != is_A_turn); // Verify that we agree on player who goes next!
126  return DoMove(cell);
127  }
128 
129  void SetBoard(side_t a, side_t b) {
130  boardA = a;
131  boardB = b;
132  }
133 
134  bool IsDone() const { return over; }
135 
136  bool IsMoveValid(size_t move) const {
137  // Exclude never-valid moves or empty pits
138  if (move >= 6 || GetCurSide()[move] == 0) { return false; }
139  return true;
140  }
141 
142  // Provide all of the legal moves.
144  emp::vector<move_t> out_v;
145  for (size_t i = 0; i < 6; i++) {
146  if (GetCurSide()[i]) out_v.push_back(i);
147  }
148  return out_v;
149  }
150 
151  void PrintSmall(std::ostream & os=std::cout) {
152  os << " ";
153  for (size_t i = 5; i < 5; i--) {
154  os << boardB[i] << " ";
155  }
156  os << std::endl;
157  os << boardB[6] << " " << boardA[6] << std::endl;
158  os << " ";
159  for (size_t i = 0; i < 6; i++) {
160  os << boardA[i] << " ";
161  }
162  os << std::endl;
163  }
164 
165  void Print(std::ostream & os=std::cout) {
166  std::cout << "+---<<<---F-----E-----D-----C-----B-----A---<<<---+ Player B";
167  if (is_A_turn == false) std::cout << " ***";
168  std::cout << "\n"
169  << "| | \n"
170  << "| (" << std::setw(2) << boardB[5]
171  << " ) (" << std::setw(2) << boardB[4]
172  << " ) (" << std::setw(2) << boardB[3]
173  << " ) (" << std::setw(2) << boardB[2]
174  << " ) (" << std::setw(2) << boardB[1]
175  << " ) (" << std::setw(2) << boardB[0]
176  << " ) |\n";
177  std::cout << "v [" << std::setw(2) << boardB[6]
178  << " ] ["
179  << std::setw(2) << boardA[6] << " ] ^\n";
180  std::cout << "| (" << std::setw(2) << boardA[0]
181  << " ) (" << std::setw(2) << boardA[1]
182  << " ) (" << std::setw(2) << boardA[2]
183  << " ) (" << std::setw(2) << boardA[3]
184  << " ) (" << std::setw(2) << boardA[4]
185  << " ) (" << std::setw(2) << boardA[5]
186  << " ) |\n";
187  std::cout << "| |\n"
188  << "+--->>>---A-----B-----C-----D-----E-----F--->>>---+ Player A";
189  if (is_A_turn == true) std::cout << " ***";
190  std::cout << std::endl << std::endl;
191  }
192 
193  size_t GetCurPlayer() const { return !is_A_turn; }
194  bool IsTurnA() const { return is_A_turn; }
195  bool IsTurnB() const { return !is_A_turn; }
196 
197  size_t ScoreA() const {
198  size_t score = 0;
199  for (size_t i = 0; i < 7; i++) {
200  score += boardA[i];
201  }
202  return score;
203  }
204 
205  size_t ScoreB() const {
206  size_t score = 0;
207  for (size_t i = 0; i < 7; i++) {
208  score += boardB[i];
209  }
210  return score;
211  }
212 
213  double GetScore(size_t player) {
214  if (player == 0) return (double) ScoreA();
215  else if (player == 1) return (double) ScoreB();
216  emp_assert(false); // Only a two player game!
217  return 0.0;
218  }
219 
220  };
221 
222 }
223 
224 #endif
side_t & GetCurSide()
Definition: Mancala.h:68
size_t move_t
Definition: Mancala.h:45
bool IsMoveValid(size_t move) const
Definition: Mancala.h:136
const side_t & GetOtherSide() const
Definition: Mancala.h:65
bool IsDone() const
Definition: Mancala.h:134
std::unordered_map< int, double > AsInput(size_t player_id) const
Definition: Mancala.h:71
void Reset(bool A_first=true)
Definition: Mancala.h:52
void PrintSmall(std::ostream &os=std::cout)
Definition: Mancala.h:151
Definition: Mancala.h:23
void push_back(PB_Ts &&...args)
Definition: vector.h:189
emp::vector< move_t > GetMoveOptions()
Definition: Mancala.h:143
size_t ScoreB() const
Definition: Mancala.h:205
~Mancala()
Definition: Mancala.h:50
size_t GetCurPlayer() const
Definition: Mancala.h:193
const side_t & GetSideB() const
Definition: Mancala.h:63
const side_t & GetCurSide() const
Definition: Mancala.h:64
static const PrintStr endl("<br>")
Pre-define emp::endl to insert a "<br>" and thus acting like a newline.
size_t GetB(size_t i) const
Definition: Mancala.h:60
bool IsTurnB() const
Definition: Mancala.h:195
side_t & GetSideB()
Definition: Mancala.h:67
side_t & GetOtherSide()
Definition: Mancala.h:69
bool DoMove(move_t cell)
Definition: Mancala.h:83
If we are in emscripten, make sure to include the header.
Definition: array.h:37
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
size_t ScoreA() const
Definition: Mancala.h:197
void Print(std::ostream &os=std::cout)
Definition: Mancala.h:165
void SetBoard(side_t a, side_t b)
Definition: Mancala.h:129
size_t GetA(size_t i) const
Definition: Mancala.h:59
side_t & GetSideA()
Definition: Mancala.h:66
#define emp_assert(...)
Definition: assert.h:199
const side_t & GetSideA() const
Definition: Mancala.h:62
bool IsTurnA() const
Definition: Mancala.h:194
bool DoMove(size_t player, move_t cell)
Definition: Mancala.h:124
double GetScore(size_t player)
Definition: Mancala.h:213
Mancala(bool A_first=true)
Definition: Mancala.h:47