aboutsummaryrefslogtreecommitdiff
path: root/comp1511
diff options
context:
space:
mode:
Diffstat (limited to 'comp1511')
-rw-r--r--comp1511/cs_beats/beats.c412
-rw-r--r--comp1511/cs_beats/test_beats.c190
-rw-r--r--comp1511/minesweeper/minesweeper.c326
3 files changed, 928 insertions, 0 deletions
diff --git a/comp1511/cs_beats/beats.c b/comp1511/cs_beats/beats.c
new file mode 100644
index 0000000..2f26898
--- /dev/null
+++ b/comp1511/cs_beats/beats.c
@@ -0,0 +1,412 @@
+// Assignment 2 20T1 COMP1511: CS bEats
+// beats.c
+//
+// The purpose of this program is to categorise music input.
+//
+// Version 1.0.0: Assignment released.
+// Version 1.0.1: Fix default return value of add_musical_note_to_beat.
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "beats.h"
+
+struct track {
+ struct beat *head;
+ struct beat *cur;
+};
+
+struct beat {
+ struct note *notes;
+ struct beat *next;
+};
+
+struct note {
+ int oct;
+ int key;
+ struct note *next;
+};
+
+////////////////////////////////////////////////////////////////////////
+// User Defined Functions //
+////////////////////////////////////////////////////////////////////////
+
+// Returns a value representing the pitch.
+static int get_pitch(const int octave, const int key) {
+ return (octave * 12) + (key);
+}
+
+// Return a malloced beat with fields initialised.
+struct beat *create_beat() {
+ Beat new_beat = malloc(sizeof(struct beat));
+ assert(new_beat != NULL);
+
+ new_beat->next = NULL;
+ new_beat->notes = NULL;
+
+ return new_beat;
+}
+
+// Returns the tail of a note linked list.
+static struct note *get_note_tail(struct note *nhead) {
+ if (nhead == NULL) {
+ return NULL;
+ }
+ struct note *ret = nhead;
+ while (ret->next != NULL) {
+ ret = ret->next;
+ }
+ return ret;
+}
+
+// Returns the tail of a beat linked list.
+static struct beat *get_beat_tail(struct beat *bhead) {
+ if (bhead == NULL) {
+ return NULL;
+ }
+ struct beat *ret = bhead;
+ while (ret->next != NULL) {
+ ret = ret->next;
+ }
+ return ret;
+}
+
+// Returns a malloced Note with fields initialised.
+static struct note *create_note() {
+ struct note *ret = malloc(sizeof(struct note));
+ assert(ret != NULL);
+
+ ret->oct = 0;
+ ret->key = 0;
+ ret->next = NULL;
+ return ret;
+}
+
+// Inserts a note into a linked list of notes before the target note.
+static void insert_note_before(struct beat *beat, struct note *note,
+ struct note *target) {
+ if (beat->notes == target) {
+ beat->notes = note;
+ note->next = target;
+ return;
+ }
+ for (struct note *i = beat->notes; i != NULL; i = i->next) {
+ if (i->next == target) {
+ i->next = note;
+ note->next = target;
+ return;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// Stage 1 Functions //
+////////////////////////////////////////////////////////////////////////
+
+// Add a note to the end of a beat.
+int add_note_to_beat(struct beat *const beat, const int oct, const int key) {
+ if (oct < 0 || oct >= 10) {
+ return INVALID_OCTAVE;
+ }
+ if (key < 0 || key >= 12) {
+ return INVALID_KEY;
+ }
+
+ struct note *ntail = get_note_tail(beat->notes);
+ if (ntail != NULL) {
+ if (get_pitch(oct, key) <= get_pitch(ntail->oct, ntail->key)) {
+ return NOT_HIGHEST_NOTE;
+ }
+ }
+ struct note *new_note = create_note();
+ new_note->oct = oct;
+ new_note->key = key;
+ new_note->next = NULL;
+
+ if (ntail == NULL) {
+ beat->notes = new_note;
+ } else {
+ ntail->next = new_note;
+ }
+ return VALID_NOTE;
+}
+
+// Print the contents of a beat.
+void print_beat(struct beat *const beat) {
+ if (beat == NULL) {
+ return;
+ }
+ if (beat->notes == NULL) {
+ printf("\n");
+ return;
+ }
+ for (struct note *i = beat->notes; i != NULL; i = i->next) {
+ printf("%d ", i->oct);
+ if (i->key >= 10) {
+ printf("%d", i->key % 12);
+ } else {
+ printf("%d%d", i->key / 12, i->key % 12);
+ }
+ if (i->next) {
+ printf(" | ");
+ }
+ }
+ printf("\n");
+}
+
+// Count the number of notes in a beat that are in a given octave.
+int count_notes_in_octave(struct beat *const beat, int oct) {
+ if (beat->notes == NULL) {
+ return 0;
+ }
+ int notes = 0;
+ for (struct note *i = beat->notes; i != NULL; i = i->next) {
+ if (i->oct == oct) {
+ ++notes;
+ }
+ }
+ return notes;
+}
+
+////////////////////////////////////////////////////////////////////////
+// Stage 2 Functions //
+////////////////////////////////////////////////////////////////////////
+
+// Return a malloced track with fields initialized.
+struct track *create_track(void) {
+ struct track *ret = malloc(sizeof(struct track));
+ ret->head = NULL;
+ ret->cur = NULL;
+ return ret;
+}
+
+// Add a beat after the current beat in a track.
+void add_beat_to_track(struct track *track, struct beat *beat) {
+ if (track->cur != NULL) { // this behaviour may be unwanted
+ if (track->cur->next != NULL) {
+ beat->next = track->cur->next;
+ track->cur->next = beat;
+ } else {
+ track->cur->next = beat;
+ }
+ } else {
+ if (track->head == NULL) {
+ track->head = beat;
+ } else {
+ beat->next = track->head;
+ track->head = beat;
+ }
+ }
+}
+
+// Set a track's current beat to the next beat.
+int select_next_beat(struct track *track) {
+ if (track->cur == NULL) {
+ if (track->head == NULL) {
+ return TRACK_STOPPED;
+ } else {
+ track->cur = track->head;
+ return TRACK_PLAYING;
+ }
+ } else {
+ if (track->cur->next == NULL) {
+ track->cur = NULL;
+ return TRACK_STOPPED;
+ } else {
+ track->cur = track->cur->next;
+ return TRACK_PLAYING;
+ }
+ }
+}
+
+// Print the contents of a track.
+void print_track(struct track *track) {
+ if (track->head == NULL) {
+ return;
+ }
+ int count = 1;
+ for (struct beat *i = track->head; i != NULL; i = i->next) {
+ if (i == track->cur) {
+ printf(">");
+ } else {
+ printf(" ");
+ }
+ printf("[%d] ", count);
+ print_beat(i);
+ ++count;
+ }
+}
+
+// Count beats after the current beat in a track.
+int count_beats_left_in_track(struct track *track) {
+ int count = 0;
+ if (track == NULL || track->head == NULL) {
+ return count;
+ }
+ struct beat *i = track->cur;
+ if (i == NULL) {
+ i = track->head;
+ }
+ for (; i != NULL; i = i->next) {
+ ++count;
+ }
+ if (track->cur) {
+ --count;
+ }
+ return count;
+}
+
+////////////////////////////////////////////////////////////////////////
+// Stage 3 Functions //
+////////////////////////////////////////////////////////////////////////
+
+// Free the memory of a beat, and any memory it points to.
+void free_beat(struct beat *beat) {
+ if (beat == NULL) {
+ return;
+ }
+ if (beat->notes != NULL) {
+ struct note *i = beat->notes;
+ struct note *forwards = i->next;
+ while (i != NULL) {
+ forwards = i->next;
+ free(i);
+ i = forwards;
+ }
+ }
+ free(beat);
+}
+
+// Free the memory of a track, and any memory it points to.
+void free_track(struct track *track) {
+ if (track == NULL) {
+ return;
+ }
+ if (track->head != NULL) {
+ struct beat *i = track->head;
+ struct beat *forwards = i->next;
+ while (i != NULL) {
+ forwards = i->next;
+ free_beat(i);
+ i = forwards;
+ }
+ }
+ free(track);
+}
+
+// Remove the currently selected beat from a track.
+int remove_selected_beat(struct track *track) {
+ if (track->cur == NULL) {
+ return TRACK_STOPPED;
+ }
+ struct beat *backwards = NULL;
+ struct beat *forwards = NULL;
+ for (struct beat *i = track->head; i != NULL; i = i->next) {
+ if (i == track->cur) {
+ track->head = i->next;
+ forwards = i->next;
+ free_beat(track->cur);
+ break;
+ } else if (i->next == track->cur) {
+ backwards = i;
+ forwards = i->next->next;
+ free_beat(track->cur);
+ backwards->next = forwards;
+ break;
+ }
+ }
+ if (forwards == NULL) {
+ track->cur = NULL;
+ return TRACK_STOPPED;
+ } else {
+ track->cur = forwards;
+ return TRACK_PLAYING;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// Stage 4 Functions //
+////////////////////////////////////////////////////////////////////////
+
+// Add note to beat, given its 'musical notation'.
+int add_musical_note_to_beat(Beat beat, char *string) {
+ int oct = string[0] - '0';
+ if (oct < 0 || oct > 9) {
+ return INVALID_MUSICAL_NOTE;
+ }
+ int key = 0;
+ switch (string[1]) {
+ case 'A':
+ key = 0;
+ break;
+ case 'B':
+ key = 2;
+ break;
+ case 'C':
+ key = 3;
+ break;
+ case 'D':
+ key = 5;
+ break;
+ case 'E':
+ key = 7;
+ break;
+ case 'F':
+ key = 8;
+ break;
+ case 'G':
+ key = 10;
+ break;
+ default:
+ return INVALID_MUSICAL_NOTE;
+ }
+ for (char *c = string + 2; *c != '\0'; ++c) {
+ if (*c == '#') {
+ ++key;
+ } else {
+ return INVALID_MUSICAL_NOTE;
+ }
+ }
+ int pitch = get_pitch(oct, key);
+ oct = pitch / 12;
+ key = pitch % 12;
+ struct note *tail = get_note_tail(beat->notes);
+ if (tail == NULL || get_pitch(tail->oct, tail->key) < pitch) {
+ add_note_to_beat(beat, oct, key);
+ return VALID_NOTE;
+ }
+ struct note *higher = NULL;
+ for (struct note *i = beat->notes; i != NULL; i = i->next) {
+ int iter_pitch = get_pitch(i->oct, i->key);
+ if (iter_pitch == pitch) {
+ return INVALID_MUSICAL_NOTE;
+ } else if (iter_pitch > pitch) {
+ higher = i;
+ break;
+ }
+ }
+ struct note *note = create_note();
+ note->oct = oct;
+ note->key = key;
+ insert_note_before(beat, note, higher);
+ return VALID_NOTE;
+}
+
+////////////////////////////////////////////////////////////////////////
+// Stage 5 Functions //
+////////////////////////////////////////////////////////////////////////
+
+// Cut a range of beats to the end of a track.
+void cut_range_to_end(Track track, int range_length) {
+ printf("cut_range_to_end not implemented yet.");
+ return;
+}
+
+// Reverse a list of beats within a range of a track.
+int reverse_range(Track track, int range_length) {
+ printf("reverse_range not implemented yet.");
+ return 0;
+}
diff --git a/comp1511/cs_beats/test_beats.c b/comp1511/cs_beats/test_beats.c
new file mode 100644
index 0000000..d1eb793
--- /dev/null
+++ b/comp1511/cs_beats/test_beats.c
@@ -0,0 +1,190 @@
+// Assignment 2 20T1 COMP1511: CS bEats
+// test_beats.c
+//
+// This program was written by YOUR-NAME-HERE (z5555555)
+// on INSERT-DATE-HERE
+//
+// Version 1.0.0: Assignment released.
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "beats.h"
+#include "test_beats.h"
+
+// Test function for `add_note_to_beat`
+int test_add_note_to_beat(void) {
+ // Test 1: Rejecting negative inputs.
+ Beat test_beat = create_beat();
+ if (add_note_to_beat(test_beat, -1, -1) != INVALID_OCTAVE) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ if (add_note_to_beat(test_beat, -1, 0) != INVALID_OCTAVE) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ if (add_note_to_beat(test_beat, 1, -1) != INVALID_KEY) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 2: Rejecting invalid pitch notes.
+ if (add_note_to_beat(test_beat, 1, 1) != VALID_NOTE) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ if (add_note_to_beat(test_beat, 1, 0) != NOT_HIGHEST_NOTE) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 3: Accepting valid inputs.
+ if (add_note_to_beat(test_beat, 1, 2) != VALID_NOTE) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ return MEETS_SPEC;
+}
+
+// Test function for `count_notes_in_octave` this is broken
+int test_count_notes_in_octave(void) {
+ // Test 1: Counting invalid octaves.
+ Beat test_beat = create_beat();
+ add_note_to_beat(test_beat, 1, 1);
+ if (count_notes_in_octave(test_beat, -1) != 0) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ if (count_notes_in_octave(test_beat, 11) != 0) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 2: Counting valid octaves.
+ if (count_notes_in_octave(test_beat, 1) != 1) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ if (count_notes_in_octave(test_beat, 1) == 0) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 3: Counting without any notes
+ struct beat *empty_beat = create_beat();
+ if (count_notes_in_octave(empty_beat, 0) != 0) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 4: Counting the correct amount
+ add_note_to_beat(test_beat, 2, 1);
+ add_note_to_beat(test_beat, 2, 2);
+ if (count_notes_in_octave(test_beat, 2) != 2) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ add_note_to_beat(test_beat, 2, 3);
+ if (count_notes_in_octave(test_beat, 2) != 3) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ return MEETS_SPEC;
+}
+
+// These struct definitions are required for the following tests.
+// They access the fields directly instead of using other functions as tests,
+// which could be considered unsafe as they are not guaranteed to be correct.
+// We only want to test a single function, not other functions indirectly.
+struct track {
+ struct beat *head;
+ struct beat *cur;
+};
+
+struct beat {
+ struct note *notes;
+ struct beat *next;
+};
+
+// Test function for `add_beat_to_track`
+int test_add_beat_to_track(void) {
+ // Test 1: Test if the beat gets added correctly.
+ struct track *test_track = create_track();
+ struct beat *test_beat = create_beat();
+ add_beat_to_track(test_track, test_beat);
+ if (test_track->head == NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 2: Ensure the beat is a shallow copy.
+ if (test_track->head != test_beat) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 3: Test if the expected fields are NULL.
+ if (test_track->cur != NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ if (test_track->head->notes != NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 4: Ensure adding muliple beats works correctly.
+ struct beat *test_beat2 = create_beat();
+ add_beat_to_track(test_track, test_beat2);
+ if (test_track->head != test_beat2) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 5: Ensure the last field is still NULL.
+ if (test_track->head->next->next != NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ return MEETS_SPEC;
+}
+
+// Test function for `remove_selected_beat`
+int test_remove_selected_beat(void) {
+ // Test 1: Ensure the correct return type on a track with no selected beat.
+ struct track *test_track = create_track();
+ struct beat *test_beat = create_beat();
+ add_beat_to_track(test_track, test_beat);
+ if (remove_selected_beat(test_track) != TRACK_STOPPED) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 2: Ensure that no beat has been deleted after the previous test.
+ if (test_track->head == NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 3: Ensure the track is still playing after the attempted removal.
+ if (test_track->cur != NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 4: Ensure the correct return type on a track with a selected beat.
+ select_next_beat(test_track);
+ if (remove_selected_beat(test_track) != TRACK_STOPPED) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 5: Ensure the beat has been deleted correct after the previous test.
+ if (test_track->head != NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 6: Ensure the track is not playing after beat removal.
+ if (test_track->cur != NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ return MEETS_SPEC;
+}
+
+// Another struct definition which is required for testing below.
+// This can probably be considered bad practice as struct defintions should not
+// be simply copied across multiple files, but compared to the alternative
+// of invoking potentially broken functions, this is preferable.
+struct note {
+ int oct;
+ int key;
+ struct note *next;
+};
+
+// Test function for `add_musical_note_to_beat`
+int test_add_musical_note_to_beat(void) {
+ // Test 1: Ensure the beat is added to an empty beat.
+ struct beat *test_beat = create_beat();
+ add_musical_note_to_beat(test_beat, "2C#");
+ if (test_beat->notes == NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 2: Ensure the beat has the correct pitch.
+ if (test_beat->notes->oct != 2 || test_beat->notes->key != 4) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 3: Ensure a higher beat is added when appropriate.
+ add_musical_note_to_beat(test_beat, "2C##");
+ if (test_beat->notes->next == NULL) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ // Test 4: Ensure that a lower beat is added when appropriate.
+ add_musical_note_to_beat(test_beat, "2C");
+ if (test_beat->notes->oct != 2 || test_beat->notes->key != 3) {
+ return DOES_NOT_MEET_SPEC;
+ }
+ return MEETS_SPEC;
+}
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;
+}