aboutsummaryrefslogtreecommitdiff
path: root/comp1511/minesweeper/minesweeper.c
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-13 18:00:17 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-13 18:00:17 +1100
commit98cef5e9a772602d42acfcf233838c760424db9a (patch)
tree5277fa1d7cc0a69a0f166fcbf10fd320f345f049 /comp1511/minesweeper/minesweeper.c
initial commit
Diffstat (limited to 'comp1511/minesweeper/minesweeper.c')
-rw-r--r--comp1511/minesweeper/minesweeper.c326
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;
+}