The problem I’m encountering involves implementing test cases for a Minesweeper game written in C. I’ve written a function called run_tests
to execute the test cases provided, but I’m having difficulty getting them to run correctly.
The test cases include both input and expected output scenarios, covering various game actions such as starting a game, opening cells, flagging cells, and quitting the game. Each test case provides an expected output grid after certain actions are performed.
My main challenge is figuring out how to modify my run_tests
function to properly execute these test cases and compare the actual output with the expected output. I’m also unsure about the best approach to structure my test cases within the function and how to handle any errors or discrepancies between the actual and expected outputs.
Overall, I’m seeking guidance on how to effectively implement these test cases in my Minesweeper game code and ensure that they run smoothly to validate the game’s functionality.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// Constants
#define DEFAULT_SIZE 9
#define DEFAULT_MINES 10
#define DEFAULT_SEED 0
// Color codes for output
#define COLOR_RED "33[31m"
#define COLOR_YELLOW "33[33m"
#define COLOR_BG_RED "33[41m"
#define COLOR_RESET "33[0m"
// Field characters
#define CHAR_CLOSED '░'
#define CHAR_OPEN '·'
#define CHAR_FLAG '¶'
#define CHAR_MINE '@'
// Structs
typedef struct {
int bomb;
int opened;
int flagged;
int adjacent_mines;
} Cell;
typedef struct {
Cell **cells;
int height;
int width;
int mines;
int remaining_flags;
} Board;
// Function Prototypes
void parse_arguments(int argc, char *argv[], int *height, int *width, int *mines, int *seed);
void initialize_board(Board *board, int height, int width, int mines);
void generate_map(Board *board, int start_row, int start_col, int seed);
void open_cell(Board *board, int row, int col);
void flag_cell(Board *board, int row, int col);
void dump_board(Board *board);
void save_game(Board *board, const char *filename);
void load_game(Board *board, const char *filename);
void print_board(Board *board);
void free_board(Board *board);
void game_loop(Board *board);
void error_message(const char *message, int exit_code);
int check_win(Board *board);
void run_tests(const char *test_file);
int main(int argc, char *argv[]) {
if (argc > 1 && strcmp(argv[1], "--test") == 0) {
run_tests(argv[2]);
} else {
int height = DEFAULT_SIZE, width = DEFAULT_SIZE, mines = DEFAULT_MINES, seed = DEFAULT_SEED;
Board board;
parse_arguments(argc, argv, &height, &width, &mines, &seed);
srand(seed);
initialize_board(&board, height, width, mines);
printf("Welcome to ESP Minesweeper!n");
printf("Chosen field size: %d x %d.n", height, width);
printf("After map generation %d mines will be hidden in the playing field.n", mines);
printf(" > ");
game_loop(&board);
free_board(&board);
}
return 0;
}
void error_message(const char *message, int exit_code) {
fprintf(stderr, "%sn", message);
exit(exit_code);
}
void parse_arguments(int argc, char *argv[], int *height, int *width, int *mines, int *seed) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--size") == 0 && i + 2 < argc) {
*height = atoi(argv[++i]);
*width = atoi(argv[++i]);
if (*height <= 0 || *width <= 0) {
error_message("Error: Invalid arguments given!", 1);
}
} else if (strcmp(argv[i], "--mines") == 0 && i + 1 < argc) {
*mines = atoi(argv[++i]);
if (*mines <= 0) {
error_message("Error: Invalid arguments given!", 1);
}
} else if (strcmp(argv[i], "--seed") == 0 && i + 1 < argc) {
*seed = atoi(argv[++i]);
} else {
error_message("Error: Unknown command!", 1);
}
}
}
void initialize_board(Board *board, int height, int width, int mines) {
board->height = height;
board->width = width;
board->mines = mines;
board->remaining_flags = mines;
board->cells = malloc(height * sizeof(Cell *));
for (int i = 0; i < height; i++) {
board->cells[i] = calloc(width, sizeof(Cell));
}
}
void generate_map(Board *board, int start_row, int start_col, int seed) {
int fields_left = board->height * board->width - 1;
int mines_left = board->mines;
srand(seed);
for (int row = 0; row < board->height; row++) {
for (int col = 0; col < board->width; col++) {
if (row == start_row && col == start_col) {
board->cells[row][col].bomb = 0;
continue;
}
unsigned long long random_number = ((unsigned long long)rand() << 32) | rand();
if (random_number % fields_left < mines_left) {
board->cells[row][col].bomb = 1;
mines_left--;
} else {
board->cells[row][col].bomb = 0;
}
fields_left--;
}
}
}
void open_cell(Board *board, int row, int col) {
if (row < 0 || col < 0 || row >= board->height || col >= board->width || board->cells[row][col].opened) {
return;
}
board->cells[row][col].opened = 1;
if (board->cells[row][col].bomb) {
printf(COLOR_BG_RED "Game Over!n" COLOR_RESET);
print_board(board);
exit(0);
}
int mine_count = 0;
for (int r = row - 1; r <= row + 1; r++) {
for (int c = col - 1; c <= col + 1; c++) {
if (r >= 0 && c >= 0 && r < board->height && c < board->width && board->cells[r][c].bomb) {
mine_count++;
}
}
}
board->cells[row][col].adjacent_mines = mine_count;
if (mine_count == 0) {
for (int r = row - 1; r <= row + 1; r++) {
for (int c = col - 1; c <= col + 1; c++) {
if (r >= 0 && c >= 0 && r < board->height && c < board->width && !board->cells[r][c].opened) {
open_cell(board, r, c);
}
}
}
}
if (check_win(board)) {
printf("Congratulations! You've won!n");
print_board(board);
exit(0);
}
}
void flag_cell(Board *board, int row, int col) {
if (row < 0 || col < 0 || row >= board->height || col >= board->width || board->cells[row][col].opened) {
return;
}
board->cells[row][col].flagged = !board->cells[row][col].flagged;
board->remaining_flags += board->cells[row][col].flagged ? -1 : 1;
}
void save_game(Board *board, const char *filename) {
FILE *file = fopen(filename, "wb");
if (!file) {
error_message("Error: Failed to open file!", 1);
}
fwrite(&board->height, sizeof(int), 1, file);
fwrite(&board->width, sizeof(int), 1, file);
fwrite(&board->mines, sizeof(int), 1, file);
fwrite(&board->remaining_flags, sizeof(int), 1, file);
for (int i = 0; i < board->height; i++) {
fwrite(board->cells[i], sizeof(Cell), board->width, file);
}
fclose(file);
}
void load_game(Board *board, const char *filename) {
FILE *file = fopen(filename, "rb");
if (!file) {
error_message("Error: Failed to open file!", 1);
}
fread(&board->height, sizeof(int), 1, file);
fread(&board->width, sizeof(int), 1, file);
fread(&board->mines, sizeof(int), 1, file);
fread(&board->remaining_flags, sizeof(int), 1, file);
board->cells = malloc(board->height * sizeof(Cell *));
for (int i = 0; i < board->height; i++) {
board->cells[i] = calloc(board->width, sizeof(Cell));
fread(board->cells[i], sizeof(Cell), board->width, file);
}
fclose(file);
}
void print_board(Board *board) {
printf(" %dn", board->remaining_flags);
printf(" ");
for (int col = 0; col < board->width; col++) {
printf("=");
}
printf("n");
for (int row = 0; row < board->height; row++) {
printf("|");
for (int col = 0; col < board->width; col++) {
if (board->cells[row][col].flagged) {
printf(COLOR_RED "¶" COLOR_RESET);
} else if (board->cells[row][col].opened) {
if (board->cells[row][col].bomb) {
printf(COLOR_YELLOW "@");
} else if (board->cells[row][col].adjacent_mines > 0) {
printf("%d", board->cells[row][col].adjacent_mines);
} else {
printf("·");
}
} else {
printf("░");
}
}
printf("|n");
}
printf(" ");
for (int col = 0; col < board->width; col++) {
printf("=");
}
printf("n");
}
void free_board(Board *board) {
for (int i = 0; i < board->height; i++) {
free(board->cells[i]);
}
free(board->cells);
}
void game_loop(Board *board) {
char command[256];
while (1) {
printf("Enter a command: ");
if (!fgets(command, sizeof(command), stdin)) {
error_message("Error: Failed to read input!", 1);
}
char *cmd = strtok(command, " ");
if (strcmp(cmd, "start") == 0) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));
printf("Game started at cell (%d, %d)!n", row, col);
free_board(board);
initialize_board(board, board->height, board->width, board->mines);
generate_map(board, row, col, time(NULL));
open_cell(board, row, col);
print_board(board);
} else if (strcmp(cmd, "open") == 0) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));
open_cell(board, row, col);
print_board(board);
} else if (strcmp(cmd, "flag") == 0) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));
flag_cell(board, row, col);
print_board(board);
} else if (strcmp(cmd, "save") == 0) {
char *filename = strtok(NULL, "n");
save_game(board, filename);
printf("Game saved to %s.n", filename);
} else if (strcmp(cmd, "load") == 0) {
char *filename = strtok(NULL, "n");
free_board(board);
load_game(board, filename);
printf("Game loaded from %s.n", filename);
print_board(board);
} else {
printf("Unknown command. Try again.n");
}
}
}
int check_win(Board *board) {
for (int row = 0; row < board->height; row++) {
for (int col = 0; col < board->width; col++) {
if (!board->cells[row][col].opened && !board->cells[row][col].bomb) {
return 0;
}
}
}
return 1;
}
void run_tests(const char *test_file) {
FILE *file = fopen(test_file, "r");
if (!file) {
perror("Failed to open test file");
exit(1);
}
Board board;
int height = DEFAULT_SIZE, width = DEFAULT_SIZE, mines = DEFAULT_MINES, seed = DEFAULT_SEED;
initialize_board(&board, height, width, mines);
char command[256];
while (fgets(command, sizeof(command), file)) {
char *cmd = strtok(command, " ");
if (strcmp(cmd, "start") == 0) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));
printf("Game started at cell (%d, %d)!n", row, col);
free_board(&board);
initialize_board(&board, board.height, board.width, board.mines);
generate_map(&board, row, col, time(NULL));
open_cell(&board, row, col);
print_board(&board);
} else if (strcmp(cmd, "open") == 0) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));
open_cell(&board, row, col);
print_board(&board);
} else if (strcmp(cmd, "flag") == 0) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));
flag_cell(&board, row, col);
print_board(&board);
} else if (strcmp(cmd, "save") == 0) {
char *filename = strtok(NULL, "n");
save_game(&board, filename);
printf("Game saved to %s.n", filename);
} else if (strcmp(cmd, "load") == 0) {
char *filename = strtok(NULL, "n");
free_board(&board);
load_game(&board, filename);
printf("Game loaded from %s.n", filename);
print_board(&board);
} else {
printf("Unknown command. Try again.n");
}
}
fclose(file);
free_board(&board);
}
here are the following test cases that i want to perform all they include both input and output;
> Welcome to ESP Minesweeper!
> Chosen field size: 9 x 9.
> After map generation 10 mines will be hidden in the playing field.
? >
< quit
>
> [31m¶[0m: 0
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
test case 2;
> Welcome to ESP Minesweeper!
> Chosen field size: 9 x 9.
> After map generation 10 mines will be hidden in the playing field.
? >
< start 5 5
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░2░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< open 0 2
>
> [31m¶[0m: 10
> =========
> |░░1░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░2░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< open 0 4
>
> [31m¶[0m: 10
> =========
> |░░1░1░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░2░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< open 8 8
>
> [31m¶[0m: 10
> =========
> |░░1░1░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░21122░░|
> |111···111|
> |·········|
> |·········|
> =========
? >
< quit
>
> [31m¶[0m: 10
> =========
> |░░1░1░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░21122░░|
> |111···111|
> |·········|
> |·········|
> =========
test case3;
> Welcome to ESP Minesweeper!
> Chosen field size: 9 x 9.
> After map generation 10 mines will be hidden in the playing field.
? >
< start 3 3
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░3░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< dump
>
> [31m¶[0m: 10
> =========
> |··111····|
> |111[33m@[0m2211·|
> |[33m@[0m113[33m@[0m3[33m@[0m1·|
> |1213[33m@[0m4321|
> |·2[33m@[0m32[33m@[0m3[33m@[0m2|
> |·2[33m@[0m2113[33m@[0m2|
> |·111··111|
> |·········|
> |·········|
> =========
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░3░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< quit
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░3░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
test case 4;
> Welcome to ESP Minesweeper!
> Chosen field size: 4 x 4.
> After map generation 10 mines will be hidden in the playing field.
? >
< start 1 3
>
> [31m¶[0m: 10
> ====
> |░░░░|
> |░░░4|
> |░░░░|
> |░░░░|
> ====
? >
< open 2 1
>
> [31m¶[0m: 10
> ====
> |░░░░|
> |░░░4|
> |░7░░|
> |░░░░|
> ====
? >
< open 1 1
>
> [31m¶[0m: 10
> ====
> |░░░░|
> |░4░4|
> |░7░░|
> |░░░░|
> ====
? >
< open 0 1
>
> [31m¶[0m: 10
> ====
> |░2░░|
> |░4░4|
> |░7░░|
> |░░░░|
> ====
? >
< open 0 2
>
> [31m¶[0m: 10
> ====
> |░22░|
> |░4░4|
> |░7░░|
> |░░░░|
> ====
? >
< quit
>
> [31m¶[0m: 10
> ====
> |░22░|
> |░4░4|
> |░7░░|
> |░░░░|
> ====
test case 5;
> Welcome to ESP Minesweeper!
> Chosen field size: 9 x 9.
> After map generation 79 mines will be hidden in the playing field.
? >
< start 4 4
>
> [31m¶[0m: 79
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░8░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< quit
>
> [31m¶[0m: 79
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░8░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
test case 6;
> Welcome to ESP Minesweeper!
> Chosen field size: 9 x 9.
> After map generation 10 mines will be hidden in the playing field.
? >
< start 2 2
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░2░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< dump
>
> [31m¶[0m: 10
> =========
> |····11111|
> |111·1[33m@[0m11[33m@[0m|
> |2[33m@[0m2112232|
> |[33m@[0m3[33m@[0m212[33m@[0m2[33m@[0m|
> |1212[33m@[0m2121|
> |···111···|
> |·····111·|
> |···112[33m@[0m1·|
> |···1[33m@[0m211·|
> =========
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░2░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░░░░░░░░|
> =========
? >
< open 8 1
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░2░░░░░░|
> |░░░░░░░░░|
> |1212░░░░░|
> |···111░░░|
> |·····1░░░|
> |···112░░░|
> |···1░░░░░|
> =========
? >
< open 8 8
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░2░░░░░░|
> |░░░░░░░░░|
> |1212░2121|
> |···111···|
> |·····111·|
> |···112░1·|
> |···1░░░1·|
> =========
? >
< quit
>
> [31m¶[0m: 10
> =========
> |░░░░░░░░░|
> |░░░░░░░░░|
> |░░2░░░░░░|
> |░░░░░░░░░|
> |1212░2121|
> |···111···|
> |·····111·|
> |···112░1·|
> |···1░░░1·|
> =========
lastly i wanted to tell you that if you want i can send you my test.toml file
Usama Ali is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.