[08 Arrays and Functions in Practice: Minesweeper Game]

Directory

  1. How to play
  2. analysis and design
  3. Code
  4. Expand
  5. Extended modifications

1. How to play


In the console interface, mines are arranged in advance on the map, and users cannot see the map content. Start selecting the click location. If it is not a mine, the number of surrounding mines will be displayed. If it is a mine, you will be killed and the game will be over. Find all the mines, or the remaining positions on the map are all mines, victory, and the game is over.

2. Analysis and Design

2.1 Data structure analysis

Both the mine map data and the displayed data need to be stored. The first thing I thought of was to use a 9*9 two-dimensional array to store it. The position of thunder is 1, and non-mine is represented by 0.

If the investigation location is the coordinate (2,5), visit 8 surrounding locations, count the number of surrounding mines, and display them at the current location.


The value stored in the (2,5) coordinates in the picture is 0, and there is 1 mine in total when traversing the surrounding positions, so the position displayed to the user as 1 means that there is 1 mine around.

Question:

  1. There are two pieces of information that need to be displayed. One is the information about whether the map itself is a mine or not, represented by 0 and 1. The other is the information that needs to be seen by the user, that is, the information about the total number of mines or surrounding mines. If they are all placed in 1 array, there will be unclear problems and confusion. For example, 1 cannot tell whether it is the total number of surrounding mines or 1 represented by the mines.
  2. When counting the number of mines in the outermost number, it is easy to cross the line. It would be troublesome if you have to judge whether the boundary is crossed every time.

Solution:
3. We can use two arrays, one to store information about mines and non-mines, and the other to display information about surrounding mines to the user. Uniformly use the char type two-dimensional array to facilitate the unification of printing characters and passing parameters. The second map is all “” characters at the beginning, which is the initialized state.
4. The data needs to be stored in an array of 9
9. Expand it into an array of 1111 and use the elements of 99 in it so that the statistics on the edge will not cross the boundary.
5. Try to use the same set of functions for processing, with unified parameters

Corresponding array:

char minemap[11][11] = {0};//?To store the arranged mine information
char flipmap[11][11] = {0};//? to store the number information of mines detected

2.2 Design of file structure

It is written in three files, one is the game content module and the main program

test.c //Test logic
game.h //Game data types and function definitions
game.c //Implementation of game functions

2.3 Function description

  1. Show menu

void menu();

  1. Variable definitions

#define ROWS 11 ? ? ? //Number of map rows
#define COLS 11 ? ? ? ? //Number of map columns
#define ROW ROWS-2 ? //Number of rows used
#define COL COLS-2 ? ? //Number of columns used
#define MINE 10 ? ? ? ? //Number of mines

3. Game functions

//1.Initialize the map
void InitMap(char ary[ROWS][COLS],int rows,int cols);
//2. Set up mines
void SetMine(char mine[ROWS][COLS],int row,int col);
//3.Display map
void ShowMap(char ary[ROWS][COLS], int row, int col);
//4.Looking for thunder
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);

2.4 Interface display

  1. Start interface
  2. Select 1, enter the game, and print out Lei’s storage map (this map does not need to be displayed, it is for testing) and the map displayed by the user. Enter the coordinates you want to open below

The coordinates were entered incorrectly and an illegal re-entry was reported.

Enter the coordinates of 2 and 3 to display the total number of surrounding mines 2


  1. Clicking on the mine will prompt the game to end and return to the main interface

  2. After checking all mines, a victory prompt will appear and return to the main interface.

3. Code implementation

3.1 Difficulty Analysis

  1. The unified definitions that require multiple changes in the game are macro definitions, such as the number of map rows and the number of mines.
  2. The unified interface passes in a two-dimensional array, and the rows and columns are changed according to needs.
  3. In order to facilitate user input, the map also prints row and column numbers.
  4. Calculate the number of surrounding mines and the changes in several coordinates around the target point. Because the final total added is the int type of the ascii sum of char characters, so the 8 characters ‘0’ are subtracted and converted into the number of mines.
  5. Click one each time and record the number of times. If it equals the number of grids minus the number of mines, then all the mines have been found and you win.

3.2 Code

1.game.h

#pragma once

#define ROWS 11 //Number of map rows
#define COLS 11 //Number of map columns
#define ROW ROWS-2 //Number of rows used
#define COL COLS-2 //Number of columns used
#define MINE 10 //Number of mines

//1.Initialize the map
void InitMap(char ary[ROWS][COLS],int rows,int cols);
//2. Set up mines
void SetMine(char mine[ROWS][COLS],int row,int col);
//3.Display map
void ShowMap(char ary[ROWS][COLS], int row, int col);
//4.Looking for thunder
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);

2.game.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void InitMap(char ary[ROWS][COLS], int rows, int cols,char set)
{<!-- -->
for (int i = 0; i < rows; i + + ) {<!-- -->
for (int j = 0; j < cols; j + + ) {<!-- -->
ary[i][j] = set;
}
}
}

void SetMine(char mine[ROWS][COLS],int row, int col)
{<!-- -->
int count = MINE;
while (count > 0) {<!-- -->
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0') {<!-- -->
mine[x][y] = '1';
count--;
}
}
\t\t
\t\t\t
}

void ShowMap(char ary[ROWS][COLS], int row, int col)
{<!-- -->
printf("--------Mine Sweeper--------\r\
");
//Print the column number first
for (int i = 0; i <= row; i + + ) {<!-- -->
printf("%d ", i);
}
printf("\r\
");
for (int i = 1; i <= row; i + + ) {<!-- -->
//Print line number
printf("%d ", i);
for (int j = 1; j <= col; j + + ) {<!-- -->
printf("%c ", ary[i][j]);
}
printf("\r\
");
}
}

//Calculate the number of surrounding mines
static int MnieCnt(char mine[ROWS][COLS],int x, int y) {<!-- -->
return mine[x - 1][y - 1] + mine[x + 1][y + 1] +
mine[x][y - 1] + mine[x][y + 1] +
mine[x + 1][y - 1] + mine[x - 1][y + 1] +
mine[x - 1][y] + mine[x + 1][y]
- 8 * '0';
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col)
{<!-- -->
int win = 0; //Record the number of mines checked
while (win < row * col -MINE) {<!-- -->
printf("Enter the coordinates of the point:");
int x, y;
scanf("%d %d", & amp;x, & amp;y);
if (x >= 1 & amp; & amp; x <= ROW & amp; & amp; y >= 1 & amp; & amp; y <= COL) {<!-- -->
if (mine[x][y] == '1') {<!-- -->
system("cls");
printf("Click the mine, the game is over\r\
");
ShowMap(mine,ROW,COL);
return;
}
}
else {<!-- -->
system("cls");
printf("Illegal coordinates, re-enter\r\
");
ShowMap(show, ROW, COL);
continue;
}
win++;
int n = MnieCnt(mine, x, y);
show[x][y] = n + '0';
system("cls");
ShowMap(show, ROW, COL);
}
\t
printf("Demining successfully\r\
");
}

3.main.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include "game.h"

void menu() {<!-- -->
printf("************************\r\
");
printf("*****1.Start the game*****\r\
");
printf("*****0.Exit the game*****\r\
");
printf("************************\r\
");
}

void game() {<!-- -->
char minemap[ROWS][COLS]; //Mine map
char flipmap[ROWS][COLS]; //Displayed map
//1.Initialize the map
InitMap(minemap,ROWS,COLS,'0');
InitMap(flipmap, ROWS, COLS, '*');
//2. Set up mines
SetMine(minemap,ROW,COL);
//3.Display map
ShowMap(minemap, ROW, COL);
ShowMap(flipmap, ROW, COL);
//4.Looking for thunder
FindMine(minemap, flipmap,ROW,COL);

}

int main()
{<!-- -->

srand((unsigned int)time(NULL));
int sel; //Get user selection
do
{<!-- -->
menu();
scanf("%d", & amp;sel);
switch (sel) {<!-- -->
case 1:
system("cls");
game();
break;
case 0:
printf("Exit the game\r\
");
return;
break;
default:
printf("Input error\r\
");
break;
}

} while (1);
return 0;
}

4.Extension

  • Choose game difficulty
    ?*Simple 9*9 chessboard, 10 mines
    ?*Medium 16*16 chessboard, 40 mines
    ?*Difficult 30*30 board, 99 mines
  • If the investigation location is not mined and the surrounding area is not mined, you can expand a
  • Can mark thunder
  • Plus demining time display

5. Extension modification

  1. Add timing display
  2. Mark mines
    Rewrite the FindMine function, add clock_t start and end timing variables, add input 1 to mark mines, and mines are displayed as @ symbols
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col)
{<!-- -->
int win = 0; //Record the number of mines checked
clock_t start,end;
int sec = 0;
start = clock();
while (win < row * col -MINE) {<!-- -->
end = clock();
sec = end - start;
printf("Elapsed time: %ds, 0 input coordinates 1 mark mine:", sec/ CLOCKS_PER_SEC);
int n;
scanf("%d", & amp;n);
if (n == 0) {<!-- -->
sec = end - start;
printf("Elapsed time: %ds, enter the coordinates of the point:", sec / CLOCKS_PER_SEC);
int x, y;
scanf("%d %d", & amp;x, & amp;y);

if (x >= 1 & amp; & amp; x <= ROW & amp; & amp; y >= 1 & amp; & amp; y <= COL) {<!-- -->
if (mine[x][y] == '1') {<!-- -->
system("cls");
printf("Click the mine, the game is over\r\
");
ShowMap(mine, ROW, COL);
return;
}
}
else {<!-- -->
system("cls");
printf("Illegal coordinates, re-enter\r\
");
ShowMap(show, ROW, COL);
continue;
}
win++;
int n = MnieCnt(mine, x, y);
show[x][y] = n + '0';
system("cls");
ShowMap(show, ROW, COL);
}
else if (n == 1) {<!-- -->
sec = end - start;
printf("Elapsed time: %ds, enter the coordinates of the mark (display @, re-enter to cancel the mark):", sec / CLOCKS_PER_SEC);
int x, y;
scanf("%d %d", & amp;x, & amp;y);
if (x >= 1 & amp; & amp; x <= ROW & amp; & amp; y >= 1 & amp; & amp; y <= COL) {<!-- -->
if(show[x][y]='@')
show[x][y] = '*';
show[x][y] = '@';
system("cls");
ShowMap(show, ROW, COL);
}
}
\t\t
}
\t
printf("Demining successfully\r\
");
}