View Single Post
Old Dec 9th, 2005, 10:42 PM   #1
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 648
Rep Power: 4 Jessehk is on a distinguished road
Tic Tac Toe progress

I don't know what happened to the Tic Toe contest (I guess there was not enough interest) but I though I would try working on a Tic Tac Toe game. It currently uses text, but after getting enough experience with Qt, I'd like to try to implement it with a GUI.

It also only uses a random position for the AI, because I haven't developed the AI makeMove() function yet.

Keep in mind, this is the equivalent of a rough draft. I'm sure there are hundreds of improvements.
tic.h

//tic.h -- TicTacToe declarations

#ifndef TICTACTOE_H_
#define TICTACTOE_H_

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

/*class CBoard : public Board { //TODO
	public:
		CBoard(char);
		virtual bool makeMove(int);
};*/

#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::set() {
	//std::cout << "set() called" << std::endl;
	if(boardSet == false) {
		//std::cout << "Board being set..." << std::endl;
		for(int x = 0; x < 3; x++)
			for(int y = 0; y < 3; y++)
				Board::board[x][y] = ' ';
	}

	else {
		std::cout << "board previously set" << std::endl;
		std::cout << "use reset() to reset game" << std::endl;
	}

	boardSet = true;
}*/

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

	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 arr[3];
	char *temp = arr;
	
	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];
			temp[1] = Board::board[1][1];
			temp[2] = Board::board[2][2];
	}

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

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

		if(count == 3)
			winner = true;
	}
	
	//checking diagonals
	count = 0;
	
	char *dia1 = checkBoard(6);
	for(int x = 0; x < 3; x++) {
		if(*(dia1 + x) == player)
			count++;
	}
	if(count == 3)
		winner = true;

	//second diagonal
	count = 0;
	char *dia2 = checkBoard(7);
	for(int x = 0; x < 3; x++)
		if(*(dia2 + x) == player)
			count++;
	if(count == 3)
		winner = true;

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

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

Board::~Board() {
}

main.cpp

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

using namespace std;

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

	bool done = false;

	int move;
	while(!done) {
		b1.reset();
		while(1) {
			cout << "Enter space with numpad: ";
			cin >> move;
			
			if(!b1.makeMove(move)) {
				cout << "bad move" << endl;
				continue;
			}

			b1.show();
			
			if(b1.checkWin()) {
				cout << "x wins!" << endl;
				done = true;
				break;
			}

			move = rand() % 8 + 1;
			while(1) {
				if(!b2.makeMove(move)) {
					continue;
				}
				else
					break;
			}

			if(b2.checkWin()) {
				cout << "o wins!" << endl;
				done = true;
				break;
			}
			
			b1.show();
			
		}
	}	
	cout << "Done!" << endl;
	
	return 0;
}


EDIT:fixed a large bug

EDIT2: I realize that it sometimes lags becuase the random moves keep getting rejected. This problem will disappear once I have written a good AI
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!

Last edited by Jessehk; Dec 9th, 2005 at 11:07 PM.
Jessehk is offline   Reply With Quote