From aba952c8a128243d3a580924066ba8d4acbaf53c Mon Sep 17 00:00:00 2001 From: Amber Date: Tue, 23 Feb 2021 15:15:11 -0500 Subject: [PATCH] Initial commit; 2017 me stupidly didn't use free(), so that needs fixing. Fixed memory issue and did some cleanup Removed VS code trash --- Dockerfile | 6 + arghandler.c => src/arghandler.c | 37 +++-- arghandler.h => src/arghandler.h | 13 +- connectfour.c => src/connectfour.c | 124 ++++++++++----- file_utils.c => src/file_utils.c | 2 +- file_utils.h => src/file_utils.h | 2 +- gamelogic.c => src/gamelogic.c | 248 +++++++++++++++++++---------- gamelogic.h => src/gamelogic.h | 16 +- 8 files changed, 298 insertions(+), 150 deletions(-) create mode 100644 Dockerfile rename arghandler.c => src/arghandler.c (76%) rename arghandler.h => src/arghandler.h (81%) rename connectfour.c => src/connectfour.c (74%) rename file_utils.c => src/file_utils.c (99%) rename file_utils.h => src/file_utils.h (98%) rename gamelogic.c => src/gamelogic.c (70%) rename gamelogic.h => src/gamelogic.h (93%) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a69172a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM gcc:8.4.0 + +WORKDIR /opt +COPY src/** /opt +RUN gcc -std=c11 -o connectfour connectfour.c file_utils.c gamelogic.c arghandler.c +CMD ["./connectfour"] \ No newline at end of file diff --git a/arghandler.c b/src/arghandler.c similarity index 76% rename from arghandler.c rename to src/arghandler.c index 213fbe6..2dad9e5 100644 --- a/arghandler.c +++ b/src/arghandler.c @@ -3,7 +3,7 @@ #include "arghandler.h" /************************************************************************************ -* @author Scoots +* @author Amber * @version 3/03/2017 * @see arghandler.h * @@ -53,21 +53,20 @@ int winlen; /* * Saved filename for loading. */ -char* loadFile; +char *loadFile; struct argp_option options[] = { - { "width", 'w', "WIDTH", 0, "Width dimension for board." }, - { "height", 'h', "HEIGHT", 0, "Height dimension for board." }, - { "square", 's', "SQUARE", 0, "Dimensions for a square board (width and height will be overrided)." }, - { "connect", 'c', "CONNECT", 0, "Length to win the game." }, - { "load", 'l', "LOAD", 0, "Load a previous saved game." }, - { 0 } -}; + {"width", 'w', "WIDTH", 0, "Width dimension for board."}, + {"height", 'h', "HEIGHT", 0, "Height dimension for board."}, + {"square", 's', "SQUARE", 0, "Dimensions for a square board (width and height will be overrided)."}, + {"connect", 'c', "CONNECT", 0, "Length to win the game."}, + {"load", 'l', "LOAD", 0, "Load a previous saved game."}, + {0}}; /* * Required arguments for the argp struct. */ -struct argp argp = { options, parse_opt, args_doc, doc }; +struct argp argp = {options, parse_opt, args_doc, doc}; /* * Argument values for flags. @@ -81,9 +80,11 @@ struct arguments arguments; * @param arg, the argument being passed. * @param state, the state of parser. */ -error_t parse_opt(int key, char* arg, struct argp_state *state) { +error_t parse_opt(int key, char *arg, struct argp_state *state) +{ struct arguments *arguments = state->input; - switch (key) { + switch (key) + { case 'w': arguments->width = atoi(arg); break; @@ -110,9 +111,10 @@ error_t parse_opt(int key, char* arg, struct argp_state *state) { * @param argc, number of command line arguments. * @param argv, the command line arguments. */ -void setup(int argc, char** argv) { - wid= 0; - hei= 0; +void setup(int argc, char **argv) +{ + wid = 0; + hei = 0; sqr = 0; winlen = 0; loadFile = NULL; @@ -123,8 +125,9 @@ void setup(int argc, char** argv) { hei = arguments.height; sqr = arguments.square; winlen = arguments.winL; - - if (arguments.loadFile != NULL) { + + if (arguments.loadFile != NULL) + { loadFile = arguments.loadFile; } } diff --git a/arghandler.h b/src/arghandler.h similarity index 81% rename from arghandler.h rename to src/arghandler.h index c903df4..0a6d144 100644 --- a/arghandler.h +++ b/src/arghandler.h @@ -3,7 +3,7 @@ #include /************************************************************************************ -* @author Scoots +* @author Amber * @version 3/03/2017 * @see argp.h * @@ -33,27 +33,28 @@ int winlen; /* * Saved filename for loading. */ -char* loadFile; +char *loadFile; /* * Argument values for flags. */ -struct arguments { +struct arguments +{ int width; int height; int square; int winL; - char* loadFile; + char *loadFile; }; /* * Function that sets up values post-parsing. */ -error_t parse_opt(int key, char* arg, struct argp_state *state); +error_t parse_opt(int key, char *arg, struct argp_state *state); /* * Parses arguments. */ -void setup(int argc, char** argv); +void setup(int argc, char **argv); #endif diff --git a/connectfour.c b/src/connectfour.c similarity index 74% rename from connectfour.c rename to src/connectfour.c index 3540224..3587c9e 100644 --- a/connectfour.c +++ b/src/connectfour.c @@ -5,8 +5,8 @@ #include "arghandler.h" /************************************************************************************ -* @author Scoots -* @version 3/03/2017 +* @author Amber +* @version 2/23/2021 * @see gamelogic.h * @see arghandler.h * @@ -25,89 +25,117 @@ * @param argv, the command line arguments. * @return 0 if the operation failed and 1 if it succeeded. */ -int main(int argc, char** argv) { +int main(int argc, char **argv) +{ // Variables and array setup - char* input = malloc(100 * sizeof(char)); + char *input = malloc(100 * sizeof(char)); int player = 1; setup(argc, argv); // Fixes invalid height or width arguments - if (hei <= 0 || hei > 2147483647 || wid <= 0 || wid > 2147483647) { + if (hei <= 0 || hei > 2147483647 || wid <= 0 || wid > 2147483647) + { setHeight(7); setWidth(7); } - else { + else + { setHeight(hei); setWidth(wid); } // Fixes invalid win length arguments - if (winlen <= 0 || winlen > 2147483647) { + if (winlen <= 0 || winlen > 2147483647) + { setWinLength(4); } - else { + else + { setWinLength(winlen); } - + // Fixes invalid square dimension arguments - if (sqr > 0 && sqr <= 2147483647) { + if (sqr > 0 && sqr <= 2147483647) + { setHeight(sqr); setWidth(sqr); } // Either starts new game or loads from argument printf("%sWelcome to Connect Four!\nType 'save' to save, 'load' to load, and 'quit' to quit.\n%s", "\x1B[32m", "\033[0m"); - if (loadFile != NULL) { - if (loadGame(loadFile) == 0) { + if (loadFile != NULL) + { + if (loadGame(loadFile) == 0) + { printf("\nInvalid file.\n"); return 0; } printBoard(); - } else { + } + else + { populateBoard(); printBoard(); } // While loop for the game logic - while (1) { + while (1) + { // Checks if player 1 has won - if (checkWin('o') == 1) { + if (checkWin('o') == 1) + { printf("Player 1 wins!\n"); printf("Would you like to play again? Type 'yes' for yes or 'no' for no.\n"); - while (1) { + while (1) + { scanf("%s", input); - if ((strcmp("yes", input) == 0)) { + if ((strcmp("yes", input) == 0)) + { printf("\n"); populateBoard(); player = 1; printBoard(); break; - } - if ((strcmp("no", input) == 0)) { + } + if ((strcmp("no", input) == 0)) + { + free(input); + clean(); printf("\n"); return 1; - } else { + } + else + { printf("Invalid input.\n"); continue; } - } + } } - + // Checks if player 2 has won - if (checkWin('x') == 1) { + if (checkWin('x') == 1) + { printf("Player 2 wins!\n"); printf("Would you like to play again? Type 'yes' for yes or 'no' for no.\n"); - while (1) { + while (1) + { scanf("%s", input); - if ((strcmp("yes", input) == 0)) { + if ((strcmp("yes", input) == 0)) + { populateBoard(); player = 1; printBoard(); printf("\n"); break; - } if ((strcmp("no", input) == 0)) { + } + if ((strcmp("no", input) == 0)) + { + free(input); + clean(); return 1; - } else { + } + else + { printf("Invalid input.\n"); continue; } @@ -118,14 +146,18 @@ int main(int argc, char** argv) { printf("\nPlayer %d's turn.\n", player); printf("Input a column (from 1 to %d) to place a token:\n", width); scanf("%s", input); - + // For quitting - if (strcmp("quit", input) == 0) { + if (strcmp("quit", input) == 0) + { + free(input); + clean(); return 1; } // Saving functionality - if (strcmp("save", input) == 0) { + if (strcmp("save", input) == 0) + { printf("Input a filename:\n"); scanf("%s", input); saveGame(input); @@ -134,13 +166,17 @@ int main(int argc, char** argv) { } // Loading functionality - if (strcmp("load", input) == 0) { + if (strcmp("load", input) == 0) + { printf("Input a filename:\n"); scanf("%s", input); - if (loadGame(loadFile) == 0) { + if (loadGame(loadFile) == 0) + { printf("\nInvalid file.\n"); continue; - } else { + } + else + { printBoard(); printf("\nGame loaded.\n"); continue; @@ -148,24 +184,32 @@ int main(int argc, char** argv) { } // Checks to make sure input is valid - if (atoi(input) < 1 || atoi(input) > width) { + if (atoi(input) < 1 || atoi(input) > width) + { printf("Invalid input. Input another column:\n"); continue; } - + // Checks to make sure input is valid - if (placeChip(atoi(input) - 1, player) == 0) { + if (placeChip(atoi(input) - 1, player) == 0) + { printf("Invalid input. Input another column:\n"); - } else { - if (player == 1) { + } + else + { + if (player == 1) + { player = 2; } - else { + else + { player = 1; } printBoard(); } } - + + free(input); + clean(); return 1; } diff --git a/file_utils.c b/src/file_utils.c similarity index 99% rename from file_utils.c rename to src/file_utils.c index fa64c56..d1869f7 100644 --- a/file_utils.c +++ b/src/file_utils.c @@ -4,7 +4,7 @@ #include "file_utils.h" /************************************************************************************ -* @author Scoots +* @author Amber * @version 3/03/2017 * @see file_utils.h * diff --git a/file_utils.h b/src/file_utils.h similarity index 98% rename from file_utils.h rename to src/file_utils.h index 182a8be..e4a1b84 100644 --- a/file_utils.h +++ b/src/file_utils.h @@ -2,7 +2,7 @@ #define FILE_UTILS /************************************************************************************ -* @author Scoots +* @author Amber * @version 3/03/2017 * * Header file for file utilities for reading in a file to an array and then diff --git a/gamelogic.c b/src/gamelogic.c similarity index 70% rename from gamelogic.c rename to src/gamelogic.c index 7ead9e7..19c5c1b 100644 --- a/gamelogic.c +++ b/src/gamelogic.c @@ -5,8 +5,8 @@ #include /************************************************************************************ -* @author Scoots -* @version 3/03/2017 +* @author Amber +* @version 2/23/2021 * @see gamelogic.h * * Implementation for the Connect Four game logic. Includes all of the functions @@ -19,7 +19,7 @@ /* * Doubly array that will store the game board. */ -char** gameBoard; +char **gameBoard; /* * Height of the game board. @@ -43,7 +43,8 @@ int winLength; * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int setHeight(int h) { +int setHeight(int h) +{ height = h; return 1; } @@ -55,7 +56,8 @@ int setHeight(int h) { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int setWidth(int w) { +int setWidth(int w) +{ width = w; return 1; } @@ -67,7 +69,8 @@ int setWidth(int w) { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int setWinLength(int l) { +int setWinLength(int l) +{ winLength = l; return 1; } @@ -78,20 +81,28 @@ int setWinLength(int l) { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int printBoard() { - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - if (gameBoard[i][j] == 'o') { - printf("\x1b[34m%c\x1b[0m", gameBoard[i][j]); - } else if (gameBoard[i][j] == 'x') { - printf("\x1b[31m%c\x1b[0m", gameBoard[i][j]); - } else { - printf("%c", gameBoard[i][j]); +int printBoard() +{ + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + if (gameBoard[i][j] == 'o') + { + printf("\x1b[34m%c\x1b[0m", gameBoard[i][j]); + } + else if (gameBoard[i][j] == 'x') + { + printf("\x1b[31m%c\x1b[0m", gameBoard[i][j]); + } + else + { + printf("%c", gameBoard[i][j]); } } printf("\n"); } - + return 1; } @@ -101,17 +112,21 @@ int printBoard() { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int populateBoard() { - gameBoard = malloc(sizeof(char*) * height); - for (int i = 0; i < height; i++) { +int populateBoard() +{ + gameBoard = malloc(sizeof(char *) * height); + for (int i = 0; i < height; i++) + { gameBoard[i] = malloc(sizeof(char) * width); } - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { gameBoard[i][j] = '*'; } } - + return 1; } @@ -125,25 +140,33 @@ int populateBoard() { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int placeChip(int col, int p) { +int placeChip(int col, int p) +{ // Handles bad arguments - if (col > width - 1 || col < 0) { + if (col > width - 1 || col < 0) + { return 0; } // Checks to make sure the move is valid and places if so - for (int i = height - 1; i >= 0; i--) { - if (i > 0 && (gameBoard[i][col] == 'o' || gameBoard[i][col] == 'x')) { + for (int i = height - 1; i >= 0; i--) + { + if (i > 0 && (gameBoard[i][col] == 'o' || gameBoard[i][col] == 'x')) + { continue; } - else if (i == 0 && gameBoard[i][col] != '*') { + else if (i == 0 && gameBoard[i][col] != '*') + { return 0; } - else { - if (p == 1) { + else + { + if (p == 1) + { gameBoard[i][col] = 'o'; } - if (p == 2) { + if (p == 2) + { gameBoard[i][col] = 'x'; } break; @@ -161,20 +184,21 @@ int placeChip(int col, int p) { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int saveGame(char* filename) { +int saveGame(char *filename) +{ // Variables and character array setup - char* buffer; + char *buffer; int count = 33; buffer = malloc((sizeof(char) * width * height) + (33 * sizeof(char))); - char* widthVal = malloc(10 * sizeof(char)); - char* heightVal = malloc(10 * sizeof(char)); - char* winVal = malloc(10 * sizeof(char)); - + char *widthVal = malloc(10 * sizeof(char)); + char *heightVal = malloc(10 * sizeof(char)); + char *winVal = malloc(10 * sizeof(char)); + // Stores board parameter and win length as strings sprintf(widthVal, "%010d", width); sprintf(heightVal, "%010d", height); sprintf(winVal, "%010d", winLength); - + /* Copies the board parameters and win length character by character to the buffer to be saved to memory */ buffer[0] = widthVal[0]; @@ -212,12 +236,15 @@ int saveGame(char* filename) { buffer[32] = '\n'; // Saves the state of the board to the buffer - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { buffer[count] = gameBoard[i][j]; count++; } - if (count >(width * height + 32)) { + if (count > (width * height + 32)) + { break; } } @@ -227,6 +254,11 @@ int saveGame(char* filename) { // Writes the buffer into memory. write_file(filename, buffer, (sizeof(char) * width * height) + (33 * sizeof(char))); + // Free up reserved memory. + free(widthVal); + free(heightVal); + free(winVal); + return 1; } @@ -239,14 +271,16 @@ int saveGame(char* filename) { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int loadGame(char* filename) { +int loadGame(char *filename) +{ // Variables - char* buffer; + char *buffer; int count = 33; - char* sub; - + char *sub; + // Reads in the previous game to memory - if (read_file(filename, &buffer) == 0) { + if (read_file(filename, &buffer) == 0) + { return 0; } @@ -263,13 +297,18 @@ int loadGame(char* filename) { populateBoard(); // Copies past game's state to board. - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { gameBoard[i][j] = buffer[count]; count++; } } + // Free up reserved memory. + free(sub); + return 1; } @@ -281,32 +320,41 @@ int loadGame(char* filename) { * @return 0 if the player passed has not won, and 1 if the * player passed has won. */ -int checkWin(char p) { +int checkWin(char p) +{ // Variables for the diagonal check algorithm int row = 0; int col = 0; - + // Handles 1 by 1 boards - if (height == 1 && width == 1 && winLength == 1 ) { - if (gameBoard[0][0] == p) { + if (height == 1 && width == 1 && winLength == 1) + { + if (gameBoard[0][0] == p) + { return 1; } - else { + else + { return 0; } } - - + // Checks horizontally int count = 0; - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - if (gameBoard[i][j] == p) { + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + if (gameBoard[i][j] == p) + { count++; - } else { + } + else + { count = 0; } - if (count == winLength) { + if (count == winLength) + { return 1; } } @@ -315,68 +363,88 @@ int checkWin(char p) { // Checks vertically count = 0; - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - if (gameBoard[j][i] == p) { + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + if (gameBoard[j][i] == p) + { count++; - } else { + } + else + { count = 0; } - if (count == winLength) { + if (count == winLength) + { return 1; } } count = 0; } - + // Checks negative slope diagonal count = 0; - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { row = i; col = j; count = 0; - while (row < height && col < width) { - if (gameBoard[row][col] == p) { + while (row < height && col < width) + { + if (gameBoard[row][col] == p) + { count++; row++; col++; - } else { + } + else + { row++; col++; count = 0; } - if (count == winLength) { + if (count == winLength) + { return 1; } } } } - + // Checks positive slope diagonal count = 0; - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { row = i; col = j; count = 0; - while (row >= 0 && col < width) { - if (gameBoard[row][col] == p) { + while (row >= 0 && col < width) + { + if (gameBoard[row][col] == p) + { count++; row--; col++; - } else { + } + else + { row--; col++; count = 0; } - if (count == winLength) { + if (count == winLength) + { return 1; } } } } - + return 0; } @@ -390,7 +458,27 @@ int checkWin(char p) { * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int modifyPostition(int row, int col, char c) { +int modifyPostition(int row, int col, char c) +{ gameBoard[row][col] = c; return 1; } + +/** +* Frees up any reserved memory from +* the game session. +*/ +int clean() +{ + if (gameBoard != NULL) + { + free(gameBoard); + for (int i = 0; i < height; i++) + { + if (gameBoard[i] != NULL) + { + free(gameBoard[i]); + } + } + } +} diff --git a/gamelogic.h b/src/gamelogic.h similarity index 93% rename from gamelogic.h rename to src/gamelogic.h index 00bb119..42f9505 100644 --- a/gamelogic.h +++ b/src/gamelogic.h @@ -2,8 +2,8 @@ #define GAME_LOGIC /************************************************************************************ -* @author Scoots -* @version 3/03/2017 +* @author Amber +* @version 2/23/2021 * * Header file for the Connect Four game logic. *************************************************************************************/ @@ -11,7 +11,7 @@ /* * Doubly array that will store the game board. */ -char** gameBoard; +char **gameBoard; /* * Height of the game board. @@ -91,7 +91,7 @@ int placeChip(int col, int p); * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int saveGame(char* filename); +int saveGame(char *filename); /* * Loads a previous game. Reloads a previous game's @@ -102,7 +102,7 @@ int saveGame(char* filename); * @return 0 if the operation failed, and 1 if the operation * succeeded. */ -int loadGame(char* filename); +int loadGame(char *filename); /* * Checks if the current state of the board is a victory @@ -126,4 +126,10 @@ int checkWin(char p); */ int modifyPostition(int row, int col, char c); +/** +* Frees up any reserved memory from +* the game session. +*/ +int clean(); + #endif