Optimize Tic Tac Toe

Started by
13 comments, last by Zahlman 14 years ago
Today I finished my first game in console with AI - Tic Tac Toe, however to finish it I had to write bunch of code in AImove function. Can anyones suggest me what simple techniques to use to shorten this code(especially AImove function)? You don't have to write code what I need, just suggest me something, I need to think about this :) Here's the code:

#include<iostream>
#include<vector>

using namespace std;

const char O = 'O';
const char X = 'X';
const char E = ' ';

void humanMove(vector<char> &b);
void AImove(vector<char> &b);
void inits();
bool win(vector<char> &b, char m);
void drawBoard(vector<char> &b);
int main()
{
	vector <char> board(9,' ');
	inits();
	while(win(board,O) == false)
	{
		humanMove(board);
		drawBoard(board);
		win(board,X);
		AImove(board);
		drawBoard(board);
		win(board,O);
	}
}
void inits()
{
	cout <<"\t\tWelcome to ultimate Tic-Tac-Toe challenge!\n\n";
	cout <<"To do your turn follow these instructions:\n";
	cout <<" 0 || 1 || 2\n 3 || 4 || 5\n 6 || 7 || 8\n";
}
void humanMove(vector<char> &b)
{
	int move;
m:
	cout <<"Enter your move: ";
	cin >> move;
	cout <<"\n";
	//check if move is legal
	if(b[move] != O)
    b[move] = X;	
	else
	{
		cout <<"Move is\n illegal!\n"; goto m;
	}
}
void drawBoard(vector<char> &b)
{
	cout <<"\n\n";
	cout << " "<<b[0]<<"||"<<b[1]<<"||"<<b[2]<<"\n";
	cout <<"--------\n";
	cout << " "<<b[3]<<"||"<<b[4]<<"||"<<b[5]<<"\n";
	cout <<"--------\n";
	cout << " "<<b[6]<<"||"<<b[7]<<"||"<<b[8]<<"\n";
}
bool win(vector<char> &b, char m)
{
	//check for win
	if(b[0] == m && b[1] == m && b[2] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[3] == m && b[4] == m && b[5] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[6] == m && b[7] == m && b[8] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[0] == m && b[3] == m && b[6] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[1] == m && b[4] == m && b[7] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[2] == m && b[5] == m && b[8] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[2] == m && b[4] == m && b[6] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	else if(b[0] == m && b[4] == m && b[8] == m)
	{
		cout << m <<" wins!!!"; return true;
	}
	//chec for tie
	else if(b[0] !=E && b[1] !=E && b[2] !=E && b[3] !=E && b[4] !=E && b[5] !=E && b[6] !=E && b[7] !=E && b[8] !=E)
	{
		cout << " TIE!!!"; return true;
	}
	return false;
}
void AImove(vector<char> &b)
{
	//if can win in one turn
	//012
	if(b[0] == O && b[1] == O && b[2] == E){
		b[2] = O; return;}
	else if(b[0] == O && b[2] == O && b[1] == E){
		b[1] = O; return;}
	else if(b[2] == O && b[1] == O && b[0] == E){
		b[0] = O; return;}
	//345
	else if(b[3] == O && b[4] == O && b[5] == E){
		b[5] = O; return;}
	else if(b[3] == O && b[5] == O && b[4] == E){
		b[4] = O; return;}
	else if(b[5] == O && b[4] == O && b[3] == E){
		b[3] = O; return;}
	//678
	else if(b[6] == O && b[7] == O && b[8] == E){
		b[8] = O; return;}
	else if(b[6] == O && b[8] == O && b[7] == E){
		b[7] = O; return;}
	else if(b[8] == O && b[7] == O && b[6] == E){
		b[6] = O; return;}
	//036
	else if(b[0] == O && b[3] == O && b[6] == E){
		b[6] = O; return;}
	else if(b[0] == O && b[6] == O && b[3] == E){
		b[3] = O; return;}
	else if(b[3] == O && b[6] == O && b[0] == E){
		b[0] = O; return;}
	//147
	else if(b[0] == O && b[1] == O && b[2] == E){
		b[2] = O; return;}
	else if(b[0] == O && b[1] == O && b[2] == E){
		b[2] = O; return;}
	else if(b[0] == O && b[1] == O && b[2] == E){
		b[2] = O; return;}
	//258
	else if(b[2] == O && b[5] == O && b[8] == E){
		b[8] = O; return;}
	else if(b[2] == O && b[8] == O && b[5] == E){
		b[5] = O; return;}
	else if(b[8] == O && b[5] == O && b[2] == E){
		b[2] = O; return;}
	//246
	else if(b[4] == O && b[6] == O && b[2] == E){
		b[2] = O; return;}
	else if(b[2] == O && b[4] == O && b[6] == E){
		b[6] = O; return;}
	else if(b[6] == O && b[2] == O && b[4] == E){
		b[4] = O; return;}
	//048
	else if(b[0] == O && b[4] == O && b[8] == E){
		b[8] = O; return;}
	else if(b[0] == O && b[8] == O && b[4] == E){
		b[4] = O; return;}
	else if(b[8] == O && b[4] == O && b[0] == E){
		b[0] = O; return;}
	//if human can win in one turn
	//012
	if(b[0] == X && b[1] == X && b[2] == E){
		b[2] = O; return;}
	else if(b[0] == X && b[2] == X && b[1] == E){
		b[1] = O; return;}
	else if(b[2] == X && b[1] == X && b[0] == E){
		b[0] = O; return;}
	//345
	else if(b[3] == X && b[4] == X && b[5] == E){
		b[5] = O; return;}
	else if(b[3] == X && b[5] == X && b[4] == E){
		b[4] = O; return;}
	else if(b[5] == X && b[4] == X && b[3] == E){
		b[3] = O; return;}
	//678
	else if(b[6] == X && b[7] == X && b[8] == E){
		b[8] = O; return;}
	else if(b[6] == X && b[8] == X && b[7] == E){
		b[7] = O; return;}
	else if(b[8] == X && b[7] == X && b[6] == E){
		b[6] = O; return;}
	//036
	else if(b[0] == X && b[3] == X && b[6] == E){
		b[6] = O; return;}
	else if(b[0] == X && b[6] == X && b[3] == E){
		b[3] = O; return;}
	else if(b[3] == X && b[6] == X && b[0] == E){
		b[0] = O; return;}
	//147
	else if(b[0] == X && b[1] == X && b[2] == E){
		b[2] = O; return;}
	else if(b[0] == X && b[1] == X && b[2] == E){
		b[2] = O; return;}
	else if(b[0] == X && b[1] == X && b[2] == E){
		b[2] = O; return;}
	//258
	else if(b[2] == X && b[5] == X && b[8] == E){
		b[8] = O; return;}
	else if(b[2] == X && b[8] == X && b[5] == E){
		b[5] = O; return;}
	else if(b[8] == X && b[5] == X && b[2] == E){
		b[2] = O; return;}
	//246
	else if(b[4] == X && b[6] == X && b[2] == E){
		b[2] = O; return;}
	else if(b[2] == X && b[4] == X && b[6] == E){
		b[6] = O; return;}
	else if(b[6] == X && b[2] == X && b[4] == E){
		b[4] = O; return;}
	//048
	else if(b[0] == X && b[4] == X && b[8] == E){
		b[8] = O; return;}
	else if(b[0] == X && b[8] == X && b[4] == E){
		b[4] = O; return;}
	else if(b[8] == X && b[4] == X && b[0] == E){
		b[0] = O; return;}
	//other turns
	else if(b[4] == E){
		b[4] = O; return;}
	else if(b[0] == E){
		b[0] = O; return;}
	else if(b[2] == E){
		b[2] = O; return;}
	else if(b[6] == E){
		b[6] = O; return;}
	else if(b[8] == E){
		b[8] = O; return;}
	else if(b[1] == E){
		b[1] = O; return;}
	else if(b[3] == E){
		b[3] = O; return;}
	else if(b[5] == E){
		b[5] = O; return;}
	else if(b[7] == E){
		b[7] = O; return;}
}

Deltron Zero and Automator.

Advertisement
The win function has a lot of code duplication. Here is a first attempt to make it shorter:

#include <algorithm>bool win(vector<char> &b, char m){    static int lines[][3] = {        {0, 1, 2}, {3, 4, 5}, {6, 7, 8},        {0, 3, 6}, {1, 4, 7}, {2, 5, 8},        {0, 4, 8}, {2, 4, 6}    };    for (int i = 0; i < 8; ++i)    {        if (b[lines[0]] == m         && b[lines[1]] == m         && b[lines[2]] == m)        {            cout << m << " wins!!!";            return true;        }    }    if (std::count(b.begin(), b.end(), E) == 0)    {        cout << " TIE!!!";        return true;    }    return false;}


By the way, the human player shouldn't be able to make the same move twice ;)
Oh, count is new algorithm for me, thanks :)

Deltron Zero and Automator.

And here is a more "STL-oriented" approach:

#include <algorithm>class line_finder{    vector<char>& b;    char m;public:    line_finder(vector<char>& b, char m) : b(b), m(m) {}    bool operator()(int* line)    {        return b[line[0]] == m            && b[line[1]] == m            && b[line[2]] == m;    }};bool win(vector<char> &b, char m){    static int lines[][3] = {        {0, 1, 2}, {3, 4, 5}, {6, 7, 8},        {0, 3, 6}, {1, 4, 7}, {2, 5, 8},        {0, 4, 8}, {2, 4, 6}    };    if (std::find_if(lines, lines + 8, line_finder(b, m)) != lines + 8)    {        cout << m << " wins!!!";        return true;    }    if (std::count(b.begin(), b.end(), E) == 0)    {        cout << " TIE!!!";        return true;    }    return false;}


Sooner or later, Zahlman will jump in and tell you about const correctness ;)
DevFred, why lines array is static?

Deltron Zero and Automator.

I don't want it to be initialized every time the win function is entered. I could have made it a global variable, but then every other function would unnecessarily have access to it.
find_if is also algorithm?

Deltron Zero and Automator.

Yes.
I will shorten AImove function with count algorithm too, thanks for help :)

Deltron Zero and Automator.

ok, now AImove function is way shorter :)

void AImove(vector<char> &b){	static int lines[][3] = {        {0, 1, 2}, {3, 4, 5}, {6, 7, 8},        {0, 3, 6}, {1, 4, 7}, {2, 5, 8},        {0, 4, 8}, {2, 4, 6}    };    //if AI can win in one turn    for (int i = 0; i < 8; ++i)    {        if (b[lines[0]] == O         && b[lines[1]] == O         && b[lines[2]] == E)		{			b[lines[2]] = O; return;		}		else if(b[lines[0]] == E         && b[lines[1]] == O         && b[lines[2]] == O)		{			b[lines[0]] = O; return;		}		else if(b[lines[0]] == O         && b[lines[1]] == E         && b[lines[2]] == O)		{			b[lines[1]] = O; return;		}	}	//if human can win in one turn	for (int i = 0; i < 8; ++i)    {        if (b[lines[0]] == X         && b[lines[1]] == X         && b[lines[2]] == E)		{			b[lines[2]] = O; return;		}		else if(b[lines[0]] == E         && b[lines[1]] == X         && b[lines[2]] == X)		{			b[lines[0]] = O; return;		}		else if(b[lines[0]] == X         && b[lines[1]] == E         && b[lines[2]] == X)		{			b[lines[1]] = O; return;		}	}	//other turns	if(b[4] == E){		b[4] = O; return;}	else if(b[0] == E){		b[0] = O; return;}	else if(b[2] == E){		b[2] = O; return;}	else if(b[6] == E){		b[6] = O; return;}	else if(b[8] == E){		b[8] = O; return;}	else if(b[1] == E){		b[1] = O; return;}	else if(b[3] == E){		b[3] = O; return;}	else if(b[5] == E){		b[5] = O; return;}	else if(b[7] == E){		b[7] = O; return;}}

Deltron Zero and Automator.

This topic is closed to new replies.

Advertisement