#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");
}