Skip to content

Instantly share code, notes, and snippets.

@barrucadu
Forked from EightAndAHalfTails/Noughts and Crosses.c
Created November 11, 2011 13:37
Show Gist options
  • Save barrucadu/1358016 to your computer and use it in GitHub Desktop.
Save barrucadu/1358016 to your computer and use it in GitHub Desktop.
BIN := xo
CC := gcc
CFLAGS := -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Winit-self -Wmissing-prototypes -Wstrict-prototypes -Wconversion -std=gnu99 -ggdb -pedantic
SOURCES := $(wildcard *.c)
.PHONY: all clean
all: $(BIN)
$(BIN): $(SOURCES:.c=.o)
@echo LD $@
@$(CC) $^ -o $@
%.o: %.c
@echo CC $@
@$(CC) $(CFLAGS) -c $^
clean:
-@rm $(BIN) $(SOURCES:.c=.o)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
/*Type Definitions*/
typedef enum oxb {nought, cross, blank} oxb_t ;
typedef enum mode {vsAI, vsHuman} gamemode_t ;
typedef enum bool {false, true} boolean ;
/*Global Variables*/
oxb_t board[10] ;
/*Functions*/
char whatis_position(int i) ; /*returns visual representation of the symbol in a given position */
oxb_t player_select(void) ; /*allows player selection */
gamemode_t game_mode(void) ; /*allows game mode selection */
void display_board(void) ; /*prints visual representation of board */
void initialise_board(void) ; /*resets board to all blanks */
int make_move( oxb_t current_player ) ; /*accepts input of current player's move */
int make_computer_move( oxb_t current_player ) ; /*Calculates and returns near-optimal move */
void update_board( oxb_t current_player, int move ) ; /*updates board with a given player's move */
boolean gamewon(void) ; /*returns a true value if game has been won, false otherwise */
boolean gamedrawn(void) ; /*returns a true value if game is a draw */
void wait(int t) ; /*Waits for t milliseconds */
int make_computer_move_easy(void) ; /*Returns random valid move */
/*Main Function*/
int main(void)
{
/*Initialisation*/
gamemode_t mode;
int diff ;
oxb_t current_player, ai_player;
mode = game_mode();
if (mode == vsAI)
{
do
{
printf("1: Easy\n2: Hard\n> ") ;
scanf("%d", &diff) ;
} while (diff != 1 && diff != 2);
}
current_player = player_select();
ai_player = (current_player == nought) ? cross : nought;
initialise_board() ;
display_board() ;
/*Gameplay*/
while((gamewon() == 0 ) && (gamedrawn() == 0))
{
if(mode == vsHuman)
{
update_board( current_player, make_move(current_player)) ;
current_player = (current_player == nought) ? cross : nought;
}
else
{
update_board( current_player, make_move(current_player));
switch(diff)
{
case 1 : update_board( ai_player, make_computer_move_easy()) ; break ;
case 2 : update_board( ai_player, make_computer_move( ai_player )) ; break ;
}
}
display_board() ;
}
/*Result Checking*/
if (gamewon() == 1)
{
switch (current_player)
{
case cross : printf("\nYou lose. How about a nice game of chess?\n\n") ; break ;
case nought : printf("\nConglaturations! You have just completed a great game.\n\n") ; break ;
default: printf("\nERROR") ;
}
}
else
{
printf("\nStrange game. The only winning move is not to play.\n\n") ;
}
return 0 ;
}
char whatis_position(int i) /*returns visual representation of the symbol in a given position*/
{
switch (board[i])
{
case nought : return 'O' ; break ;
case cross : return 'X' ; break ;
default : return ' ' ; break ;
}
}
oxb_t player_select(void)
{
char symbol ;
do
{
printf("Select your symbol: [O/X]\n> ") ;
scanf("%c", &symbol) ;
switch(symbol)
{
case 'X' :
case 'x' : return cross ;
case 'O' :
case 'o' : return nought ;
}
}
while(1);
}
gamemode_t game_mode(void)
{
int imode;
do
{
printf("1: vs AI\n2: vs Human\n> ") ;
scanf("%d", &imode) ;
switch (imode)
{
case 1: return vsAI;;
case 2: return vsHuman;
}
}
while(1);
}
void display_board(void) /*prints visual representation of board*/
{
printf("\n%c|%c|%c\n-----\n%c|%c|%c\n-----\n%c|%c|%c\n",
whatis_position(7), whatis_position(8), whatis_position(9),
whatis_position(4), whatis_position(5), whatis_position(6),
whatis_position(1), whatis_position(2), whatis_position(3)
) ;
}
void initialise_board(void) /*resets board to all blanks*/
{
int i ;
for(i = 1 ; i < 10 ; i++){
board[i] = blank ;
}
}
int make_move( oxb_t current_player ) /*accepts input of current player's move*/
{
int move ;
do{
switch (current_player){
case cross : printf("\nCross, please press desired position on numpad > ") ; break ;
case nought : printf("\nNought, please press desired position on numpad > ") ; break ;
default: printf("ERROR") ;
}
scanf("%d", &move) ;
}
while (board[move] != blank) ;
return move ;
}
int make_computer_move( oxb_t current_player )
{
wait(500) ; /*to make it seem like the computer is thinking >.>*/
int mask[8][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{1, 4, 7},
{2, 5, 8},
{3, 6, 9},
{1, 5, 9},
{3, 5, 7}} ;
int i, j, keysquare1 = 0, keysquare2 = 0 ;
for( i=0 ; i<8 ; i++ ) /*checks for winning or blocking opportunities*/
{
for( j = 0 ; j < 3 ; j++ ){
if((board[mask[i][j]] == board[mask[i][((j+1)%3)]]) && (board[mask[i][((j+2)%3)]] == blank) && (board[mask[i][j]] != blank))
{
printf("\nAI plays %d to win or block\n", mask[i][((j+2)%3)]) ;
return mask[i][((j+2)%3)] ;
}
}
}
for( i=1 ; i<8 ; i++ ) /*checks for forking opportunities*/
{
for( j = 0 ; j < 2 ; j++ )
{
if((board[mask[i][j]] == board[mask[i][(j+1)%3]]) && (board[mask[i][(j+2)%3]] != blank) && (board[mask[i][j]] == blank))
{
if((mask[i][j] == keysquare1) || (mask[i][(j+1)%3] == keysquare1))
{
printf("\nAI plays %d to fork or prevent a fork\n", keysquare1) ;
return keysquare1 ;
}
else if ((mask[i][j] == keysquare2) || (mask[i][(j+1)%3] == keysquare2))
{
printf("\nAI plays %d to fork or prevent a fork\n", keysquare2) ;
return keysquare2 ;
}
else
{
keysquare1 = mask[i][j] ;
keysquare2 = mask[i][(j+1)%3] ;
}
}
}
}
if(board[5] == blank) /*play the centre*/
{
printf("\nAI plays the centre\n") ;
return 5 ;
}
if((board[1] == !current_player) && (board[9] == blank)) /*play the opposite corner*/
{
printf("\nAI plays the opposite corner\n") ;
return 9 ;
}
else if((board[9] == !current_player) && (board[1] == blank))
{
printf("\nAI plays the opposite corner\n") ;
return 1 ;
}
else if((board[7] == !current_player) && (board[3] == blank))
{
printf("\nAI plays the opposite corner\n") ;
return 3 ;
}
else if((board[3] == !current_player) && (board[7] == blank))
{
printf("\nAI plays the opposite corner\n") ;
return 7 ;
}
if(board[1] == blank) /*play an empty corner*/
{
printf("\nAI plays 1\n") ;
return 1 ;
}
if(board[3] == blank)
{
printf("\nAI plays 3\n") ;
return 3 ;
}
if(board[7] == blank)
{
printf("\nAI plays 7\n") ;
return 7 ;
}
if(board[9] == blank)
{
printf("\nAI plays 9\n") ;
return 9 ;
}
if(board[2] == blank) /*play an empty side*/
{
printf("\nAI plays 2\n") ;
return 2 ;
}
if(board[4] == blank)
{
printf("\nAI plays 4\n") ;
return 4 ;
}
if(board[6] == blank)
{
printf("\nAI plays 6\n") ;
return 6 ;
}
if(board[8] == blank)
{
printf("\nAI plays 8\n") ;
return 8 ;
}
}
void update_board( oxb_t current_player, int move ) /*updates board with a given player's move*/
{
board[move] = current_player ;
}
boolean gamewon(void) /*returns a true value if game has been won, false otherwise*/
{
int i ;
int mask[8][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{1, 4, 7},
{2, 5, 8},
{3, 6, 9},
{1, 5, 9},
{3, 5, 7}} ;
boolean result = false ;
for(i = 0; i < 8; i++)
{
result = result ||
( (board[mask[i][0]] != blank) &&
(board[mask[i][0]] == board[mask[i][1]]) &&
(board[mask[i][1]] == board[mask[i][2]]) ) ;
}
return result ;
}
boolean gamedrawn(void) /*returns a true value if game is a draw*/
{
int i ;
boolean unfilled = false ;
boolean draw = false ;
for(i=1 ; i<10 ; i++ )
{
unfilled = unfilled || (board[i] == blank) ;
}
draw = (!unfilled && !gamewon()) ;
return draw;
}
void wait(int t) /*Waits for t milliseconds*/
{
int millisec = t;
struct timespec req;
memset (&req, 0, sizeof (req));
req.tv_nsec = millisec * 1000000L;
nanosleep(&req, (struct timespec *)NULL);
}
int make_computer_move_easy()
{
time_t t ;
int move ;
do
{
srand((unsigned) time(&t)) ;
move = (rand() % 9) + 1 ;
}
while(board[move] != blank) ;
return move ;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment