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
This commit is contained in:
parent
28a3188ea3
commit
b3b369a076
7 changed files with 142 additions and 20 deletions
10
Makefile
10
Makefile
|
|
@ -1,14 +1,16 @@
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -g -Wall -pedantic
|
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
|
CFILES = main.c connect4.c
|
||||||
OFILES = ${CFILES:.c=.o}
|
OFILES = ${CFILES:.c=.o}
|
||||||
|
|
||||||
connect4: ${OFILES}
|
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:
|
clean:
|
||||||
rm -r ${TARGET} ${OFILES}
|
rm -r connect4 test_connect4 *.o
|
||||||
|
|
|
||||||
71
connect4.c
71
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)));
|
new_board->tile_heights = calloc(width, sizeof(*(new_board->tile_heights)));
|
||||||
if (!new_board->tile_heights)
|
if (!new_board->tile_heights)
|
||||||
goto out_tile_heights;
|
goto out_tile_heights;
|
||||||
|
|
||||||
new_board->height = height;
|
new_board->height = height;
|
||||||
new_board->width = width;
|
new_board->width = width;
|
||||||
new_board->next_player = RED;
|
new_board->next_player = RED;
|
||||||
|
|
@ -28,26 +28,81 @@ out_tilemap:
|
||||||
return NULL;
|
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)
|
if (drop_pos >= board->width)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
size_t tower_height = board->height-board->tile_heights[drop_pos]-1;
|
size_t tower_height = board->height-board->tile_heights[drop_pos]-1;
|
||||||
|
|
||||||
if (tower_height < 0)
|
if (tower_height > board->height)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
IDX(drop_pos, tower_height, board) = board->next_player;
|
IDX(drop_pos, tower_height, board) = board->next_player;
|
||||||
|
|
||||||
board->tile_heights[drop_pos]++;
|
board->tile_heights[drop_pos]++;
|
||||||
board->next_player *= -1;
|
board->next_player *= -1;
|
||||||
|
|
||||||
// Check if player won in separate function
|
return check_for_win(board, drop_pos, tower_height);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_board(struct Board *board) {
|
void print_board(struct Board *board)
|
||||||
|
{
|
||||||
for (int j = 0; j < board->height; j++) {
|
for (int j = 0; j < board->height; j++) {
|
||||||
printf("|");
|
printf("|");
|
||||||
for (int i = 0; i < board->width; i++) {
|
for (int i = 0; i < board->width; i++) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ struct Board {
|
||||||
// Returns a board struct with height and width based on parameters
|
// Returns a board struct with height and width based on parameters
|
||||||
struct Board *make_board(size_t height, size_t width);
|
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
|
// 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);
|
int drop_tile(struct Board *board, size_t drop_pos);
|
||||||
|
|
||||||
|
|
|
||||||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -18,11 +18,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720768451,
|
"lastModified": 1720957393,
|
||||||
"narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=",
|
"narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9",
|
"rev": "693bc46d169f5af9c992095736e82c3488bf7dbb",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,13 @@
|
||||||
git
|
git
|
||||||
gnumake
|
gnumake
|
||||||
gcc
|
gcc
|
||||||
gdb
|
|
||||||
clang_16
|
clang_16
|
||||||
clang-tools_16
|
clang-tools_16
|
||||||
lld_16
|
lld_16
|
||||||
llvmPackages_16.libllvm
|
llvmPackages_16.libllvm
|
||||||
|
|
||||||
|
valgrind
|
||||||
|
gdb
|
||||||
|
|
||||||
cmake
|
cmake
|
||||||
gtest
|
gtest
|
||||||
|
|
|
||||||
9
main.c
9
main.c
|
|
@ -5,12 +5,13 @@
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct Board *my_board = make_board(6, 7);
|
struct Board *my_board = make_board(6, 7);
|
||||||
while (1) {
|
int drop_spot = 0;
|
||||||
|
do {
|
||||||
print_board(my_board);
|
print_board(my_board);
|
||||||
int drop_spot = 0;
|
|
||||||
printf("Where to drop? ");
|
printf("Where to drop? ");
|
||||||
scanf("%d",&drop_spot);
|
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;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
60
test_connect4.c
Normal file
60
test_connect4.c
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include "connect4.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue