1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
|
#include <iostream>
#include <assert.h>
#include <cstddef>
#include <string>
#include <vector>
#include <sstream>
#include <deque>
using namespace std;
// A board struct for the game tic-tac-toe
struct BoardXO
{
int8_t state[9]; //where player markers are on the board (player can be -1 or 1; 0 for unoccupied)
uint8_t moves[9]; //sequence of moves that led to current game state (i.e., which marker position players selected)
int8_t turn[9]; //which player made the corresponding move (either -1, 1, etc., or, -1, 1, etc.)
uint8_t numMoves; //total number of moves that have been made in the game to this point
BoardXO()
{
for (int i=0; i<9; i++)
{
state[i] = 0;
}
numMoves = 0;
}
const int8_t& operator[](std::uint8_t idx) const
{
if (idx<0 || idx > 8)
{
throw std::range_error("Error: Subscript out of bounds.");
}
return state[idx];
}
};
class XO
{
private:
BoardXO b; //a board that stores the current state of the game
bool gameOver(const BoardXO& brd); //1 draw or game won, 0 available moves
int8_t winner(const BoardXO& brd); //-1 for player -1 or 1 for player 1 or 0 for no winner (draw)
bool makeMove(const int8_t& play, const uint8_t& pos, BoardXO& brd);
public:
XO();
XO(const int8_t* play, const uint8_t* pos, const uint8_t& n);
void show();
bool makeMove(const int8_t& play, const uint8_t& pos); //place player marker play (-1 or 1) at position pos; increment number of moves counter (numMoves)
bool makeMoves(const int8_t* play, const uint8_t* pos, const uint8_t& n);
bool makeOptimalMove(); // pre-condition: board has one marker set (i.e., one player has placed a marker); post condition: game state updated to reflect optimal move for active player
BoardXO getBoard(); //return current board (this is mainly for testing/grading)
bool gameOver(); //1 draw or game won, 0 available moves
int8_t winner(); //-1 for player -1 or 1 for player 1 or 0 for no winner (draw)
};
XO::XO() {}
/* create game where moves have already been played. For example, a game could be initialized using XO({-1,1,-1,1,-1,1}, {2,0,3,7,6,8}, 6)*/
XO::XO(const int8_t* play, const uint8_t* pos, const uint8_t& n){} // moves won't be invalid for codeabbey.
//place player marker play (-1 or 1) at position pos; increment number of moves counter (b.numMoves)
bool XO::makeMove(const int8_t& play, const uint8_t& pos, BoardXO& brd)
{ //moves made will not be invalid for this problem.
brd.state[(int)pos] = play;
brd.moves[(int)brd.numMoves] = pos;
brd.turn[(int)brd.numMoves] = play;
brd.numMoves = brd.numMoves + 1;
return true;
}
bool XO::makeMove(const int8_t& play, const uint8_t& pos){ return makeMove(play, pos, b);}
bool XO::makeMoves(const int8_t* play, const uint8_t* pos, const uint8_t& n)
{
if ((int)n< 0 || (int)n > 9)
{
std::cout<<"At move " << (int)n << " Tried to make more moves that would breach legal amount"<<std::endl;
return false;
}
for (int i=0; i<(int)n; i++)
{
if(!makeMove(*(play+i), *(pos+i)))
{
return false;
}
}
return true;
}
// pre-condition: board has one marker set (i.e., one player has placed a marker); post condition: game state updated to reflect optimal move for active player
/* blah blah blah. */
bool XO::makeOptimalMove()
{
if(gameOver())
{
return false;
}
deque<BoardXO> q;
q.push_back(b);
int scores[9] = {-10,-10,-10,-10,-10,-10,-10,-10,-10};
for (int i=0 ; i<9; i++)
{
if((int)b[i]==0)
{
scores[i]= 1;
}
}
while (!q.empty())
{
BoardXO c = q.front();
q.pop_front();
int nextPlay = 0;
if((int)c.turn[(int)c.numMoves - 1] == 1)
{
nextPlay = -1;
}
else
{
nextPlay = 1;
}
if (!gameOver(c))
{
for (int i=0 ; i<9; i++)
{
BoardXO temp = c;
if ((int)c.state[i] == 0)
{
assert(makeMove((int8_t)nextPlay, (uint8_t)i, temp));
q.push_back(temp);
}
}
}
else
{
int initmove = (int)c.moves[(int)b.numMoves];
int8_t whichPlay = c.turn[(int)b.numMoves];
if (winner(c) == whichPlay)
{
int newscore = 10 - c.numMoves;
if(scores[initmove]> 0 && newscore > scores[initmove])
{
scores[initmove] = newscore;
}
}
else if ((int)winner(c) == 0)
{
if (scores[initmove]>0)
{
scores[initmove] = 0;
}
}
else
{
int newscore = c.numMoves - 10;
if(newscore<scores[initmove])
{
scores[initmove] = newscore;
}
}
}
}
int nextPlay = (int)b.turn[(int)b.numMoves-1]*-1;
int maxscore = -11;
int index = 0;
for (int i=0; i<9; i++)
{
if(scores[i] > maxscore && (int)b.state[i] == 0)
{
maxscore = scores[i];
index = i;
}
}
makeMove((int8_t)nextPlay, (uint8_t)index);
return true;
}
BoardXO XO::getBoard(){ return b; }
bool XO::gameOver(const BoardXO& brd)
{
if (brd.numMoves == 9)
{ return true;}
if (brd[0]!= 0)
{
if (brd[0] == brd[1] && brd[1] == brd[2])
return true;
if( brd[0] == brd[3] && brd[3] == brd[6])
return true;
if( brd[0] == brd[4] && brd[4] == brd[8])
return true;
}
if (brd[3]!= 0 && brd[3] == brd[4] && brd[4] == brd[5])
{
return true;
}
if (brd[6]!= 0 && brd[6] == brd[7] && brd[7] == brd[8])
{
return true;
}
if (brd[2]!= 0)
{
if (brd[2] == brd[4] && brd[4] == brd[6])
return true;
if(brd[2]== brd[5] && brd[5]==brd[8])
return true;
}
if (brd[1]!=0 && brd[1]== brd[4] && brd[4]==brd[7])
{
return true;
}
return false;
} //1 draw or game won, 0 available moves
int8_t XO::winner(const BoardXO& brd)
{
if (brd[0]!= 0)
{
if (brd[0] == brd[1] && brd[1] == brd[2])
return brd[0];
if( brd[0] == brd[3] && brd[3] == brd[6])
return brd[0];
if( brd[0] == brd[4] && brd[4] == brd[8])
return brd[0];
}
if (brd[3]!= 0 && brd[3] == brd[4] && brd[4] == brd[5])
{
return brd[3];
}
if (brd[6]!= 0 && brd[6] == brd[7] && brd[7] == brd[8])
{
return brd[6];
}
if (brd[2]!= 0)
{
if (brd[2] == brd[4] && brd[4] == brd[6])
return brd[2];
if(brd[2]== brd[5] && brd[5]==brd[8])
return brd[2];
}
if (brd[1]!=0 && brd[1]== brd[4] && brd[4]==brd[7])
{
return brd[1];
}
return 0;
} //-1 for player -1, or 1 for player 1, or 0 for no winner (draw)
bool XO::gameOver(){ return gameOver(b); }
int8_t XO::winner(){ return winner(b);}
|