#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.

" ); printf ( "Try not to get too frustrated, but he never loses.

" ); printf ( "The best you can hope for is a cat's game.



" ); printf ( "Good luck and have fun!



" ); printf ( "Programmed by Joseph 'Ninwa' Bleau

" ); printf ( "(PS: I am not responsible for keyboards broken out of furstration.)



" ); 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 ( "

Those were invalid coordinates, try again!

" ); } else { printf ( "

Those were invalid coordinates, try again!

" ); 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!

Congratulations player '%c'



" , winner ); else { printf ( "I guess there was a cats game! Oh well, nice try both of you! :)



" ); state [ currentState ]. result = 3 ; } printf ( "Final board:



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

" ); printf ( " +-----------+

" ); 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 ( "|

" ); } printf ( " +-----------+



" ); } void clearScreen () { /* Stupid utility function to clear the screen by printing 80 newlines. */ int i ; for ( i = 0 ; i < 80 ; i ++ ) printf ( "

" ); }