Tic Tac Toe Source code

// main.cpp
// The main source file of the Tic Tac Toe game
// (C) Copyright 2003 Brendan Madden

#include <windows.h> // for colours
#include <iostream.h> // for output and most other code
#include <stdio.h>
#include <time.h>

// functions
bool SetTextColour(int red, int green, int blue)
{
// This function is a sort of RGB thing.
// Enter either 0, 1, or 2 for each entry.
// 0 means none of the colour will be used.
// 1 means a light version of the colour will
// be used and 2 means a dark version will be
// used.  The colour combinations will be added
// and result in different colours.  For example:
// Setting the red value to 1 and the green and
// blue values to 0 will result in the colour
// being red.  Setting the red value to 2 and the
// blue value to 2 will create a dark purple.
// Setting all values to 1 will result in grey,
// setting all values to 0 will result in
// black.  Setting all values to 2 will result in white.
// NOTE: Only 2 colours may be used in a
// combination.  For example, red, green, and blue
// cannot all be used in a single combination.

// To get around the failing when using 3 colours, we'll set
// it to black, white, or grey first and return true so that
// we can use those colours

HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);

WORD F_RED = FOREGROUND_RED | FOREGROUND_INTENSITY;
WORD F_GREEN = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
WORD F_BLUE = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
WORD F_D_RED = FOREGROUND_RED;
WORD F_D_GREEN = FOREGROUND_GREEN;
WORD F_D_BLUE = FOREGROUND_BLUE;
WORD F_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
WORD F_GREY = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;

// black and grey and white
if (red == 0 && green == 0 && blue == 0)
{
SetConsoleTextAttribute(stdOut, 0);
return true;
}
if (red == 1 && green == 1 && blue == 1)
{
SetConsoleTextAttribute(stdOut, F_GREY);
return true;
}
if (red == 2 && green == 2 && blue == 2)
{
SetConsoleTextAttribute(stdOut, F_WHITE);
return true;
}

// Check to make sure only 2 colours used
// (Exceptions are if all colours equal 1, then it will set the text to white
// If all colours are set to 0, the text will be black)
if (red != 0 && green != 0 && blue != 0)
return false; // Fail

// Red basic combinations
if (red == 1 && green == 0 && blue == 0)
SetConsoleTextAttribute(stdOut, F_RED);
if (red == 2 && green == 0 && blue == 0)
SetConsoleTextAttribute(stdOut, F_D_RED);

// Green basic combinations
if (red == 0 && green == 1 && blue == 0)
SetConsoleTextAttribute(stdOut, F_GREEN);
if (red == 0 && green == 2 && blue == 0)
SetConsoleTextAttribute(stdOut, F_D_GREEN);

// Blue basic combinations
if (red == 0 && green == 0 && blue == 1)
SetConsoleTextAttribute(stdOut,  F_BLUE);
if (red == 0 && green == 0 && blue == 2)
SetConsoleTextAttribute(stdOut,  F_D_BLUE);

// More complicated combinations
if (red == 1 && green == 1 && blue == 0)
SetConsoleTextAttribute(stdOut, F_RED | F_GREEN); // yellow
if (red == 1 && green == 2 && blue == 0)
SetConsoleTextAttribute(stdOut, F_RED | F_GREEN); // yellow
if (red == 2 && green == 1 && blue == 0)
SetConsoleTextAttribute(stdOut, F_RED | F_GREEN); // yellow
if (red == 2 && green == 2 && blue == 0)
SetConsoleTextAttribute(stdOut, F_D_RED | F_D_GREEN); // dark yellow
if (red == 1 && green == 0 && blue == 1)
SetConsoleTextAttribute(stdOut, F_RED | F_BLUE); // light purple
if (red == 2 && green == 0 && blue == 1)
SetConsoleTextAttribute(stdOut,  F_RED | F_BLUE); // light purple
if (red == 1 && green == 0 && blue == 2)
SetConsoleTextAttribute(stdOut, F_RED | F_BLUE); // light purple
if (red == 2 && green == 0 && blue == 2)
SetConsoleTextAttribute(stdOut, F_D_RED | F_D_BLUE); // dark purple
if (red == 0 && green == 1 && blue == 1)
SetConsoleTextAttribute(stdOut, F_GREEN | F_BLUE); // light turquoise
if (red == 0 && green == 2 && blue == 1)
SetConsoleTextAttribute(stdOut, F_GREEN | F_BLUE); // light turquoise
if (red == 0 && green == 1 && blue == 2)
SetConsoleTextAttribute(stdOut, F_GREEN | F_BLUE); // light turquoise
if (red == 0 && green == 2 && blue == 2)
SetConsoleTextAttribute(stdOut, F_D_GREEN | F_D_BLUE); // dark turquoise

return true;
}

// the game board
int board[3][3];

// Display the board
void Board()
{
char blank = ' ';
char x = 'X';
char o = 'O';

SetTextColour(0,1,1);
printf("   1   2   3\n");
SetTextColour(1,1,1);

for (int i=0; i<3; i++)
{
SetTextColour(1,1,0);
printf("%i",i+1);
SetTextColour(1,1,1);
printf("|");
for (int j=0; j<3; j++)
{
switch(board[j][i])
{
case 0:
printf(" ");
printf("%c",blank);
printf(" |");
break;
case 1:
printf(" ");
SetTextColour(2,2,2);
printf("%c",x);
SetTextColour(1,1,1);
printf(" |");
break;
case 2:
printf(" ");
SetTextColour(1,0,0);
printf("%c",o);
SetTextColour(1,1,1);
printf(" |");
break;
}
}
printf("\n");
printf("______________\n");
}
}

// Clears the screen
void clrscr()
{
system("cls");
}

// sets the cursor to said position
void gotoxy(int x, int y)
{
HANDLE hConsoleOutput;
COORD dwCursorPosition;

dwCursorPosition.X = x;
dwCursorPosition.Y = y;
hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hConsoleOutput,dwCursorPosition);
}

// Animated intro text
void prntInt(int i)
{
switch (i)
{
case 0:
printf("T");
break;
case 1:
printf("I");
break;
case 2:
printf("C");
break;
case 3:
printf(" ");
break;
case 4:
printf("T");
break;
case 5:
printf("A");
break;
case 6:
printf("C");
break;
case 7:
printf(" ");
break;
case 8:
printf("T");
break;
case 9:
printf("O");
break;
case 10:
printf("E");
break;
}
}

// Main Menu
int Menu()
{
int op;

clrscr();
SetTextColour(0,1,0);
printf("\t\t X ");
SetTextColour(1,1,1);
printf("| O | O\n");
printf("\t\t------------\n");
printf("\t\t O | ");
SetTextColour(0,1,0);
printf("X ");
SetTextColour(1,1,1);
printf("| O\n");
printf("\t\t------------\n");
printf("\t\t O | O |");
SetTextColour(0,1,0);
printf(" X");
SetTextColour(1,1,1);
printf("\n\n\t\t");
SetTextColour(0,1,1);
for (int i=0; i<=10; i++)
{
prntInt(i);
Sleep(200);
}
gotoxy(15,7);
SetTextColour(2,2,2);
printf("*");
Sleep(400);
gotoxy(15,7);
printf(" ");
gotoxy(27,5);
printf("*");
Sleep(500);
gotoxy(27,5);
printf(" ");
gotoxy(0,8);
printf("\t\t--- MENU ---\n");
SetTextColour(0,1,0);
printf("\t\t(1)");
SetTextColour(1,1,1);
printf("Single Player Game\n");
SetTextColour(0,1,0);
printf("\t\t(2)");
SetTextColour(1,1,1);
printf("Two Player Game\n");
SetTextColour(0,1,0);
printf("\t\t(0)");
SetTextColour(1,1,1);
printf("Quit: ");
cin >> op;
switch(op)
{
case 0:
printf("\nPress Enter");
cin.ignore(1,'\n');
cin.get();
break;
case 1:
case 2:
break;
default:
SetTextColour(1,0,0);
printf("\nInvalid entry");
SetTextColour(1,1,1);
cin.ignore(1,'\n');
cin.get();
return Menu();
break;
}
clrscr();
return op;
}

int main()
{
int op; // Used for several things
int letter; // Was originally a character, but changed to an integer...the name stayed the same
int row, column; // the row and column values for use in the game board
int menu; // An integer used for checking the menu option selected
bool first=true; // This is for an AI move later
int corner; // for use in an AI check
int space1, space2;
int fillcount=0;

// A random option is possible for the AI, so we'll seed it
srand(time(NULL));

// initialise the board to 0 (blank)
for (int a = 0; a<3; a++)
{
for (int b=0; b<3; b++)
board[b][a]=0;
}
menu = Menu(); // Show the menu and take assign the option selected to the variable 'menu'
switch(menu)
{
case 0:
return 0;
break;
case 1:
break;
}
// Two player game (a little simpler than the 1-player because of no AI
// However, it is still rather lengthy due to win checking
if(menu==2)
{
for(;;)
{
clrscr();
Board();

// Check for a tie
for(int s=0; s<3; s++)
{
for(int t=0; t<3; t++)
{
if(board[t][s] != 0)
fillcount++;
}
}
if(fillcount > 8)
{
SetTextColour(0,0,1);
printf("\n\t\tA Cat's Game!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
return 0;
break;
}
else
return main();
}
else
fillcount = 0;

SetTextColour(2,2,2);
cout << "\n(1)Place X\t(2)Return to Menu\t(0)Quit: ";
cin >> op;
SetTextColour(1,1,1);
switch(op)
{
case 1:
break;
case 2:
return main();
break;
case 0:
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
return 0;
break; // quit
default:
SetTextColour(1,0,0);
printf("\nNot a valid option.  Please select a valid option.");
SetTextColour(1,1,1);
cin.ignore(1,'\n');
cin.get();
continue;
}

// Looks more complicated than it is.
// This basically makes the user interface
// somewhat easier by colour-coding some of the words
// and such.  Also some error checking.
printf("\nEnter the ");
SetTextColour(1,1,0);
printf("row ");
SetTextColour(1,1,1);
printf("number: ");
SetTextColour(0,1,0);
cin >> letter;
SetTextColour(1,1,1);
if (letter < 1 || letter > 3)  // Check for illegal row value
{
SetTextColour(1,0,0);
cout << "\nInvalid row number, please enter a valid row number.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}

printf("Enter the ");
SetTextColour(0,1,1);
printf("column ");
SetTextColour(1,1,1);
printf("number: ");
SetTextColour(0,1,0);
cin >> op;
SetTextColour(1,1,1);
if (op < 1 || op > 3) // check for illegal column value
{
SetTextColour(1,0,0);
cout << "\nInvalid column number, please enter a valid column number.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}
// Now check to see if space is already filled
row = letter-1;
column = op-1;

if (board[column][row] != 0)
{
SetTextColour(1,0,0);
cout << "\nThe position ";
cout << letter << "," << op << " ";
cout << "is already filled.  Please try a new location.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}
else // fill the space
board[column][row] = 1;
// Update screen
gotoxy(0,0);
Board();
gotoxy(0,12); // return cursor to previous position
// Check for win
if (board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1)
{
/*
X - -
- X -
- - X
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 1 && board[0][1] == 1 && board[0][2] == 1)
{
/*
X X X
- - -
- - -
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 1 && board[1][0] == 1 && board[2][0] == 1)
{
/*
X - -
X - -
X - -
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][2] == 1 && board[1][1] == 1 && board[2][0] == 1)
{
/*
- - X
- X -
X - -
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 1 && board[1][1] == 1 && board[1][2] == 1)
{
/*
- X -
- X -
- X -
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][1] == 1 && board[1][1] == 1 && board[2][1] == 1)
{
/*
- - -
X X X
- - -
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if(board[0][2] == 1 && board[1][2] == 1 && board[2][2] == 1)
{
/*
- - -
- - -
X X X
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 1 && board[1][1] == 1 && board[1][2] == 1)
{
/*
- X -
- X -
- X -
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[2][0] == 1 && board[2][1] == 1 && board[2][2] == 1)
{
/*
- - X
- - X
- - X
*/
SetTextColour(0,1,0);
printf("\n\t\tX Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}

// O's turn
for(;;) // This is so O can re-do his/her turn should they enter an invalid option
{
clrscr();
Board();

// Check for a tie
for(int a=0; a<3; a++)
{
for(int b=0; b<3; b++)
{
if(board[b][a] != 0)
fillcount++;
}
}
if(fillcount > 8)
{
SetTextColour(0,0,1);
printf("\n\t\tA Cat's Game!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
return 0;
break;
}
else
return main();
}
else
fillcount = 0;

SetTextColour(2,2,2);
cout << "\n(1)Place O\t(2)Return to Menu\t(0)Quit: ";
cin >> op;
SetTextColour(1,1,1);
switch(op)
{
case 1:
break;
case 2:
return main();
break;
case 0:
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
return 0;
break; // quit
default:
SetTextColour(1,0,0);
printf("\nNot a valid option.  Please select a valid option.");
SetTextColour(1,1,1);
cin.ignore(1,'\n');
cin.get();
continue;
}

// Looks more complicated than it is.
// This basically makes the user interface
// somewhat easier by colour-coding some of the words
// and such.  Also some error checking.
printf("\nEnter the ");
SetTextColour(1,1,0);
printf("row ");
SetTextColour(1,1,1);
printf("number: ");
SetTextColour(0,1,0);
cin >> letter;
SetTextColour(1,1,1);
if (letter < 1 || letter > 3)  // Check for illegal row value
{
SetTextColour(1,0,0);
cout << "\nInvalid row number, please enter a valid row number.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}

printf("Enter the ");
SetTextColour(0,1,1);
printf("column ");
SetTextColour(1,1,1);
printf("number: ");
SetTextColour(0,1,0);
cin >> op;
SetTextColour(1,1,1);
if (op < 1 || op > 3) // check for illegal column value
{
SetTextColour(1,0,0);
cout << "\nInvalid column number, please enter a valid column number.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}
// Now check to see if space is already filled
row = letter-1;
column = op-1;

if (board[column][row] != 0)
{
SetTextColour(1,0,0);
cout << "\nThe position ";
cout << letter << "," << op << " ";
cout << "is already filled.  Please try a new location.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}
else // fill the space
board[column][row] = 2;
// Update screen
gotoxy(0,0);
Board();
gotoxy(0,12); // return cursor to previous position
// Check for win
if (board[0][0] == 2 && board[1][1] == 2 && board[2][2] == 2)
{
/*
O - -
- O -
- - O
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 2 && board[0][1] == 2 && board[0][2] == 2)
{
/*
O O O
- - -
- - -
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 2 && board[1][0] == 2 && board[2][0] == 2)
{
/*
O - -
O - -
O - -
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][2] == 2 && board[1][1] == 2 && board[2][0] == 2)
{
/*
- - O
- O -
O - -
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 2 && board[1][1] == 2 && board[1][2] == 2)
{
/*
- O -
- O -
- O -
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][1] == 2 && board[1][1] == 2 && board[2][1] == 2)
{
/*
- - -
O O O
- - -
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if(board[0][2] == 2 && board[1][2] == 2 && board[2][2] == 2)
{
/*
- - -
- - -
O O O
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 2 && board[1][1] == 2 && board[1][2] == 2)
{
/*
- O -
- O -
- O -
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[2][0] == 2 && board[2][1] == 2 && board[2][2] == 2)
{
/*
- - O
- - O
- - O
*/
SetTextColour(0,1,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
break;
}
}
}
// Main game loop
for(;;)
{
clrscr();
Board();
// After updating the board, the very first thing to occur will be to check for an O win
// from the previous turn.
// NOTE: This code is simply copied/pasted from the X wins code
// Check for win
if (board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1)
{
/*
O - -
- O -
- - O
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 2 && board[0][1] == 2 && board[0][2] == 2)
{
/*
O O O
- - -
- - -
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 2 && board[1][0] == 2 && board[2][0] == 2)
{
/*
O - -
O - -
O - -
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][2] == 2 && board[1][1] == 2 && board[2][0] == 2)
{
/*
- - O
- O -
O - -
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 2 && board[1][1] == 2 && board[1][2] == 2)
{
/*
- O -
- O -
- O -
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][1] == 2 && board[1][1] == 2 && board[2][1] == 2)
{
/*
- - -
O O O
- - -
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if(board[0][2] == 2 && board[1][2] == 2 && board[2][2] == 2)
{
/*
- - -
- - -
O O O
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 2 && board[1][1] == 2 && board[1][2] == 2)
{
/*
- O -
- O -
- O -
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[2][0] == 2 && board[2][1] == 2 && board[2][2] == 2)
{
/*
- - O
- - O
- - O
*/
SetTextColour(1,0,0);
printf("\n\t\tO Wins!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}

SetTextColour(2,2,2);
cout << "\n(1)Place X\t(2)Return to Menu\t(0)Quit: ";
cin >> op;
SetTextColour(1,1,1);
switch(op)
{
case 1:
break;
case 2:
return main();
break;
case 0:
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
return 0;
break; // quit
default:
SetTextColour(1,0,0);
printf("\nNot a valid option.  Please select a valid option.");
SetTextColour(1,1,1);
cin.ignore(1,'\n');
cin.get();
continue;
}

// Looks more complicated than it is.
// This basically makes the user interface
// somewhat easier by colour-coding some of the words
// and such.  Also some error checking.
printf("\nEnter the ");
SetTextColour(1,1,0);
printf("row ");
SetTextColour(1,1,1);
printf("number: ");
SetTextColour(0,1,0);
cin >> letter;
SetTextColour(1,1,1);
if (letter < 1 || letter > 3)  // Check for illegal row value
{
SetTextColour(1,0,0);
cout << "\nInvalid row number, please enter a valid row number.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}

printf("Enter the ");
SetTextColour(0,1,1);
printf("column ");
SetTextColour(1,1,1);
printf("number: ");
SetTextColour(0,1,0);
cin >> op;
SetTextColour(1,1,1);
if (op < 1 || op > 3) // check for illegal column value
{
SetTextColour(1,0,0);
cout << "\nInvalid column number, please enter a valid column number.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}
// Now check to see if space is already filled
row = letter-1;
column = op-1;

if (board[column][row] != 0)
{
SetTextColour(1,0,0);
cout << "\nThe position ";
cout << letter << "," << op << " ";
cout << "is already filled.  Please try a new location.\n";
cin.ignore(1,'\n');
cin.get();
SetTextColour(1,1,1);
continue;
}
else // fill the space
board[column][row] = 1;
// Update screen
gotoxy(0,0);
Board();
gotoxy(0,12); // return cursor to previous position
// Check for win
if (board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1)
{
/*
X - -
- X -
- - X
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 1 && board[0][1] == 1 && board[0][2] == 1)
{
/*
X X X
- - -
- - -
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][0] == 1 && board[1][0] == 1 && board[2][0] == 1)
{
/*
X - -
X - -
X - -
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][2] == 1 && board[1][1] == 1 && board[2][0] == 1)
{
/*
- - X
- X -
X - -
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 1 && board[1][1] == 1 && board[1][2] == 1)
{
/*
- X -
- X -
- X -
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[0][1] == 1 && board[1][1] == 1 && board[2][1] == 1)
{
/*
- - -
X X X
- - -
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if(board[0][2] == 1 && board[1][2] == 1 && board[2][2] == 1)
{
/*
- - -
- - -
X X X
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[1][0] == 1 && board[1][1] == 1 && board[1][2] == 1)
{
/*
- X -
- X -
- X -
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
if (board[2][0] == 1 && board[2][1] == 1 && board[2][2] == 1)
{
/*
- - X
- - X
- - X
*/
SetTextColour(0,1,0);
printf("\n\t\tYou Win!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}

// Check for a tie
for(int a=0; a<3; a++)
{
for(int b=0; b<3; b++)
{
if(board[b][a] != 0)
fillcount++;
}
}
if(fillcount > 8)
{
SetTextColour(1,1,0);
printf("\n\t\tA Cat's Game!!!\n");
SetTextColour(1,1,1);
cout << "\n(1)New Game (0)Quit: ";
cin >> op;
if (op == 0)
{
cout << "\nPress Enter";
cin.ignore(1,'\n');
cin.get();
break;
}
else
return main();
}
else
fillcount = 0;

// Now for the hard part...AI
// We'll start with O's first move
// Generally, it's best to take the middle
// position first.  So, we'll say that if X
// doesn't take the middle first turn, O will.
if (first) // only check after the first move of the game
{
if (board[1][1] == 0) // is the middle position still blank?
board[1][1] = 2; // If so, stick an O there.
else
{
// If the spot is taken, take a random corner piece
corner = 1+rand()%4;
switch(corner)
{
case 1:
board[0][0] = 2;
break;
case 2:
board[2][0] = 2;
break;
case 3:
board[0][2] = 2;
break;
case 4:
board[2][2] = 2;
break;
}
}
first = false; // The first turn is over, so this AI check is done
continue;
}

// Now we'll do the AI for O.
// O will take a more aggressive strategy.
// Before he even bothers to see if X may win, O checks if he can (like a human would).
// If he can't, then he'll move to his second priority: stopping X.  If he can win, he will.
// However, if he can't at the moment and X can, then O will prevent this.
// If neither of the above scenarios are true at anytime during an O turn, O chooses a random
// empty space to occupy.  There was originally code for O to search for a free corner piece
// before trying a random one, but I've found that for the most part, the only time that O
// would try this would be too far into the game for there to be much of a chance of any corner
// positions.  Thus, this code was dumped.

// NOTE: This code is simply a copied/pasted version of the X checking code,
// except all the X's are changed to O's.
if(board[0][0] == 2)
{
if (board[1][0] == 2 && board[2][0] == 0)
{
// Left to right win?
/*
O O -
- - -
- - -
*/
board[2][0] = 2;
continue;
// This is used so that it will restart the game loop
// and not place more than one O
}
if(board[2][0] == 2 && board[1][0] == 0)
{
// Another possible left-right win
/*
O - O
- - -
- - -
*/
board[1][0] = 2;
continue;
}
if (board[0][1] == 2 && board[0][2] == 0)
{
// A up-down win
/*
O - -
O - -
- - -
*/
board[0][2] = 2;
continue;
}
if (board[0][2] == 2 && board[0][1] == 0)
{
// The other possible up-down win
/*
O - -
- - -
O - -
*/
board[0][1] = 2;
continue;
}
if (board[1][1] == 2 && board[2][2] == 0)
{
// A possible diagonal win
/*
O - -
- O -
- - -
*/
board[2][2] = 2;
continue;
}
if(board[2][2] == 2 && board[1][1] == 0)
{
// The other possible diagonal win
/*
O - -
- - -
- - O
*/
board[1][1] = 2;
continue;
}
// Ends possible O wins utilising the first position
}
// Possible O wins utilising position 2 (only up-down wins)
if(board[1][0] == 2)
{
if (board[1][1] == 2 && board[1][2] == 0)
{
// The first up-down possible win
/*
- O -
- O -
- - -
*/
board[1][2] = 2;
continue;
}
if (board[1][2] == 2 && board[1][1] == 0)
{
// The other up-down possible win
/*
- O -
- - -
- O -
*/
board[1][1] = 2;
continue;
}
// Ends possible wins utilising position 2
}
// Possible up-down O wins utilising position 3
if(board[2][0] == 2)
{
if (board[2][1] == 2 && board[2][2] == 0)
{
/*
- - O
- - O
- - -
*/
board[2][2] = 2;
continue;
}
if(board[2][2] == 2 && board[2][1] == 0)
{
/*
- - O
- - -
- - O
*/
board[2][1] = 2;
break;
}
if(board[1][1] == 2 && board[0][2] == 0)
{
/*
- - O
- O -
- - -
*/
board[0][2] = 2;
continue;
}
// NOTE: A second diagonal check is unnecessary since our initial
// check ensured that the middle space is filled no matter what.
// Ends possible wins utilising position 3
}
// All possible left-right wins utilising the middle row
if(board[0][1] == 2)
{
if(board[1][1] == 2 && board[2][1] == 0)
{
/*
- - -
O O -
- - -
*/
board[2][1] = 2;
continue;
}
// NOTE: There isn't a check for the other 'possible' win because our
// initial first check would have made sure the middle space was
// filled no matter what.
// Ends possible O wins utilising the middle row (with the exception of one)
}
// All possible left-right wins utilising the last row
if(board[0][2] == 2)
{
if(board[1][2] == 2 && board[2][2] == 0)
{
/*
- - -
- - -
O O -
*/
board[2][2] = 2;
break;
}
if(board[2][2] == 2 && board[1][2] == 0)
{
/*
- - -
- - -
O - O
*/
board[1][2] = 2;
continue;
}
}
// There are still possible O wins that were excluded from the previous
// searches because they involved the initial if() position.  Wins are possible
// when this space is not in use, obviously.  Most were taken care of anyways,
// but some remain, and those will be dealt with here.

// A left-right search for row 1
if(board[1][0] == 2 && board[2][0] == 2 && board[0][0] == 0)
{
/*
- O O
- - -
- - -
*/
board[0][0] = 2;
continue;
}
if(board[2][2] == 2 && board[1][1] == 2 && board[0][0] == 0)
{
/*
- - -
- O -
- - O
*/
board[0][0] = 2;
continue;
}
if(board[0][1] == 2 && board[0][2] == 2 && board[0][0] == 0)
{
/*
- - -
O - -
O - -
*/
board[0][0] = 2;
continue;
}
if(board[1][2] == 2 && board[1][1] == 2 && board[1][0] == 0)
{
/*
- - -
- O -
- O -
*/
board[1][0] = 2;
continue;
}
if(board[0][2] == 2 && board[1][1] == 2 && board[2][0] == 0)
{
/*
- - -
- O -
O - -
*/
board[2][0] = 2;
continue;
}
if(board[2][1] == 2 && board[1][1] == 2 && board[0][1] == 0)
{
/*
- - -
- O O
- - -
*/
board[0][1] = 2;
continue;
}

// Look for possible X wins involving position 1
if(board[0][0] == 1)
{
if (board[1][0] == 1 && board[2][0] == 0)
{
// Left to right win?
/*
X X -
- - -
- - -
*/
board[2][0] = 2;
continue;
// This is used so that it will restart the game loop
// and not place more than one O
}
if(board[2][0] == 1 && board[1][0] == 0)
{
// Another possible left-right win
/*
X - X
- - -
- - -
*/
board[1][0] = 2;
continue;
}
if (board[0][1] == 1 && board[0][2] == 0)
{
// A up-down win
/*
X - -
X - -
- - -
*/
board[0][2] = 2;
continue;
}
if (board[0][2] == 1 && board[0][1] == 0)
{
// The other possible up-down win
/*
X - -
- - -
X - -
*/
board[0][1] = 2;
continue;
}
if (board[1][1] == 1 && board[2][2] == 0)
{
// A possible diagonal win
/*
X - -
- X -
- - -
*/
board[2][2] = 2;
continue;
}
if(board[2][2] == 1 && board[1][1] == 0)
{
// The other possible diagonal win
/*
X - -
- - -
- - X
*/
board[1][1] = 2;
continue;
}
// Ends possible X wins utilising the first position
}
// Possible X wins utilising position 2 (only up-down wins)
if(board[1][0] == 1)
{
if (board[1][1] == 1 && board[1][2] == 0)
{
// The first up-down possible win
/*
- X -
- X -
- - -
*/
board[1][2] = 2;
continue;
}
if (board[1][2] == 1 && board[1][1] == 0)
{
// The other up-down possible win
/*
- X -
- - -
- X -
*/
board[1][1] = 2;
continue;
}
// Ends possible wins utilising position 2
}
// Possible up-down X wins utilising position 3
if(board[2][0] == 1)
{
if (board[2][1] == 1 && board[2][2] == 0)
{
/*
- - X
- - X
- - -
*/
board[2][2] = 2;
continue;
}
if(board[2][2] == 1 && board[2][1] == 0)
{
/*
- - X
- - -
- - X
*/
board[2][1] = 2;
break;
}
if(board[1][1] == 1 && board[0][2] == 0)
{
/*
- - X
- X -
- - -
*/
board[0][2] = 2;
continue;
}
// NOTE: A second diagonal check is unnecessary since our initial
// check ensured that the middle space is filled no matter what.
// Ends possible wins utilising position 3
}
// All possible left-right wins utilising the middle row
if(board[0][1] == 1)
{
if(board[1][1] == 1 && board[2][1] == 0)
{
/*
- - -
X X -
- - -
*/
board[2][1] = 2;
continue;
}
// NOTE: There isn't a check for the other 'possible' win because our
// initial first check would have made sure the middle space was
// filled no matter what.
// Ends possible X wins utilising the middle row (with the exception of one)
}
// All possible left-right wins utilising the last row
if(board[0][2] == 1)
{
if(board[1][2] == 1 && board[2][2] == 0)
{
/*
- - -
- - -
X X -
*/
board[2][2] = 2;
break;
}
if(board[2][2] == 1 && board[1][2] == 0)
{
/*
- - -
- - -
X - X
*/
board[1][2] = 2;
continue;
}
}
// There are still possible X wins that were excluded from the previous
// searches because they involved the initial if() position.  Wins are possible
// when this space is not in use, obviously.  Most were taken care of anyways,
// but some remain, and those will be dealt with here.

// A left-right search for row 1
if(board[1][0] == 1 && board[2][0] == 1 && board[0][0] == 0)
{
/*
- X X
- - -
- - -
*/
board[0][0] = 2;
continue;
}
if(board[2][2] == 1 && board[1][1] == 1 && board[0][0] == 0)
{
/*
- - -
- X -
- - X
*/
board[0][0] = 2;
continue;
}
if(board[0][1] == 1 && board[0][2] == 1 && board[0][0] == 0)
{
/*
- - -
X - -
X - -
*/
board[0][0] = 2;
continue;
}
if(board[1][2] == 1 && board[1][1] == 1 && board[1][0] == 0)
{
/*
- - -
- X -
- X -
*/
board[1][0] = 2;
continue;
}
if(board[0][2] == 1 && board[1][1] == 1 && board[2][0] == 0)
{
/*
- - -
- X -
X - -
*/
board[2][0] = 2;
continue;
}
if(board[2][1] == 1 && board[1][1] == 1 && board[0][1] == 0)
{
/*
- - -
- X X
- - -
*/
board[0][1] = 2;
continue;
}
// Ends all possible X win checks
// Finally, if none of that is possible, it will simply choose a random empty space
for(;;)
{
space1=1+rand()%3;
space2=1+rand()%3;
if(board[space2-1][space1-1] == 0)
{
board[space2-1][space1-1] = 2;
break;
}
}
}
return 0;
}