Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Assignment 1 20T1 COMP1511: Minesweeper
- // minesweeper.c
- //
- // This program was written by z5312070
- // on 11/3/2020
- //
- // Version 1.0.0 (2020-03-08): Assignment released.
- // Version 1.0.1 (2020-03-08): Fix punctuation in comment.
- // Version 1.0.2 (2020-03-08): Fix second line of header comment to say minesweeper.c
- #include <stdio.h>
- #include <stdlib.h>
- // Possible square states.
- #define VISIBLE_SAFE 0
- #define HIDDEN_SAFE 1
- #define HIDDEN_MINE 2
- // 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
- // Add any extra #defines here.
- #define GAME_ALIVE 0
- #define GAME_OVER 1
- #define GAME_WON 2
- #define REVEAL_SQUARE_SIZE 3
- #define MAX_HINTS 3
- #define COORD_SIZE 4
- void initialise_field(int minefield[SIZE][SIZE]);
- void print_debug_minefield(int minefield[SIZE][SIZE]);
- void placeMine(int minefield[SIZE][SIZE], int row, int column, int squareState);
- void detect_row(int minefield[SIZE][SIZE], int row);
- void detect_column(int minefield[SIZE][SIZE], int col);
- void detect_square(int minefield[SIZE][SIZE], int row, int column, int size);
- int reveal_square(int minefield[SIZE][SIZE], int row, int column);
- void set_3x3square_visible_safe(int minefield[SIZE][SIZE], int coords[COORD_SIZE]);
- int count_in_square(int minefield[SIZE][SIZE], int row, int column, int size, int squareState);
- void handle_hints(int minefield[SIZE][SIZE], int mineOption, int *hintsUsed);
- void draw_status(int status);
- void print_gameplay_minefield(int minefield[SIZE][SIZE], int gameStatus);
- void print_minefield(int minefield[SIZE][SIZE], int row, int col, int incrementer, int gameStatus);
- int reveal_radial(int minefield[SIZE][SIZE], int row, int column);
- void shift_grid(int minefield[SIZE][SIZE], int row, int column);
- void math_clamp(int min, int max, int *x);
- void math_clamp_array(int min, int max, int arraySize, int *array);
- int main(void) {
- // declare variables
- int hintsUsed = 0;
- int numberOfMinesToAdd = 0;
- int mineOption = 0;
- int roundsPlayed = 0; // doesn't include hints
- int gameStatus = GAME_ALIVE;
- int gameMode = DEBUG_MODE;
- int minefield[SIZE][SIZE];
- initialise_field(minefield);
- printf("Welcome to minesweeper!\n");
- printf("How many mines? ");
- scanf("%d", &numberOfMinesToAdd);
- printf("Enter pairs:\n");
- // gets user input for the position of mine(s)
- int numberOfPairs = 0;
- while (numberOfPairs < numberOfMinesToAdd) { // cycle through the amount of mines
- int row, col;
- scanf("%d %d", &row, &col);
- placeMine(minefield, row, col, HIDDEN_MINE);
- numberOfPairs++;
- }
- printf("Game Started\n");
- print_debug_minefield(minefield);
- // check for valid input and continuous loop
- while (scanf("%d", &mineOption) == 1) {
- int row = 0;
- int column = 0;
- handle_hints(minefield, mineOption, &hintsUsed);
- if (mineOption == REVEAL_SQUARE) {
- scanf("%d %d", &row, &column);
- gameStatus = reveal_square(minefield, row, column);
- roundsPlayed++;
- } else if (mineOption == GAMEPLAY_MODE) {
- printf("Gameplay mode activated\n");
- gameMode = GAMEPLAY_MODE;
- } else if (mineOption == DEBUG_MODE) {
- printf("Debug mode activated\n");
- gameMode = DEBUG_MODE;
- } else if (mineOption == REVEAL_RADIAL) {
- scanf("%d %d", &row, &column);
- gameStatus = reveal_radial(minefield, row, column);
- roundsPlayed++;
- }
- // safe first turn
- if (roundsPlayed == 1 && gameStatus == GAME_OVER) {
- shift_grid(minefield, row, column);
- // run revealer again after shift
- if (mineOption == REVEAL_SQUARE) {
- gameStatus = reveal_square(minefield, row, column);
- } else if (mineOption == REVEAL_RADIAL) {
- gameStatus = reveal_radial(minefield, row, column);
- }
- } else {
- if (gameStatus == GAME_OVER) {
- printf("Game over \n");
- } else if (gameStatus == GAME_WON) {
- printf("Game Won! \n");
- }
- }
- if (gameMode == GAMEPLAY_MODE) {
- print_gameplay_minefield(minefield, gameStatus);
- } else {
- print_debug_minefield(minefield);
- }
- }
- return 0;
- }
- // runs hints
- void handle_hints(int minefield[SIZE][SIZE], int mineOption, int *hintsUsed) {
- int row, col, size;
- if (mineOption == DETECT_ROW) {
- scanf("%d", &row);
- if (*hintsUsed < MAX_HINTS) {
- detect_row(minefield, row);
- *hintsUsed = *(hintsUsed) + 1;
- } else {
- printf("Help already used\n");
- }
- } else if (mineOption == DETECT_COL) {
- scanf("%d", &col);
- if (*hintsUsed < MAX_HINTS) {
- detect_column(minefield, col);
- *hintsUsed = *(hintsUsed) + 1;
- } else {
- printf("Help already used\n");
- }
- } else if (mineOption == DETECT_SQUARE) {
- scanf("%d %d %d", &row, &col, &size);
- if (*hintsUsed < MAX_HINTS) {
- detect_square(minefield, row, col, size);
- *hintsUsed = *(hintsUsed) + 1;
- } else {
- printf("Help already used\n");
- }
- }
- }
- // Places mine on the minefield
- void placeMine(int minefield[SIZE][SIZE], int row, int column, int squareState) {
- // check if they the user input is in the bounds of the minefield
- if (row < SIZE && column < SIZE && row >= 0 && column >= 0) {
- // pass it into location storage
- minefield[row][column] = squareState;
- }
- }
- // Set the entire minefield to HIDDEN_SAFE.
- void initialise_field(int minefield[SIZE][SIZE]) {
- int row = 0;
- while (row < SIZE) {
- int col = 0;
- while (col < SIZE) {
- placeMine(minefield, row, col, HIDDEN_SAFE);
- col++;
- }
- row++;
- }
- }
- // Print out the actual values of the minefield.
- void print_debug_minefield(int minefield[SIZE][SIZE]) {
- int row = 0;
- while (row < SIZE) {
- int col = 0;
- while (col < SIZE) {
- printf("%d ", minefield[row][col]);
- col++;
- }
- printf("\n");
- row++;
- }
- }
- // Prints the number of lines in a row
- void detect_row(int minefield[SIZE][SIZE], int row) {
- int totalMines = 0;
- int i = 0;
- while (i < SIZE) {
- if (minefield[row][i] == HIDDEN_MINE) {
- totalMines++;
- }
- i++;
- }
- printf("There are %d mine(s) in row %d \n", totalMines, row);
- }
- // Prints the number of lines in a column
- void detect_column(int minefield[SIZE][SIZE], int col) {
- int totalMines = 0;
- int i = 0;
- while (i < SIZE) {
- if (minefield[i][col] == HIDDEN_MINE) {
- totalMines++;
- }
- i++;
- }
- printf("There are %d mine(s) in column %d \n", totalMines, col);
- }
- // Counts the number of mines in a specific area box
- // returns the number of mines found
- int count_in_square(int minefield[SIZE][SIZE], int row, int column, int size, int squareState) {
- int round = size / 2;
- int coords[COORD_SIZE] = {
- row - round, // start row position
- column - round, // start column position
- row + round, // end row position
- column + round // end column position
- };
- math_clamp_array(0, SIZE, COORD_SIZE, coords);
- int numberOfMines = 0;
- int startRowPosReset = coords[0];
- while (startRowPosReset <= coords[2]) {
- int startColPosReset = coords[1];
- while (startColPosReset <= coords[3]) {
- if (minefield[startRowPosReset][startColPosReset] == squareState) {
- numberOfMines++;
- }
- startColPosReset++;
- }
- startRowPosReset++;
- }
- return numberOfMines;
- }
- // Prints the number of lines in a specific area
- void detect_square(int minefield[SIZE][SIZE], int row, int column, int size) {
- int numberOfMines = count_in_square(minefield, row, column, size, HIDDEN_MINE);
- printf("There are %d mine(s) in the square centered at row %d, column %d of size %d \n", numberOfMines, row, column, size);
- }
- // reveals content of the square
- // returns 0:alive | 1:hits bomb | 2:won
- int reveal_square(int minefield[SIZE][SIZE], int row, int column) {
- // calculates the radius and rounds down
- int radius = REVEAL_SQUARE_SIZE / 2;
- int coords[COORD_SIZE] = {
- row - radius, // start row position
- column - radius, // start column position
- row + radius, // end row position
- column + radius // end column position
- };
- // checks if the coordinate is valid
- math_clamp_array(0, SIZE, COORD_SIZE, coords);
- if (minefield[row][column] == HIDDEN_MINE) { // check if user reveals a mine
- return GAME_OVER;
- } else {
- //check if mine is in the vicinity
- int numberOfMinesInSquare = count_in_square(minefield, row, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (numberOfMinesInSquare != 0) { // if it contains mines
- // set the user input to VISIBLE_SAFE
- placeMine(minefield, row, column, VISIBLE_SAFE);
- } else { // if it doesn't contain mines
- // set 3x3 square VISIBLE_SAFE
- set_3x3square_visible_safe(minefield, coords);
- }
- }
- // check if every square has been searched
- int hiddenSafeCounter = count_in_square(minefield, row, column, SIZE, HIDDEN_SAFE);
- if (hiddenSafeCounter == 0) {
- return GAME_WON;
- }
- return GAME_ALIVE;
- }
- // set 3x3 square to visible safe
- void set_3x3square_visible_safe(int minefield[SIZE][SIZE], int coords[COORD_SIZE]) {
- int startRowPosReset = coords[0];
- while (startRowPosReset <= coords[2]) { // loop through rows
- int startColPosReset = coords[1];
- while (startColPosReset <= coords[3]) { // loop through columns
- placeMine(minefield, startRowPosReset, startColPosReset, VISIBLE_SAFE);
- startColPosReset++;
- }
- startRowPosReset++;
- }
- }
- // draws happy or sad face
- void draw_status(int status) {
- if (status == GAME_OVER) { // dead
- printf("xx\n");
- printf("/\\\n");
- } else { // alive or won
- printf("..\n");
- printf("\\/\n");
- }
- }
- // draws the minefield with mines hidden
- void print_gameplay_minefield(int minefield[SIZE][SIZE], int gameStatus) {
- draw_status(gameStatus);
- int totalSizeRow = SIZE + 3;
- int totalSizeCol = SIZE + 20 ;
- int lastRowArray = totalSizeRow - 1;
- int lastColArray = totalSizeCol - 1;
- int row = 0;
- while (row < totalSizeRow) {
- int col = 0;
- int incrementer = 1;
- while (col < totalSizeCol) {
- // draw top numbers
- if (row == 0) {
- if (col < 4) { // draw white space at the start
- printf(" ");
- } else {
- if (col == (1 + 3 * incrementer)) {
- int tensColumn = (incrementer / 10) % 10;
- printf("%d", tensColumn);
- } else if (col == (2 + 3 * incrementer)) {
- int lastDigit = (incrementer - 1) % 10; //-1 to start a 0
- printf("%d", lastDigit);
- } else {
- printf(" "); // draws the spaces between the numbers
- }
- }
- } else if (row == 1 || row == lastRowArray) { // draw top line and bottom
- if (col < 3) {
- printf(" ");
- } else {
- printf("-");
- }
- } else {
- if (col == 0) { // draw side axis
- int tensRow = ((row - 2) / 10) % 10;
- printf("%d", tensRow);
- } else if (col == 1) { // draw side axis
- int lastDigit = (row - 2) % 10; // -2 because of the spacer at top
- printf("%d", lastDigit);
- } else if (col == 3 || col == lastColArray) { // draw the side lines
- printf("|");
- } else if (col == 2 || (col == 3 + 3 * incrementer)) { // between mines
- printf(" ");
- } else {
- print_minefield(minefield, row, col, incrementer, gameStatus);
- }
- }
- if (col == (3 + 3 * incrementer)) { // gap between mine
- incrementer++;
- }
- col++;
- }
- printf("\n");
- row++;
- }
- }
- // draws the gameplay minefield from array
- void print_minefield(int minefield[SIZE][SIZE], int row, int col, int incrementer, int gameStatus) {
- int fieldRow = row - 2; // -2 to account for gap in the top corner
- int fieldCol = incrementer - 1; // -1 because first array starts a 0
- int isSecondPosition = 0;
- if (col == (2 + 3 * incrementer)) { // second minefield position
- isSecondPosition = 1;
- }
- if (minefield[fieldRow][fieldCol] == VISIBLE_SAFE) { // if it has been explored
- int adjacentMines = count_in_square(minefield, fieldRow, fieldCol, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (adjacentMines > 0) { // has mine next to it
- if (isSecondPosition) {
- printf("%d", adjacentMines);
- } else {
- int tensColumn = adjacentMines / 10;
- printf("%d", tensColumn);
- }
- } else { // is explored and contains no mine or no mines next to it
- printf(" ");
- }
- } else if (gameStatus == GAME_OVER && minefield[fieldRow][fieldCol] == HIDDEN_MINE) {
- // reveal mines if game is over
- if (isSecondPosition) {
- printf(")");
- } else {
- printf("(");
- }
- } else { // not explored yet
- printf("#");
- }
- }
- void shift_grid(int minefield[SIZE][SIZE], int row, int column) {
- while (minefield[row][column] == HIDDEN_MINE ) {
- int tempLastRow[SIZE];
- int colInc = 0;
- // store bottom row
- while (colInc < SIZE) {
- tempLastRow[colInc] = minefield[SIZE - 1][colInc];
- colInc++;
- }
- // shift everything down
- int rowInc = 0;
- while (rowInc < SIZE) {
- int colInc2 = 0;
- int tempRowBefore[SIZE];
- while (colInc2 < SIZE) {
- int temp[SIZE];
- // set first row to last row
- if (rowInc == 0) {
- tempRowBefore[colInc2] = minefield[rowInc][colInc2];
- minefield[rowInc][colInc2] = tempLastRow[colInc2];
- } else { // set row to previous row
- temp[colInc2] = minefield[rowInc][colInc2];
- minefield[rowInc][colInc2] = tempRowBefore[colInc2];
- tempRowBefore[colInc2] = temp[colInc2];
- }
- colInc2++;
- }
- rowInc++;
- }
- }
- }
- int reveal_radial(int minefield[SIZE][SIZE], int row, int column) {
- if (minefield[row][column] == HIDDEN_MINE) { // check if user reveals a mine
- return GAME_OVER;
- } else {
- //check if mine is in the vicinity
- int numberOfMinesInSquare = count_in_square(minefield, row, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (numberOfMinesInSquare != 0) { // if it contains mines
- // set the center to VISIBLE_SAFE only
- placeMine(minefield, row, column, VISIBLE_SAFE);
- } else { // if it doesn't contain mines
- // middle top
- int i1 = row;
- while (i1 >= 0) {
- if (minefield[i1][column] != HIDDEN_MINE) {
- placeMine(minefield, i1, column, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, i1, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- i1 = -1;
- }
- i1--;
- }
- // middle bottom
- int i2 = row;
- while (i2 < SIZE) {
- if (minefield[i2][column] != HIDDEN_MINE) {
- placeMine(minefield, i2, column, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, i2, column, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- i2 = SIZE;
- }
- i2++;
- }
- // middle left
- int j3 = column;
- while (j3 >= 0) {
- if (minefield[row][j3] != HIDDEN_MINE) {
- placeMine(minefield, row, j3, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, row, j3, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- j3 = -1;
- }
- j3--;
- }
- // middle right
- int j4 = column;
- while (j4 < SIZE) {
- if (minefield[row][j4] != HIDDEN_MINE) {
- placeMine(minefield, row, j4, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, row, j4, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- j4 = SIZE;
- }
- j4++;
- }
- // top left diagonal
- int i5 = row;
- int j5 = column;
- while (i5 >= 0 && j5 >= 0) {
- if (minefield[i5][j5] != HIDDEN_MINE) {
- placeMine(minefield, i5, j5, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, i5, j5, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- i5 = -1;
- }
- i5--;
- j5--;
- }
- // top right diagonal
- int i6 = row;
- int j6 = column;
- while (i6 >= 0 && j6 < SIZE) {
- if (minefield[i6][j6] != HIDDEN_MINE) {
- placeMine(minefield, i6, j6, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, i6, j6, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- i6 = -1;
- }
- i6--;
- j6++;
- }
- // bottom left diagonal
- int i7 = row;
- int j7 = column;
- while (i7 < SIZE && j7 >= 0) {
- if (minefield[i7][j7] != HIDDEN_MINE) {
- placeMine(minefield, i7, j7, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, i7, j7, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- i7 = SIZE;
- }
- i7++;
- j7--;
- }
- // bottom right diagonal
- int i8 = row;
- int j8 = column;
- while (i8 < SIZE && j8 < SIZE) {
- if (minefield[i8][j8] != HIDDEN_MINE) {
- placeMine(minefield, i8, j8, VISIBLE_SAFE);
- }
- int mines = count_in_square(minefield, i8, j8, REVEAL_SQUARE_SIZE, HIDDEN_MINE);
- if (mines > 0) {
- i8 = SIZE;
- }
- i8++;
- j8++;
- }
- }
- }
- // check if every square has been searched
- int hiddenSafeCounter = count_in_square(minefield, row, column, SIZE, HIDDEN_SAFE);
- if (hiddenSafeCounter == 0) {
- return GAME_WON;
- }
- return GAME_ALIVE;
- }
- // clamp coords
- void math_clamp(int min, int max, int *x) {
- if (*x <= min) {
- *x = min;
- } else if (*x >= max) {
- *x = max - 1; // need to -1 because to account for 0 index for array
- }
- }
- // clamp coords in an array
- void math_clamp_array(int min, int max, int arraySize, int *array) {
- int i = 0;
- while (i < arraySize) {
- math_clamp(0, SIZE, array);
- array++;
- i++;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement