View Single Post
Old Dec 14th, 2005, 11:00 AM   #4
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 639
Rep Power: 4 Jessehk is on a distinguished road
Quote:
Originally Posted by UnKnown X
You should try making an expanded tic-tac-toe where the user decides how many rows and columns on which to play. Then you can't make the AI so specific. Makes for a nice challenge.
thanks, I'll keep that in mind for a challenge

Here is the second rough version.

The computer will now block you from winning.
Next I'd like to add a offensive function with a 50% chance of running (so the computer is still beatable)

anyway, here it is:

tic.h

//tic.h -- TicTacToe declarations

#ifndef TICTACTOE_H_
#define TICTACTOE_H_

class Board
{
	private:
		char *checkBoard(int);
	protected:
		static char board[3][3];
		char player;
		char otherPlayer;
	public:
		Board(char,char);
		void reset();
		virtual bool makeMove(int);
		bool checkWin();
		void show() const;
		virtual ~Board(); 
		bool checkCats() const;
};

class CBoard : public Board
{
	public:
		CBoard(char, char);
		virtual bool makeMove();
	private:
		int *checkDefence();
		void makeRandomMove();
//		int checkOffence();
};

#endif

tic.cpp

//tic.cpp -- implementation of class

#include <iostream>
#include "tic.h"

char Board::board[3][3];

Board::Board(char icon, char otherIcon)
{
	//std::cout << "constructor called" << std::endl;
	player = icon;
	otherPlayer = otherIcon;
}

void Board::reset() 
{
	for(int x = 0; x < 3; x++)
		for(int y = 0; y < 3; y++)
			Board::board[x][y] = ' ';
}


bool Board::makeMove(int space)
{
	//board setup is like that of numpad
	if(space < 1 || space > 9)
	{
		std::cout << "invalid range!" << std::endl;
		
		return false;
	}

	int x, y; //x-axis, y-axis
	x = y = 0;

	switch(space) {
		case 7:
			x = 0;
			y = 0;
			break;
		case 8:
			x = 1;
			y = 0;
			break;
		case 9:
			x = 2;
			y = 0;
			break;
		case 4:
			x = 0;
			y = 1;
			break;
		case 5:
			x = 1;
			y = 1;
			break;
		case 6:
			x = 2;
			y = 1;
			break;
		case 1:
			x = 0;
			y = 2;
			break;
		case 2:
			x = 1;
			y = 2;
			break;
		case 3:
			x = 2;
			y = 2;
			break;
	}
	
	if((Board::board[x][y] == otherPlayer) || (Board::board[x][y] == player)) //if space is taken...
		return false; //move failed. return false.
	else
	{
		Board::board[x][y] = player; //otherwise, make move

		return true; //return success
	}
}

char *Board::checkBoard(int part)
{
	//0, 1, 2 ==> cols
	//3, 4, 5 ==> rows
	//6, 7 ==> diagonals

	char *temp = new char[3];
	
	int space;
	
	switch(part)
	{
		//columns
		
		case 0:
		case 1:
		case 2:
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[part][a];
			break;
		//rows
		case 3:
			space = 0;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		case 4:
			space = 1;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		case 5:
			space = 2;
			for(int a = 0; a < 3; a++)
				temp[a] = Board::board[a][space];
			break;
		//diagonals
		case 6:
			temp[0] = Board::board[0][2];
			temp[1] = Board::board[1][1];
			temp[2] = Board::board[2][0];
			break;
		case 7:
			temp[0] = Board::board[0][0];
			//std::cout << "from checkBoard -- diagonal 2 " << Board::board[0][0] << std::endl;
			temp[1] = Board::board[1][1];
			//std::cout << "from checkBoard -- diagonal 2 " << Board::board[1][1] << std::endl;
			temp[2] = Board::board[2][2];
			//std::cout << "from checkBoard -- diagonal 2" << Board::board[2][2] << std::endl;
			break;
	}

	return temp;
}
		
bool Board::checkWin()
{
	int count = 0;
	bool winner = false;
	
	//checking columns
	for(int x = 0; x < 3; x++)
	{ //for each colums
		char *col = checkBoard(x);//get the column
		count = 0;
		for(int a = 0; a < 3; a++) //check each space in column
			if(*(col + a) == player) //if space is taken
				count++; //increase count

		if(count == 3)
		{		//if all three taken on column...
			winner = true; //set winner to true;
			//std::cout << "column winner" << std::endl;
		}
		delete [] col;
	}
	
	
	//checking rows
	
	for(int x = 3; x < 6; x++)
	{ //for each rows
		char *row = checkBoard(x);
		count = 0; //starting count again
		for(int a = 0; a < 3; a++)
			if(*(row + a) == player) //if space is taken
				count++; //increase count

		if(count == 3)
		{
			winner = true;
			//std::cout << "row winner" << std::endl;
		}
		
		delete [] row;
	}
	
	
	//checking diagonals
	count = 0;
	
	char *dia1 = checkBoard(6);
	
	//for(int a = 0; a < 3; a++)
	//	std::cout << "diagonal[" << a << "] = " << dia1[a] << std::endl;
	
	for(int x = 0; x < 3; x++)
	{
		if(*(dia1 + x) == player)
			count++;
	}
	
	if(count == 3)
	{	
		//std::cout << "diagonal 1 winner" << std::endl << std::endl;
		winner = true;
	}

	delete [] dia1;
	
	//second diagonal
	count = 0;
	char *dia2 = checkBoard(7);
	
	//for(int a = 0; a < 3; a++)
	//	std::cout << "diagonal[" << a << "] = " << dia2[a] << std::endl;
	
	for(int x = 0; x < 3; x++)
		if(*(dia2 + x) == player)
			count++;
	if(count == 3)
	{
		//std::cout << "diagonal 2 winner" << std::endl;
		winner = true;
	}
	
	delete [] dia2;

	return winner; //returns false if no win, true if winner
}

void Board::show() const
{
	std::cout << "---------";
	for(int a = 0; a < 3; a++)
	{
		std::cout << std::endl;
		std::cout << "|";
		for(int c = 0; c < 3; c++)
			std::cout << " " <<  Board::board[c][a];
		std::cout.put(' ');
		std::cout << "|";
	}
	std::cout << "\n---------" << std::endl;
}

bool Board::checkCats() const
{
	int taken = 0;
	
	for(int x = 0; x < 3; x++)
		for(int y = 0; y < 3; y++)
			if(Board::board[x][y] != ' ')
				taken++;
	
	/*if(taken == 9)
		std::cout << "return true" << std::endl;
	else
		std::cout << "return false" << std::endl;
	
	return (taken == 9);*/
	return taken == 9;
}

Board::~Board()
{
}

//CBoard method definitions

CBoard::CBoard(char icon, char otherIcon)
	: Board(icon, otherIcon) 
{
	player = icon;
	otherPlayer = otherIcon;
}

int *CBoard::checkDefence()
{
	//look for any spots where the human player will win
	
	//first look for rows
	
	int *spot = new int[3];
	bool found = false;
	int count = 0;
	
	for(int x = 0; x < 3; x++)
	{
		count = 0;
		for(int y = 0; y < 3; y++)
		{
			if(Board::board[x][y] == otherPlayer && Board::board[x][y] != player)
				count++;
			if(count == 2)
			{
				for(int c = 0; c < 3; c++)
				{
					if(Board::board[x][c] != otherPlayer && Board::board[x][c] != player)
					{	
						spot[0] = x;
						spot[1] = c;
						found = true;
					}
				} 

			}
		}
	}
	
	if(found)
		return spot;
	
	//then check for columns
	
	count = 0;
	
	for(int x = 0; x < 3; x++)
	{
		count = 0;
		for(int y = 0; y < 3; y++)
		{
			if(Board::board[y][x] == otherPlayer && Board::board[y][x] != player)
				count++;
			if(count == 2)
			{
				for(int c = 0; c < 3; c++)
				{
					if(Board::board[c][x] != otherPlayer && Board::board[c][x] != player)
					{
						spot[0] = c;
						spot[1] = x;
						found = true;
					}
				}
			}
		}
	}
	
	if(found) 
		return spot;
	
	//check diagonals
	
	count = 0;
	
	//first diagonal: lower left to upper right
	
	
	if(Board::board[0][2] == otherPlayer && Board::board[1][1] == otherPlayer 
		 && Board::board[2][0] != player)
	{
		spot[0] = 2; //2
		spot[1] = 0; //0
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	else if(Board::board[1][1] == otherPlayer && Board::board[2][0] == otherPlayer 
		&& Board::board[0][2] != player)
	{
		spot[0] = 0; //0
		spot[1] = 2; //2
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	else if(Board::board[0][2] == otherPlayer && Board::board[2][0] == otherPlayer
		&& Board::board[1][1] != player)
	{
		spot[0] = 1; //1
		spot[1] = 1; //1
 		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}

	if(found)
		return spot;
	
	
	//second diagonal
	
	if(Board::board[0][0] == otherPlayer && Board::board[1][1] == otherPlayer 
		  && Board::board[2][2] != player)
	{
		spot[0] = 2; //2
		spot[1] = 2; //2
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	
	else if(Board::board[1][1] == otherPlayer && Board::board[2][2] == otherPlayer 
		 && Board::board[0][0] != player)
	{
		spot[0] = 0; //0
		spot[1] = 0; //0
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	
	else if(Board::board[0][0] == otherPlayer && Board::board[2][2] == otherPlayer 
		 && Board::board[1][1] != player)
	{
		spot[0] = 1; //1
		spot[1] = 1; //1
		found = true;
		//std::cout << "diagonal should be blocked" << std::endl;
	}
	
	if(found)
		return spot;
		
	return NULL;
}
	
void CBoard::makeRandomMove()
{
	srand(time(0));
	
	while(1)
	{
		int move = rand() % 9 + 1;
		if(Board::makeMove(move)) //if move is good
			break;
		else
			continue; //otherwise, make another move
	}
}

bool CBoard::makeMove()
{
	int *spot = checkDefence();
	if(spot != NULL)
	{
		//std::cout << "spot[0] = " << spot[0] << std::endl;
		//std::cout << "spot[1] = " << spot[1] << std::endl;
		Board::board[spot[0]][spot[1]] = player;
	}
	
	else
	{
		srand(time(0));
		
		makeRandomMove();
	}
	
	delete [] spot;
	return true;
}

main.cpp

#include "tic.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
	srand(time(0));
		
	Board b1('x', 'o');
	CBoard b2('o', 'x');

	bool done = false;
	
	b2.reset();

	while(!done)
	{
		int move;
		while(1)
		{	
			cout << "Enter move: ";
			cin >> move;
			if(!b1.makeMove(move)) //bad move
				cout << "bad move" << endl;
			else
				break;
		}
		
		//cout << "out of first whiel loop" << endl;
		
		b1.show();
		if(b1.checkWin())
		{
			cout << "x wins!" << endl;
			done = true;
			continue;
		}
		
		if(b1.checkCats())
		{
			cout << "cat's game" << endl;
			done = true;
			continue;
		}
		
		//cout << "b2.makeMove()" << endl;
		b2.makeMove();
		b2.show();
		if(b2.checkWin())
		{
			cout << "o wins!" << endl;
			done = true;
			continue;
		}
		
		if(b2.checkCats())
		{
			cout << "cat's game" << endl;
			done = true;
			continue;
		}
	}
	
	return 0;
	
}
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote