-
-
Save barrucadu/1358016 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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