// Original problem statement @ http://nabetani.sakura.ne.jp/hena/1/
// Input is game steps for tic tac toe
// o takes the first move. Moves keep alternating between o and x then onwards
// If o or x makes a line of 3 in any direction, it is declared as won
// It o or x makes a move over already marked block, it is declared as foul
// and opponent is declared as winner
// Input is never broken. So you don't need to handle the exception case.
// 1 | 2 | 3
// --+---+--
// 4 | 5 | 6 <--------- Board layout
// --+---+--
// 7 | 8 | 9
#include <iostream>
#include <cctype>
#include <cassert>
using namespace std;
class CTicTacToe {
static const signed char BAD_INPUT_ = 'B';
static const signed char CONTINUE_ = 'C';
static const signed char DRAW_GAME_ = 'D';
public:
CTicTacToe()
: firstMover('o')
, curMover('o') //curMover(firstMover)
, status(CONTINUE_)
, nMoves(0) {
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
board[i][j] = '.';
}
bool isRemaining() const { return getStatus() == CONTINUE_; }
signed char getStatus() const { return status; }
void playNext(signed char move);
private:
void play(int r, int c);
signed char flipMover(signed char c) const { return 'x' - c + 'o'; }
bool isCurWinning() const;
bool hasWon() const;
private:
// Why char? Because it is easy to debug
// Tic tac toe is NOT a complex game in terms of space and computation
// requirement.
// Why explicitly signed? To make flipMover work.
signed char firstMover;
signed char curMover;
signed char board[3][3];
signed char status;
int nMoves;
};
void CTicTacToe::playNext(signed char move) {
assert(nMoves < 9); // Bad input case
assert(status == CONTINUE_); // Current status of game
if( '1' <= move && move <= '9') {
const int n = move - '1';
const int r = n / 3;
const int c = n % 3;
if( board[r][c] == '.' ) {
play(r, c);
} else {
status = toupper( flipMover( curMover ) );
}
} else {
status = BAD_INPUT_;
}
}
void CTicTacToe::play(int r, int c) {
if(nMoves++ < 4) {
board[r][c] = curMover;
} else {
board[r][c] = curMover;
const bool curWon = hasWon();
if(curWon) {
status = curMover;
} else if(9 == nMoves) {
status = DRAW_GAME_;
}
}
curMover = flipMover( curMover );
}
//
//bool CTicTacToe::isCurWinning() const {
// for(int i = 0; i < 3; ++i) {
// int nC = 0, nD = 0;
// for(int j = 0; j < 3; ++j) { // Check row#i
// if(board[i][j] == '.') ++nD;
// if(board[i][j] == curMover) ++nC;
// }
// if(2 == nC && 1 == nD) return true;
//
// nC = 0, nD = 0;
// for(int j = 0; j < 3; ++j) { // Check col#i
// if(board[j][i] == '.') ++nD;
// if(board[j][i] == curMover) ++nC;
// }
// if(2 == nC && 1 == nD) return true;
// }
//
// int nC = 0, nD = 0;
// for(int j = 0; j < 3; ++j) { // Check Digonal
// if(board[j][j] == '.') ++nD;
// if(board[j][j] == curMover) ++nC;
// }
// if(2 == nC && 1 == nD) return true;
// nC = 0, nD = 0;
// for(int j = 0; j < 3; ++j) { // Check Digonal2
// if(board[j][2-j] == '.') ++nD;
// if(board[j][2-j] == curMover) ++nC;
// }
// if(2 == nC && 1 == nD) return true;
// return false;
//}
bool CTicTacToe::hasWon() const {
for(int i = 0; i < 3; ++i) {
int nC = 0;
for(int j = 0; j < 3; ++j) { // Check row#i
if(board[i][j] == curMover) ++nC;
}
if(3 == nC) return true;
nC = 0;
for(int j = 0; j < 3; ++j) { // Check col#i
if(board[j][i] == curMover) ++nC;
}
if(3 == nC) return true;
}
int nC = 0;
for(int j = 0; j < 3; ++j) { // Check Digonal
if(board[j][j] == curMover) ++nC;
}
if(3 == nC) return true;
nC = 0;
for(int j = 0; j < 3; ++j) { // Check Digonal2
if(board[j][2-j] == curMover) ++nC;
}
if(3 == nC) return true;
return false;
}
void play(const char *moves) {
CTicTacToe game;
int index = 0;
do {
//cerr << "Sending move " << moves[index] << endl;
game.playNext( moves[index++] );
} while( game.isRemaining() );
cout << "Input: " << moves << endl;
switch ( game.getStatus() ) {
case 'O':
case 'X':
cout << "Foul : ";
/* Fall-through */
case 'o':
case 'x':
cout << static_cast<char>( tolower( game.getStatus() ) )
<< " won." << endl;
break;
case 'D':
cout << "Draw game." << endl;
break;
default:
cerr << "DEBUG:: " << game.getStatus() << endl;
cout << "Broken input" << endl;
break;
}
cout << endl;
}
int main(int argc, char *const *argv) {
for(int i = 1; i < argc; ++i) {
play(argv[i]);
}
if(argc < 2) {
cout << "Expecting:: x won." << endl;
play("79538246");
cout << "Expecting:: x won." << endl;
play("35497162193");
cout << "Expecting:: x won." << endl;
play("61978543");
cout << "Expecting:: x won." << endl;
play("254961323121");
cout << "Expecting:: x won." << endl;
play("6134278187");
cout << "-------------------------------------------------" << endl;
cout << "Expecting:: Foul : x won." << endl;
play("4319581");
cout << "Expecting:: Foul : x won." << endl;
play("9625663381");
cout << "Expecting:: Foul : x won." << endl;
play("7975662");
cout << "Expecting:: Foul : x won." << endl;
play("2368799597");
cout << "Expecting:: Foul : x won." << endl;
play("18652368566");
cout << "-------------------------------------------------" << endl;
cout << "Expecting:: o won." << endl;
play("965715");
cout << "Expecting:: o won." << endl;
play("38745796");
cout << "Expecting:: o won." << endl;
play("371929");
cout << "Expecting:: o won." << endl;
play("758698769");
cout << "Expecting:: o won." << endl;
play("42683953");
cout << "-------------------------------------------------" << endl;
cout << "Expecting:: Foul : o won." << endl;
play("618843927");
cout << "Expecting:: Foul : o won." << endl;
play("36535224");
cout << "Expecting:: Foul : o won." << endl;
play("882973");
cout << "Expecting:: Foul : o won." << endl;
play("653675681");
cout << "Expecting:: Foul : o won." << endl;
play("9729934662");
cout << "-------------------------------------------------" << endl;
cout << "Expecting:: Draw Game." << endl;
play("972651483927");
cout << "Expecting:: Draw Game." << endl;
play("5439126787");
cout << "Expecting:: Draw Game." << endl;
play("142583697");
cout << "Expecting:: Draw Game." << endl;
play("42198637563");
cout << "Expecting:: Draw Game." << endl;
play("657391482");
}
return 0;
}
// EOF