// Assignment 1 20T1 COMP1511: Minesweeper // minesweeper.c #include #include // 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; }