Created
June 21, 2018 18:45
-
-
Save qbatten/c9228a637ddba6ee3579a2922c12c49f to your computer and use it in GitHub Desktop.
Tic Tac Toe - Quinn Batten
This file contains hidden or 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
/*------------Libraries------------*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
/*------------PRINT BOARD: prints the current board state------------*/ | |
/* | |
Input: the current board state, represented by a char* of length 10 (9char+\0), where spaces that have been played | |
in have an "X" or "O" (whichever player played there), and unplyed spaces have a lowercase letter between a | |
and i, in increasing order from top left. | |
Output: Prints the board state, does not return any value. | |
*/ | |
void printBoard(char *board) | |
{ | |
printf("\033[2J"); //clear screen | |
printf("\n %c | %c | %c \n", board[0], board[1], board[2]); | |
printf("-----------\n"); | |
printf(" %c | %c | %c \n", board[3], board[4], board[5]); | |
printf("-----------\n"); | |
printf(" %c | %c | %c \n", board[6], board[7], board[8]); | |
} | |
/*------------GAME OVER: Prints congratulatory message------------*/ | |
//Input: (int) If someone won, the int of the ASCII Char of the winner. | |
//Output: Prints the result of the game, then returns 1 (unless there's a problem). | |
int gameOver(int result) | |
{ | |
if ((int) result == 88 || (int) result == 79) //if X or O won | |
{ | |
printf("\nGAME OVER!\nPlayer %c is the winner!!\n", (char) result); | |
return 1; | |
} | |
else if (result == 1) //tie | |
{ | |
printf("\nIt's a tie!!!\n"); | |
return 1; | |
} | |
else //Should never happen | |
{ | |
printf("\nError in Game Over. Wrong result passed to fn.\n"); | |
return 0; | |
} | |
} | |
/*------------CHANGE PLAYER: Changes the player whose turn it is, then prompts for the current player's move.------------*/ | |
//Input: (char *player) the char representing the current player. Must be "X" or "O", aka (char) 88 or (char) 79. | |
//Output: (char) a char representing the NEW current player. Must be "X" or "O", aka (char) 88 or (char) 79. | |
char changePlayer(char player) | |
{ | |
if (player == 88) //X | |
{ | |
player = 79; | |
} | |
else if (player == 79) //O | |
{ | |
player = 88; | |
} | |
else //Should never happen | |
{ | |
printf("ERROR IN MOVE: Wrong player passed"); | |
} | |
return player; | |
} | |
/*------------PROMPT MOVE: Prompts for the current player's move.------------*/ | |
/* | |
Input: | |
1. (char *board) the current board state as a pointer to allocated memory (must be writable). | |
2. (char *player) the char representing the current player. Must be "X" or "O", aka (char) 88 or (char) 79. | |
Output: | |
(int) an integer between 0 and 8 (inclusive) represnting the space on the board that the current player | |
wants to play in. | |
*/ | |
int promptMove(char *board, char player) | |
{ | |
printf("Player %c, which space would you like to play?: ", player); | |
int last = 41; //int value of ASCII character; used to check for double newlines & quits | |
//loop to check validity of submission | |
while (1 == 1) | |
{ | |
int space; //int (0-8); the space on the board that the player has selected | |
int input; //int value of ASCII character; the immediate, most recent typed value | |
int answer = 0; //int value of ASCII character;where input goes if its not garbage. | |
while ((input = getchar()) != EOF && input != '\n') //Toss newlines and EOF | |
//NOTE: Need to make this while loop more robust. I want it to only accept one char at a time & to toss ANSI escape codes, but haven't figured it out yet. Something with fgets, it sounds like. | |
{ | |
if (answer == 0 && input >= 97 && input <= 105) //Check if it's an ASCII char btwn 'a' and 'i' | |
{ | |
answer = input; | |
space = answer - 97; //translate ASCII code to space in board array | |
if (board[space] >= 97 && board[space] <= 105) //check if that space has been played | |
{ | |
return space; | |
} | |
else | |
{ | |
printBoard(board); | |
printf("\nThat space is taken already! Please try again:"); | |
} | |
} | |
else if (input == 113 || input == 81) //quit | |
{ | |
last = input; | |
printf("\nAre you sure you would like to quit? (y/n)\n"); | |
} | |
else //they entered something weird | |
{ | |
if ((last == 81 || last == 113) && (input == 89 || input == 121)) //if last key was qQ and this is yY, quit | |
{ | |
printf("\nQuitting game...\n"); | |
exit(0); | |
} | |
printBoard(board); | |
printf("Type in the letter of the space you want to play in.\nIt must be a lowercase letter between 'a' and 'i'.\n------\nPlayer %c, please try again:", | |
player); | |
} | |
} | |
} | |
} | |
/*------------Checks whether a win has occurred------------*/ | |
/* | |
Input: Current board state (see printBoard above, input is identical) | |
Output: | |
- If someone won, the int of the char representing that player. Must be 88 (X) or 79 (O). | |
- If the board is full but no win happened (aka a tie), return 1. | |
- If no win yet, return 0. | |
*/ | |
int checkGame(char *board) | |
{ | |
int tie = 0; | |
for (int i = 0; i <= strlen(board); i ++) | |
{ | |
//case: horizontal win | |
if (i % 3 == 0 && board[i] == board[i + 1] && board[i] == board[i + 2]) | |
{ | |
return (int) board[i]; | |
} | |
//case: vertical win | |
else if (i <= 2 && board[i] == board[i + 3] && board[i] == board[i + 6]) | |
{ | |
return (int) board[i]; | |
} | |
//case: diagonal win | |
if (i == 0 || i == 2) | |
{ | |
int add; | |
if (i == 0) | |
{ | |
add = 4; | |
} | |
else if (i == 2) | |
{ | |
add = 2; | |
} | |
else //should never happen | |
{ | |
printf("\nERROR in Board Check Function!!!\n"); | |
return 0; | |
} | |
if (board[i] == board[i + add] && board[i] == board[i + (2 * add)]) | |
{ | |
return (int) board[i]; | |
} | |
} | |
//counting filled spaces; if all spaces are filled, game's over (tie) | |
if (board[i] == 88 || board[i] == 79) | |
{ | |
tie = tie + 1; | |
} | |
if (tie > 8) | |
{ | |
return 1; | |
} | |
} | |
return 0; | |
} | |
int main(void) | |
{ | |
//Declare variables & allocate memory | |
char playerChar = (char) 88; //current player | |
char *boardState = "abcdefghi"; //initial board state | |
int currMove = 0; //the space played in most recently (Current) | |
int game = 0; //boolean for whether the game is still running | |
char *oldBoard = malloc(10 * sizeof(char)); //old board state, just storage | |
if (oldBoard == NULL) | |
{ | |
return 1; | |
} | |
char *newBoard = malloc(10 * sizeof(char)); //new board state (Current) | |
if (newBoard == NULL) | |
{ | |
return 1; | |
} | |
//Assign correct initial values to old & new board states | |
strncpy(oldBoard, boardState, 11); | |
strncpy(newBoard, boardState, 11); | |
//The big loop of play. Continues as play occurs, until game ends. | |
while (game == 0) | |
{ | |
printBoard(newBoard); | |
playerChar = changePlayer(playerChar); | |
currMove = promptMove(newBoard, playerChar); | |
//Copy new board state into newBoard variable | |
for (int i = 0, n = strlen(boardState); i < n; i++) | |
{ | |
if (i == currMove) | |
{ | |
newBoard[i] = playerChar; | |
} | |
else | |
{ | |
newBoard[i] = oldBoard[i]; | |
} | |
} | |
strncpy(oldBoard, newBoard, 11); | |
game = checkGame(newBoard); | |
} | |
printBoard(newBoard); | |
return gameOver(game); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment