#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
struct State
{
int result; /* Stores the result: 0 is in progress, 1 is X Win, 2 is 0 Win, 3 is Cats Game */
int turn; /* Stores the number of turns since the current state. */
char currentPlayer; /* Stores the piece of the player whos turn it is. */
char board[3][3]; /* Stores information about the board. */
};
void setupNextState(struct State*, struct State*);
void initializeState(struct State*);
void initializeBoard(struct State*);
void drawBoard(struct State*);
void placeRandomPiece(struct State*);
char checkForWinner(struct State* state);
void clearScreen();
/* TaccyAI: A Tic-Tac-Toe AI Engine */
void TaccyRandomPiece(struct State* );
void TaccyMakeMove(struct State*);
short TaccyStopMakeWin(struct State*, char);
short TaccyBlockCorner(struct State*);
int main(void)
{
struct State state[10]; /* The current state of our game. */
int x = -1, y = -1; /* Used for holding input of user/ coordinates */
short validCoordinates = 0; /* Used for looping until user enters valid coordinates. */
short currentState = 0; /* Holds the current state we're in */
char winner = ' '; /* Holds value of winner if applicable */
srand((int)time(0)); /* Seed RNG */
initializeState(&state[currentState]);
printf("You are about to play against the TaccyAI, Tic-Tac-Toe Bot.\n");
printf("Try not to get too frustrated, but he never loses.\n");
printf("The best you can hope for is a cat's game.\n\n");
printf("Good luck and have fun!\n\n");
printf("Programmed by Joseph 'Ninwa' Bleau\n");
printf("(PS: I am not responsible for keyboards broken out of furstration.)\n\n");
system("pause");
while(state[currentState].turn != 10&& state[currentState].result == 0)
{
clearScreen();
drawBoard(&state[currentState]);
if(state[currentState].turn % 2 == 0){
state[currentState].currentPlayer = 'O';
validCoordinates = 0; /* Reset checker. */
while(validCoordinates == 0){
printf("Enter coordinates to place your mark (e.g 0,1): ");
scanf("%i,%i",&y,&x);
/* Check range on coordinates */
if( x < 3 && x >= 0 && y < 3 && y >= 0 ){
/* Check that a piece is not already there. */
if( state[currentState].board[y][x] == ' ' ){
/* Everything checks out, place our piece. */
validCoordinates = 1;
state[currentState].board[y][x] = 'O';
}
else
printf("\nThose were invalid coordinates, try again!\n");
}
else{
printf("\nThose were invalid coordinates, try again!\n");
fflush(stdin);
}
}
}
else{
/* CPU's Turn (TaccyAI) */
state[currentState].currentPlayer = 'X';
TaccyMakeMove(&state[currentState]);
}
if(state[currentState].turn > 4){
/* Assess Board, is there a winner? */
winner = checkForWinner(&state[currentState]);
if(winner != ' '){
clearScreen();
if(winner == 'X')
state[currentState].result = 1;
else if(winner == 'O')
state[currentState].result = 2;
if( winner != 'C' )
printf("There was a winner! \nCongratulations player '%c'\n\n",winner);
else{
printf("I guess there was a cats game! Oh well, nice try both of you! :)\n\n");
state[currentState].result = 3;
}
printf("Final board:\n\n");
drawBoard(&state[currentState]);
continue;
}
}
setupNextState(&state[currentState],&state[currentState+1]);
currentState++;
}
return 0;
}
void TaccyRandomPiece(struct State* state)
{
short piecePlaced = 0;
int y,x;
while(piecePlaced == 0)
{
x = rand()%3;
y = rand()%3;
if( state->board[y][x] == ' ' ){
piecePlaced = 1;
state->board[y][x] = 'X';
}
}
}
short TaccyBlockCorner(struct State* state)
{
//[x] [ ]
//[ ] [ ]
if( state->board[0][0] == 'X' ){
if(state->board[0][2] == ' '){
state->board[0][2] = 'X';
return 1;
}
if(state->board[2][0] == ' '){
state->board[2][0] = 'X';
return 1;
}
}
//[ ] [x]
//[ ] [ ]
if( state->board[0][2] == 'X' ){
if(state->board[0][0] == ' '){
state->board[0][0] = 'X';
return 1;
}
if(state->board[2][2] == ' '){
state->board[2][2] = 'X';
return 1;
}
}
//[ ] [ ]
//[ ] [x]
if( state->board[2][2] == 'X' ){
if(state->board[0][2] == ' '){
state->board[0][2] = 'X';
return 1;
}
if(state->board[2][0] == ' '){
state->board[2][0] = 'X';
return 1;
}
}
//[ ] [ ]
//[x] [ ]
if( state->board[2][0] == 'X' ){
if(state->board[0][0] == ' '){
state->board[0][0] = 'X';
return 1;
}
if(state->board[2][2] == ' '){
state->board[2][2] = 'X';
return 1;
}
}
if( state->board[0][2] == 'X' && state->board[0][0] == ' '){
state->board[0][0] = 'X';
return 1;
}
if( state->board[0][0] == 'O' && state->board[2][2] == ' ' ){
state->board[2][2] = 'X';
return 1;
}
if( state->board[0][2] == 'O' && state->board[2][0] == ' '){
state->board[2][0] = 'X';
return 1;
}
if( state->board[2][2] == 'O' && state->board[0][0] == ' ' ){
state->board[0][0] = 'X';
return 1;
}
if( state->board[2][0] == 'O' && state->board[0][2] == ' ' ){
state->board[0][2] = 'X';
return 1;
}
return 0;
}
short TaccyStopMakeWin(struct State* state, char check_for)
{
int i,j;
for(i=0;i<3;i++){
for(j=0;j<3;j++){
if(state->board[i][j] == ' ')
{
state->board[i][j] = check_for;
if(checkForWinner(state) == check_for){
state->board[i][j] = 'X';
return 1;
}
else{
state->board[i][j] = ' ';
}
}
}
}
return 0;
}
short TaccyCheckEnemyCorners(struct State* state)
{
int counter = 0;
if(state->board[0][0] == 'O')
counter++;
if(state->board[0][2] == 'O')
counter++;
if(state->board[2][2] == 'O')
counter++;
if(state->board[2][0] == 'O')
counter++;
if( counter > 1)
{
if( state->board[1][0] == ' ' ){
state->board[1][0] = 'X';
return 1;
}
if( state->board[2][1] == ' ' ){
state->board[2][1] = 'X';
return 1;
}
if( state->board[1][2] == ' '){
state->board[1][2] = 'X';
return 1;
}
if( state->board[0][1] == ' '){
state->board[0][1] = 'X';
return 1;
}
}
return 0;
}
void TaccyMakeMove(struct State* state)
{
/* Easter egg. One out of approximately every fifty game the computer cheats
and fills out the entire board. :o) */
int r = rand()%50;
int i,j;
if(r == 7) /* 7 is my favorite number :) */{
for( i=0; i<3; i++ ){
for( j=0; j<3; j++ )
{
if( state->board[i][j] != 'O' )
state->board[i][j] = 'X';
}
}
return;
}
if(state->turn < 2 && state->board[1][1] == 'O'){
state->board[2][2] = 'X';
return;
}
if(TaccyStopMakeWin(state,'X') == 1)
return;
if(TaccyStopMakeWin(state,'O') == 1)
return;
if(state->board[1][1] == ' '){
state->board[1][1] = 'X';
return;
}
if( state->board[1][1] == 'X' )
if(TaccyCheckEnemyCorners(state) == 1)
return;
if(TaccyBlockCorner(state) == 1)
return;
/* Realistically, this shouldn't happen. */
TaccyRandomPiece(state);
}
void setupNextState(struct State* s1, struct State* s2)
{
int i, j;
s2->turn = s1->turn+1;
s2->result = s1->result;
if( s1->currentPlayer == 'X' )
s2->currentPlayer = 'O';
else
s2->currentPlayer = 'X';
for(i=0;i<3;i++)
for(j=0;j<3;j++)
s2->board[i][j] = s1->board[i][j];
}
void initializeState(struct State* state)
{
state->turn = 0;
state->currentPlayer = 'X';
state->result = 0;
initializeBoard(state);
}
void initializeBoard(struct State* state)
{
int i, j;
for(i = 0; i < 3; i++){
for(j = 0; j <3; j++){
state->board[i][j] = ' ';
}
}
}
/* Checks the board within the state for a winner.
/* Return Values:
/* '\0' - No Winner
/* '0' - Player ('O') is the winner
/* 'X' - CPU ('X') is the winner */
char checkForWinner(struct State* state)
{
int i,j;
for(i=0;i<3;i++){
if( state->board[i][0] != ' ' ){
if( state->board[i][0] == state->board[i][1] &&
state->board[i][1] == state->board[i][2] )
return state->board[i][0];
}
if( state->board[0][i] != ' ' ){
if( state->board[0][i] == state->board[1][i] &&
state->board[1][i] == state->board[2][i] )
return state->board[0][i];
}
}
for(i=0,j=2;i<=2;i+=2,j-=2){
if( state->board[0][i] != ' ' ){
if( state->board[0][i] == state->board[1][1] &&
state->board[1][1] == state->board[2][j] )
return state->board[0][i];
}
}
/* Check to see if all positions are filled with no win, aka cats-game. */
for(i=0;i<3;i++)
for(j=0;j<3;j++){
if( state->board[i][j] == ' ' )
return ' ';
}
return 'C';
}
void drawBoard(struct State* state)
{
int i,j;
printf(" | 0 | 1 | 2 |\n");
printf(" +-----------+\n");
for(i=0;i<3;i++){
for(j=0;j<3;j++){
if(j == 0 )
printf(" %i ",i);
printf("| %c ", state->board[j][i]);
}
printf("|\n");
}
printf(" +-----------+\n\n");
}
void clearScreen() { /* Stupid utility function to clear the screen by printing 80 newlines. */
int i;
for(i = 0; i < 80; i++)
printf("\n");
}