From b3b369a076fff9a896e7d26b8edeb580af0cc646 Mon Sep 17 00:00:00 2001 From: Julia Lange Date: Mon, 15 Jul 2024 18:57:53 -0700 Subject: [PATCH] Add Horizontal and Vertical win checking Adds horizontal and vertical win checking, as well as tests for such features. Adds valgrind to the flake.nix Adds test_connect4 option to Makefile --- Makefile | 10 ++++--- connect4.c | 71 +++++++++++++++++++++++++++++++++++++++++++------ connect4.h | 2 ++ flake.lock | 6 ++--- flake.nix | 4 ++- main.c | 9 ++++--- test_connect4.c | 60 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 142 insertions(+), 20 deletions(-) create mode 100644 test_connect4.c diff --git a/Makefile b/Makefile index dd5e09b..818efc3 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,16 @@ CC = gcc CFLAGS = -g -Wall -pedantic -connect4.c main.c: connect4.h +test_connect4.c connect4.c main.c: connect4.h -TARGET = connect4 CFILES = main.c connect4.c OFILES = ${CFILES:.c=.o} connect4: ${OFILES} - $(CC) $(CFLAGS) -o ${TARGET} ${OFILES} + $(CC) $(CFLAGS) -o connect4 ${OFILES} + +test_connect4: test_connect4.o connect4.o + $(CC) $(CFLAGS) -o test_connect4 test_connect4.o connect4.o clean: - rm -r ${TARGET} ${OFILES} + rm -r connect4 test_connect4 *.o diff --git a/connect4.c b/connect4.c index 7fb4b98..0b5c52d 100644 --- a/connect4.c +++ b/connect4.c @@ -14,7 +14,7 @@ struct Board *make_board(size_t height, size_t width) new_board->tile_heights = calloc(width, sizeof(*(new_board->tile_heights))); if (!new_board->tile_heights) goto out_tile_heights; - + new_board->height = height; new_board->width = width; new_board->next_player = RED; @@ -28,26 +28,81 @@ out_tilemap: return NULL; } -int drop_tile(struct Board *board, size_t drop_pos) { +void free_board(struct Board *board) +{ + free(board->tile_heights); + free(board->tilemap); + free(board); +} + +int check_for_win_horizontal(struct Board *board, size_t pos_i, size_t pos_j) +{ + enum Tile current_player = board->next_player * -1; + char in_a_row = 1; + // Right + size_t npos_i = pos_i + 1; + while (npos_i < board->width && IDX(npos_i, pos_j, board) == current_player) { + in_a_row++; + npos_i++; + if (in_a_row >= 4) + return 1; + } + // Left + npos_i = pos_i - 1; + while (npos_i < board->width && IDX(npos_i, pos_j, board) == current_player) { + in_a_row++; + npos_i--; + if (in_a_row >= 4) + return 1; + } + return 0; +} + +int check_for_win_vertical(struct Board *board, size_t pos_i, size_t pos_j) +{ + enum Tile current_player = board->next_player * -1; + char in_a_row = 1; + // Down + size_t npos_j = pos_j + 1; + while (npos_j < board->height && \ + IDX(pos_i, npos_j, board) == current_player) { + in_a_row++; + npos_j++; + if (in_a_row >= 4) + return 1; + } + return 0; +} + +int check_for_win(struct Board *board, size_t pos_i, size_t pos_j) +{ + if (check_for_win_horizontal(board, pos_i, pos_j)) + return 1; + if (check_for_win_vertical(board, pos_i, pos_j)) + return 1; + return 0; +} + +int drop_tile(struct Board *board, size_t drop_pos) +{ if (drop_pos >= board->width) return -1; size_t tower_height = board->height-board->tile_heights[drop_pos]-1; - if (tower_height < 0) + if (tower_height > board->height) return -1; - + IDX(drop_pos, tower_height, board) = board->next_player; board->tile_heights[drop_pos]++; board->next_player *= -1; - // Check if player won in separate function - - return 0; + return check_for_win(board, drop_pos, tower_height); } -void print_board(struct Board *board) { +void print_board(struct Board *board) +{ for (int j = 0; j < board->height; j++) { printf("|"); for (int i = 0; i < board->width; i++) { diff --git a/connect4.h b/connect4.h index a6cf828..38bc8eb 100644 --- a/connect4.h +++ b/connect4.h @@ -22,6 +22,8 @@ struct Board { // Returns a board struct with height and width based on parameters struct Board *make_board(size_t height, size_t width); +void free_board(struct Board *board); + // Drops a tile, returns 0 if successful, -1 if error, and 1 if the move won int drop_tile(struct Board *board, size_t drop_pos); diff --git a/flake.lock b/flake.lock index ffe3698..be5e5f0 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720768451, - "narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=", + "lastModified": 1720957393, + "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9", + "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index acd1e65..bc739d6 100644 --- a/flake.nix +++ b/flake.nix @@ -17,11 +17,13 @@ git gnumake gcc - gdb clang_16 clang-tools_16 lld_16 llvmPackages_16.libllvm + + valgrind + gdb cmake gtest diff --git a/main.c b/main.c index 4e6f967..0b18d18 100644 --- a/main.c +++ b/main.c @@ -5,12 +5,13 @@ int main(int argc, char *argv[]) { struct Board *my_board = make_board(6, 7); - while (1) { + int drop_spot = 0; + do { print_board(my_board); - int drop_spot = 0; printf("Where to drop? "); scanf("%d",&drop_spot); - drop_tile(my_board, drop_spot-1); - } + } while (!drop_tile(my_board, drop_spot-1)); + print_board(my_board); + printf("Congratulations!"); return EXIT_SUCCESS; } diff --git a/test_connect4.c b/test_connect4.c new file mode 100644 index 0000000..a49b7e2 --- /dev/null +++ b/test_connect4.c @@ -0,0 +1,60 @@ +#include "connect4.h" +#include +#include +#include + +void drop_series(struct Board *board, int *positions, size_t psize) { + for(int i = 0; i < psize; i++) { + drop_tile(board, positions[i]); + } +} + +void test_vertical_win(void) +{ + struct Board *board = make_board(4,4); + int positions[] = {0, 3, 0, 3, 0, 3}; + drop_series(board, positions, 6); + int output = drop_tile(board, 0); + assert(output == 1 && "Vertical Win"); + free_board(board); +} + +void test_left_horizontal_win(void) +{ + struct Board *board = make_board(4,4); + int positions[] = {0, 0, 1, 1, 2, 2}; + drop_series(board, positions, 6); + int output = drop_tile(board, 3); + assert(output == 1 && "Left Horizontal Win"); + free_board(board); +} + +void test_right_horizontal_win(void) +{ + struct Board *board = make_board(4,4); + int positions[] = {3, 3, 2, 2, 1, 1}; + drop_series(board, positions, 6); + int output = drop_tile(board, 0); + assert(output == 1 && "Right Horizontal Win"); + free_board(board); +} + +void test_middle_horizontal_win(void) +{ + struct Board *board = make_board(4,4); + int positions[] = {3, 3, 2, 2, 0, 0}; + drop_series(board, positions, 6); + int output = drop_tile(board, 1); + assert(output == 1 && "Middle Horizontal Win"); + free_board(board); +} + +int main(int argc, char *argv[]) +{ + test_vertical_win(); + test_left_horizontal_win(); + test_right_horizontal_win(); + test_middle_horizontal_win(); + + return EXIT_SUCCESS; +}