0

Simple tic tac toe game against CPU, however, I'm printing out the results of the AI part and its coming up with some really large numbers that aren't suppose to be there. After the computer's first move, it just crashes and goes into endless loop. Where did I go wrong that it causes this loop? AI section includes evalAllMoves, bestMove, and evalMove.

#include <iostream>
#include <string>
#include <ctime>
#include <Windows.h>
using namespace std;



class Board
{
private:
	char finalBoard[9];
	int board[9];
	int dupeBoard[9];
	int count;
public:
	Board();
	void getArray(char theArray[9]);
	void printBoard();
	bool checkMove(int col);
	void makeMove(char player, int col);
	void undoMove(int col);
	bool isFull();
	//bool isEmpty();//checks to see if board is empty which will dictate if computer is either 'X' or 'O'
	//void reset();
	bool hasWon(char player);
	void hostTournament();
	char temp;
};


/******************************************************************/

class Player
{
private:
	char player;
public:
	Player(char p);
	Player();
	char letter(Board b);
	int evalAllMoves(Board b);
	int evalMove(int col, Board b);
	int bestMove(int scores[]);
};


/********************************************************************/


/* Player()
 * Description: Initializes the player to be either 'X' or 'O'
 */

Player::Player()
{
	player = 'O'; //default second player
}


/* HumanPlayer(char player)
 * Description: Initializes the human player to user-specified value
 */
Player::Player(char p)
{
	player = p;
}

/* evalAllMoves()
 * Description: Prompt the computer player for a move and validate it
 * Arguments: The current Board class
 */
int Player::evalAllMoves(Board b)
{
	int move;
	int highScore = 0; 
	int scores[4];
	int bestCol = 0;

	for (int i = 0; i < 4; i++)
	{ 
		scores[i] = evalMove(i,b);
		cout<<scores[i]<<endl;
	}

	cout << " " << endl;
	 
	move = bestMove(scores);

	return move;
}

int Player::evalMove(int col, Board b)
{
	//check if I win
	if (player == 'O')
	{
		b.makeMove(player, col);
		if (b.hasWon(player))
			return 100;
		b.undoMove(col);

	//check if I lose
		b.makeMove('X', col);
		if (b.hasWon('X'))
			return 99;
		b.undoMove(col);
	}
	else
		return 50;
		
}

int Player::bestMove(int scores[])
{
	int highScore = 0;
	int bestCol = 0;

	for (int i = 0; i < 4; i++)
	{
		if(scores[i] > highScore)
		{
			highScore = scores[i];
			bestCol = i;
		}
	}
	cout << highScore << endl;
	cout << bestCol << endl;

	return bestCol;

}


/*****************************************************************************
 *  Human Player Class Declaration and Definitions
 ****************************************************************************/

class HumanPlayer
{
private:
	char player;  // 'X' or 'O'

public:
	HumanPlayer(char p);
	HumanPlayer();
	int evalAllMoves(Board b);
};

/*****************************************************************************
 *  HumanPlayer Function Definitions
 ****************************************************************************/

/* HumanPlayer()
 * Description: Initializes the human player to be 'X' by default
 */
HumanPlayer::HumanPlayer()
{
	player = 'X'; // default player
}


/* HumanPlayer(char player)
 * Description: Initializes the human player to user-specified value
 */
HumanPlayer::HumanPlayer(char p)
{
	player = p;
}

/* evalAllMoves()
 * Description: Prompt the human player for a move and validate it
 * Arguments: The current Board class
 */
int HumanPlayer::evalAllMoves(Board b)
{
	bool validMove = false;
	int move;
		
	cout << "Human player " 
		<< player
		<< ": What column to play next? [0-8]: ";
	cin >> move;
	validMove = b.checkMove(move);

	while(!validMove || cin.fail())
	{
		cin.clear();
		cin.ignore(INT_MAX, '\n');
		cout << "Sorry, THAT is not a valid move for the current board." << endl;
		cout << "Please enter a valid column to play next [0-8]: ";
		cin >> move;
		validMove = b.checkMove(move);
	}

	return move;
}


/*****************************************************************************
 *  Board Function Definitions
 ****************************************************************************/

/* Board()
 * Description: Initializes the connect 4 board to be empty (as denoted by 'e')
 */
Board::Board()
{
	// for every row and column pair fill in an 'e'
	board[0] = 0;
	board[1] = 1;
	board[2] = 2;
	board[3] = 3;
	board[4] = 4;
	board[5] = 5;
	board[6] = 6;
	board[7] = 7;
	board[8] = 8;
	finalBoard[0] = '0';
	finalBoard[1] = '1';
	finalBoard[2] = '2';
	finalBoard[3] = '3';
	finalBoard[4] = '4';
	finalBoard[5] = '5';
	finalBoard[6] = '6';
	finalBoard[7] = '7';
	finalBoard[8] = '8';
}


/* getArray
 * Description: Fill the parameter theArray with the values currently stored in the
 *              game board.  Must be 6 rows by 7 cols.
 */

void Board::getArray(char theArray[9])
{
	for(int x = 0; x < 9; x++)
		theArray[x] = finalBoard[x];
}

//Name: printBoard
	//Purpose: print out the array which is the the board
void Board::printBoard()
{
	//system("CLS");
	for(int y = 0; y < 9; y++)
	{
		if(board[y] == 3)
		{
			cout<< endl;
			cout<< "---------------\n";
		}
		if(board[y] == 6)
		{
			cout<< endl;
			cout<< "---------------\n";
		}
		cout<<"| " << finalBoard[y] << " |";
		
	}
}
/* checkMove()
 * Description: Tests to see if the proposed move is legal
 */
bool Board::checkMove(int col)
{
	// if outside of legal column values, return false
	if (col < 0 || col > 8)
		return false;
	if (finalBoard[col] == 'X' || finalBoard[col] == 'O')
		return false;
	// otherwise, it's ok
	return true;
}
/* makeMove()
 * Description: If the move is legal, updates the game board to reflect the
 *              move the player is making.
 */
void Board::makeMove(char player, int col)
{
	// Test for legality
	if (checkMove(col))
	{
	// Fill in player's move
		temp = finalBoard[col];
		finalBoard[col] = player;
		return;
	}
}
/* undoMove
 * Description: Removes the last token placed in the specified column
 */

void Board::undoMove(int col)
{
	if (finalBoard[col] != temp)
	{
		finalBoard[col] = temp;
		return;
	}
}


/* isFull()
 * Description: Tests to see if board is completely full by checking top of each column
 */
bool Board::isFull()
{
	bool full = true;
	// since fill from bottom (row 5), just test row 0 for each column
	if(count < 8)
		full = false;
	return full;
}



//Name: hasWon
	//Purpose: go through all possible combination of winning checks to see if there are any possible wins on the board, before moving on
	//         and asking next player for move.

bool Board::hasWon(char player)
{
	if(finalBoard[0] == player && finalBoard[1] == player && finalBoard[2] == player)
	{			
		return true;
	}
	else if(finalBoard[0] == player && finalBoard[4] == player && finalBoard[8] == player)
	{		
		return true;
	}
	else if(finalBoard[0] == player && finalBoard[3] == player && finalBoard[6] == player)
	{		
		return true;
	}
	else if(finalBoard[3] == player && finalBoard[4] == player && finalBoard[5] == player)
	{		
		return true;
	}
	else if(finalBoard[6] == player && finalBoard[7] == player && finalBoard[8] == player)		
	{
		return true;
	}
	else if(finalBoard[6] == player && finalBoard[4] == player && finalBoard[2] == player)
	{		
		return true;
	}
	else if(finalBoard[1] == player && finalBoard[4] == player && finalBoard[7] == player)
	{		
		return true;
	}
	else if(finalBoard[2] == player && finalBoard[5] == player && finalBoard[8] == player)
	{
		return true;
	}
	
	else	// else, hasn't won
		return false;
}



/* hostTournament
 * Description: hosts a games between Player and AI;
 */
void Board::hostTournament()
{
	cout<<"Welcome to Tic-Tac-Toe! \nLets Play! \n";
	cout<<"Player will be 'X', and Computer will be 'O'\n";
	// Create a human and computer player object
	HumanPlayer hpX('X');
	Player pO('O');
	count = 0;
	// initialize game board
	bool gameOver = false;
	int move = -1;
	// start the game: pauses added so user can watch game unfold
	printBoard();
	Sleep(500); // pause for 500 milliseconds (0.5 seconds)
	do
	{
		// Player X makes a move.
		do
		{
			move = hpX.evalAllMoves(*this); // human player
		} while(!checkMove(move));
		makeMove('X',move);
		printBoard();
		Sleep(500);
		// check to see if it was a winning move
		if (hasWon('X'))
		{
			cout << "Congratulations Player X, you have won!!\n\n";
			gameOver = true;
		}
		// check to see if move resulted in a stalemate
		else if (isFull())
		{
			cout << "A Stalemate, too bad!\n\n";
			gameOver = true;
		}
		else
		{
			// Player O makes a move
			do
			{
				move = pO.evalAllMoves(*this);
			}while(!checkMove(move));
			makeMove('O',move);
			printBoard();
			Sleep(500);
			// check to see if it was the winning move
			if (hasWon('O'))
			{
				cout << "Congratulations Player O, you have won!!\n\n";
				gameOver = true;
			}
			// check to see if move resulted in a statemate
			else if (isFull())
			{
				cout << "A Stalemate, too bad!\n\n";
				gameOver = true;
			}
		}		
		count = count + 1;
	// continue until either one player wins or the board fills up
	}while (!gameOver);
}


int main ()
{
	// in case anyone's using random numbers
	srand((unsigned)time(0));
	// create game board
	Board b;
	// start tournament
	b.hostTournament();
	system("PAUSE");
}

Edited by babyhuyx: n/a

2
Contributors
1
Reply
2
Views
5 Years
Discussion Span
Last Post by raptr_dflo
0

At line 100, you return a score without first undoing the move. So instead, try something like:

int score = -1;
if (b.hasWon(player))
    score = 100;
b.undoMove(col);
if (score >= 0)
    return score;

or just:

if (b.hasWon(player)) {
    b.undoMove(move);
    return 100;
}
else
    b.undoMove(move);

Then above, at line 81 of evalAllMoves(), why are you just checking the first 4 positions of the board, instead of all 9? And you presumably need to check whether a position has previously been occupied by either player, before attempting to play there.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.