diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-13 18:00:17 +1100 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-13 18:00:17 +1100 |
| commit | 98cef5e9a772602d42acfcf233838c760424db9a (patch) | |
| tree | 5277fa1d7cc0a69a0f166fcbf10fd320f345f049 /comp1511/minesweeper | |
initial commit
Diffstat (limited to 'comp1511/minesweeper')
| -rw-r--r-- | comp1511/minesweeper/minesweeper.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/comp1511/minesweeper/minesweeper.c b/comp1511/minesweeper/minesweeper.c new file mode 100644 index 0000000..8a892ed --- /dev/null +++ b/comp1511/minesweeper/minesweeper.c @@ -0,0 +1,326 @@ +// Assignment 1 20T1 COMP1511: Minesweeper +// minesweeper.c + +#include <stdio.h> +#include <stdbool.h> + +// Possible square states. +#define VISIBLE_SAFE 0 +#define HIDDEN_SAFE 1 +#define HIDDEN_MINE 2 +#define EXPLODED_MINE 3 + +// The size of the starting grid. +#define SIZE 8 + +// The possible command codes. +#define DETECT_ROW 1 +#define DETECT_COL 2 +#define DETECT_SQUARE 3 +#define REVEAL_SQUARE 4 +#define GAMEPLAY_MODE 5 +#define DEBUG_MODE 6 +#define REVEAL_RADIAL 7 + +// All game states +#define GAME_LOST -1 +#define GAME_ONGOING 0 +#define GAME_WON 1 + +// Miscellaneous values +// Max hints: +#define MAX_HINTS 3 +// Start in debug mode (non-zero for true): +#define DEBUG_DEFAULT 1 + +// Out of bounds check for x and y values. True if valid. +static bool is_valid(const int x, const int y) { + if (x > SIZE - 1 || x < 0) { + return false; + } + if (y > SIZE - 1 || y < 0) { + return false; + } + return true; +} + +// Searches entire minefield for a value. True if found. +static bool search_minefield(const int minefield[SIZE][SIZE], const int search) { + for (int i = 0; i < SIZE; ++i) { + for (int j = 0; j < SIZE; ++j) { + if (minefield[i][j] == search) { + return true; + } + } + } + return false; +} + +// Returns the prior defined game state. +static int get_game_state(const int minefield[SIZE][SIZE]) { + if (search_minefield(minefield, EXPLODED_MINE)) { + return GAME_LOST; + } + else if (search_minefield(minefield, HIDDEN_SAFE)) { + return GAME_ONGOING; + } + return GAME_WON; +} + +// Set the entire minefield to HIDDEN_SAFE. +static void initialise_field(int minefield[SIZE][SIZE]) { + for (int i = 0; i < SIZE; ++i) { + for (int j = 0; j < SIZE; ++j) { + minefield[i][j] = HIDDEN_SAFE; + } + } +} + + +// Prints the count of mines per row. +static void detect_row(const int minefield[SIZE][SIZE], const int arg) { + int count = 0; + for (int i = 0; i < SIZE; ++i) { + if (minefield[arg][i] == HIDDEN_MINE) { + ++count; + } + } + printf("There are %d mine(s) in row %d\n", count, arg); +} + +// Prints the count of mines per column. +static void detect_column(const int minefield[SIZE][SIZE], const int arg) { + int count = 0; + for (int i = 0; i < SIZE; ++i) { + if (minefield[i][arg] == HIDDEN_MINE) { + ++count; + } + } + printf("There are %d mine(s) in column %d\n", count, arg); +} + +// Returns the count of mines within a square, drawn forwards and downwards. +static int detect_square(const int minefield[SIZE][SIZE], + int x, + int y, + int size, + int should_print) { + int count = 0; + for (int i = 0; i < size; ++i) { + for (int j = 0; j < size; ++j) { + if (!(is_valid(x + i, y + j))) { + continue; + } + if (minefield[x + i][y + j] == HIDDEN_MINE) { + ++count; + } + } } + if (should_print) { + printf("There are %d mine(s) in the square centered ", count); + printf("at row %d, column %d of size %d\n", x + 1, y + 1, size); + } + return count; +} + +// Modifies the minefield by revealing a point. Reveals adjacent if possible. +static void reveal_square(int minefield[SIZE][SIZE], + const int x, + const int y) { + if (minefield[x][y] == HIDDEN_MINE) { + minefield[x][y] = EXPLODED_MINE; + return; + } + int tmpx = x - 1; + int tmpy = y - 1; + if (detect_square(minefield, tmpx, tmpy, 3, 0)) { + minefield[x][y] = VISIBLE_SAFE; + return; + } + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + if (is_valid(tmpx + i, tmpy + j)) { + minefield[tmpx + i][tmpy + j] = VISIBLE_SAFE; + } + } + } +} + +// Print out the internal values of the minefield. +// Exploded mines are printed as 'HIDDEN_MINE' int to comply with requirement. +static void print_debug_minefield(const int minefield[SIZE][SIZE]) { + for (int i = 0; i < SIZE; ++i) { + for (int j = 0; j < SIZE; ++j) { + if (minefield[i][j] == EXPLODED_MINE) { + printf("%d ", HIDDEN_MINE ); + } else { + printf("%d ", minefield[i][j]); + } + } + printf("\n"); + } +} + +// Prints the minefield in the "gameplay" style. +// This includes the game state face ASCII glyph. +static void print_gameplay_minefield(const int minefield[SIZE][SIZE], + const int game_state) { + if (game_state == GAME_LOST) { + printf("xx\n/\\\n"); + } else { + printf("..\n\\/\n"); + } + printf(" "); + for (int i = 0; i < SIZE; ++i) { + printf("%d%d ", i / 10, i % 10); + } + printf("\n "); + for (int i = 0; i < SIZE; ++i) { + printf("---"); + } + printf("-\n"); + for (int i = 0; i < SIZE; ++i) { + printf("%d%d |", i / 10, i % 10); + for (int j = 0; j < SIZE; ++j) { + int point = minefield[i][j]; + if (point >= HIDDEN_MINE && game_state == GAME_LOST) { + printf("()"); + } + else if (point >= EXPLODED_MINE && game_state == GAME_WON) { + printf("##"); + } + else if (point == HIDDEN_SAFE) { + printf("##"); + } + else if (point == HIDDEN_MINE) { + printf("##"); + } + else if (point == VISIBLE_SAFE) { + int adjacent = detect_square(minefield, i - 1, j - 1, 3, 0); + if (adjacent) { + printf("%d%d", adjacent / 10, adjacent % 10); + } else { + printf(" "); + } + } + if (j < SIZE - 1) { + printf(" "); + } else { + printf("|"); + } + } + printf("\n"); + } + printf(" "); + for (int i = 0; i < SIZE; ++i) { + printf("---"); + } + printf("-\n"); +} + +// Wrapper function for the debug and game mode styles of printing. +static void print_minefield(const int minefield[SIZE][SIZE], + const int debug_mode, + const int game_state) { + if (debug_mode) { + print_debug_minefield(minefield); + } else { + print_gameplay_minefield(minefield, game_state); + } +} + +int main(void) { + int minefield[SIZE][SIZE]; + initialise_field(minefield); + + printf("Welcome to minesweeper!\nHow many mines? "); + int pair_count = 0; + scanf("%d", &pair_count); + + printf("Enter pairs:\n"); + for (int i = 0; i < pair_count; ++i) { + int x = 0, y = 0; + scanf("%d %d", &x, &y); + if (!is_valid(x, y)) { + continue; + } + minefield[x][y] = HIDDEN_MINE; + } + + printf("Game Started\n"); + int game_state = GAME_ONGOING; + int hints = MAX_HINTS; + int debug_mode = DEBUG_DEFAULT; + while(!(game_state = get_game_state(minefield))) { + print_minefield(minefield, debug_mode, game_state); + int command = 0; + if ((scanf(" %d", &command) <= 0)) { + return 0; + } + switch (command) { + case DETECT_ROW : { + int row = 0; + scanf(" %d", &row); + if (hints <= 0) { + printf("Help already used\n"); + break; + } + detect_row(minefield, row); + --hints; + break; + } + case DETECT_COL : { + int col = 0; + scanf(" %d", &col); + if (hints <= 0) { + printf("Help already used\n"); + break; + } + detect_column(minefield, col); + --hints; + break; + } + case DETECT_SQUARE : { + int x = 0; + int y = 0; + int size = 0; + scanf("%d %d %d", &x, &y, &size); + if (hints <= 0) { + printf("Help already used\n"); + break; + } + detect_square(minefield, x - 1, y - 1, size, 1); + --hints; + break; + } + case REVEAL_SQUARE : { + int x = 0; + int y = 0; + scanf("%d %d", &x, &y); + reveal_square(minefield, x , y); + break; + } + case GAMEPLAY_MODE : { + debug_mode = 0; + printf("Gameplay mode activated\n"); + break; + } + case DEBUG_MODE : { + debug_mode = 1; + printf("Debug mode activated\n"); + break; + } + } + } + // Early exit if the game is suspended. + if (game_state == GAME_ONGOING) { + return 0; + } + + if (game_state == GAME_LOST) { + printf("Game over\n"); + } else { + printf("Game Won!\n"); + } + print_minefield(minefield, debug_mode, game_state); + return 0; +} |
