Monday, March 14, 2011

Tic tac toe

For my second object oriented programming module. we were told to write an unbeatable tic tac toe playing machine.
(not exactly big blue or Watson, but fun nonetheless)

#include <iostream>
#include <string>
#include <vector>
using namespace std;

bool isWin(vector<vector<int> > board, int playerNum){

int size = board.size();

//check verticals
for(int row=0; row<size; row++){
bool win = 1;
for(int col=0, player=board[row][col]; col<size; col++){
if(player!=playerNum || player!=board[row][col]) {
win = 0;
break;
}
}
if(win==1) return 1;
}

//check horizontals
for(int col=0; col<size; col++){
bool win = 1;
for(int row=0, player=board[row][col]; row<size; row++){
if(player!=playerNum || player!=board[row][col]) {
win = 0;
break;
}
}
if(win==1) return 1;
}

//check forward diagonal
bool win = 1;
for(int diag=0, player=board[diag][diag]; diag<size; diag++){
if(player!=playerNum || player!=board[diag][diag]){
win=0;
break;
}
}
if(win==1) return 1;

//check backward diagonal
win =1;
for(int diag=0, player=board[diag][size-diag-1]; diag<size; diag++){
if(player!=playerNum || player!=board[diag][size-diag-1u]){
win=0;
break;
}
}
if(win==1) return 1;

return 0;
}

//print the gui
void printBoard(vector<vector<int> > board){
unsigned int size = board.size();
for(unsigned int row=0; row<size; row++){
for(unsigned int col=0; col<size; col++){
string mark = " ";
if(board[row][col]==1){
mark = "X";
}
else if (board[row][col]==2){
mark = "O";
}
cout << mark;
if(col==(size-1)) cout<<endl;
else cout<<" | ";
}
if(row!=size-1) cout << " ---------";
cout<<endl;
}
}

//generate a vector of possible board configurations
vector<vector<vector <int > > > getAllPossibleMoves(vector<vector<int > > board, unsigned int player){
vector<vector<vector <int > > > allPossibleMoves;
unsigned int size = board.size();
for(unsigned int row=0; row<size; row++){
for(unsigned int col=0; col<size; col++){
if(board[row][col] == 0){
board[row][col] = player;
allPossibleMoves.push_back(board);
board[row][col] = 0;
}
}
}
return allPossibleMoves;
}

//return 1 if board is full, otherwise 0
bool boardFull(vector<vector<int> > board){
unsigned int size = board.size();
for(unsigned int row=0; row<size; row++){
for(unsigned int col=0; col<size; col++){
if(board[row][col]==0) {return 0;}
}
}
return 1;
}

int nextBestMoveSub(vector<vector<int> > board, bool isNextMove){
if((isNextMove==1) && isWin(board,1) ){
return 2;
}
isNextMove = 0; //no longer the next move, have to play more moves
if(isWin(board,1)) return 1;//if this move wins return win
//return draw if board is full
if(boardFull(board))return 0;


vector<vector<vector<int> > > allOpponentsPossibleMoves = getAllPossibleMoves(board,2);
unsigned int opponentsMoves = allOpponentsPossibleMoves.size();

//check if opponent won, if he did, this move is sure lose.
for(unsigned int opponentMove=0; opponentMove<opponentsMoves; opponentMove++){
if(isWin(allOpponentsPossibleMoves[opponentMove],2)) return -1;
}

int outcome = 1;
//check if any of my future moves would result in a win.
for(unsigned int opponentMove=0; opponentMove<opponentsMoves; opponentMove++){
vector<vector<vector<int> > > allMyPossibleMoves = getAllPossibleMoves(allOpponentsPossibleMoves[opponentMove],1);
unsigned int myMoves = allMyPossibleMoves.size();

int myBest = -1;
//for each of my possible moves, check for the best possible outcome
for(unsigned int myMove=0; myMove<myMoves; myMove++){
int winLoseDraw = nextBestMoveSub(allMyPossibleMoves[myMove], isNextMove);
myBest = (winLoseDraw>=myBest)?winLoseDraw:myBest;
}

//for each of the opponents move, check for the worst possible outcome
outcome = (myBest<=outcome)?myBest:outcome;
}

return outcome;
}

vector<vector<int> > nextBestMove(vector<vector<int> > board){
vector<vector<int> > bestMove;
bool foundWin = 0;

vector<vector<vector<int> > > allMyPossibleMoves = getAllPossibleMoves(board,1);
unsigned int myMoves = allMyPossibleMoves.size();

//for each of my possible moves, check if it results in win, if so return win
for(unsigned int myMove=0; myMove<myMoves; myMove++){
int winLoseDraw = nextBestMoveSub(allMyPossibleMoves[myMove], 1);
if(winLoseDraw==2) return allMyPossibleMoves[myMove];//next move win, return it
if(winLoseDraw==1){
bestMove = allMyPossibleMoves[myMove];//sure win in unknown number of moves
foundWin = 1;
}
if(bestMove.size()==0) bestMove = allMyPossibleMoves[myMove];//not initialized, just take the move as default
if(!foundWin && winLoseDraw==0) bestMove = allMyPossibleMoves[myMove];//if winning move haven't been found, take draw
}
return bestMove;

}


void playGame(){
while(true){
//initialize the board
const unsigned int size = 3;
vector<vector<int> > board = vector<vector<int> >(size);
for(unsigned int i=0; i < size; i++){
board[i] = vector<int>(size);
}

//randomly choose a spot to move to

srand(time(NULL));
unsigned int firstMoveRow = rand()%size;
unsigned int firstMoveCol = rand()%size;

board[firstMoveRow][firstMoveCol]=1;

//print board
printBoard(board);

int outcome = 0;
//while board still has movable space
while(!boardFull(board)){

unsigned int row = 0;
unsigned int col = 0;

//ask user for input
while(true){
cout<<"please make a move by entering row and col numbers (eg: for the first square, 0 0)"<<endl;
cin>>row>>col;

if(cin.fail()||(row<0)||(row>=size)||(col<0)||(col>=size)){
cout<<"input error, please try again"<<endl;
cin.clear();
cin.ignore(1000, '\n');
continue;
}

//check if spot is taken
if(board[row][col]!=0){
cout<<"spot already taken, please try again"<<endl;
printBoard(board);
}else{
board[row][col]=2;
//print board
printBoard(board);
break;
}
}
if(isWin(board, 2)){
outcome = 2;
break;
}

//nextMove(board)
cout<<"my move"<<endl;
board = nextBestMove(board);

//print board
printBoard(board);

if(isWin(board,1)){
outcome = 1;
break;
}
}

vector<string> endGameMessage(3);
endGameMessage[0] = "We draw, you want to play again(y,n)?";
endGameMessage[1] = "I win!, you want to play again(y,n)?";
endGameMessage[2] = "You Win!!, this should never have happened, you want to play again(y,n)?";

cout<<endGameMessage[outcome]<<endl;
string playAgain = "n";
cin>>playAgain;
if(playAgain!="y") return;
}
}


int main (){
playGame();
//assignment1Question2();
//assignment1Question2();
//testIsTrivial();
//problem1();
return 0;
}

No comments:

Post a Comment