Implementation of minesweeper game including blank expansion

Write the directory title here

  • 1. Game description
  • 2. Overall code
  • 3. Explain in detail
    • 3.1 Menu section
    • 3.2 Main part of the game
      • 3.2.1 Overall analysis
      • 3.2.2 Chessboard initialization
      • 3.2.3 Chessboard display
      • 3.2.4 Setting up mines
      • 3.2.5 Mine clearance stage
      • 3.2.6 Code for counting the number of mines
      • 3.2.7 Expand using iteration:
      • 3.2.8 Minesweeper part of the main code
  • 4. Summary

1. Game description

Minesweeper game function description:

?Use the ?console to implement the classic Minesweeper game

? The game can be continued or exited through the menu

? The minesweeper chessboard is a 9*9 grid?

? By default, 10 mines are randomly arranged

? Can detect mines

? If the location is not a mine, it will show that there are ? mines around it.

? If the location is mine, it will blow up and the game will end.

? Find all the mines except 10 mines, the mines are cleared successfully, and the game is over.

2. Overall code

//Header file part
#define _CRT_SECURE_NO_WARNINGS
#pragma once

#include <stdio.h>
#include <time.h>
#include <stdlib.h>


//Chessboard length and width
#define ROW 9
#define COL 9

#define ROWS ROW + 2
#define COLS COL + 2

#define EASY_COUNT 10 //Number of mines


//Initialize the chessboard
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char ch);

//Print the chessboard
void PrintBoard(char arr[ROWS][COLS], int row, int col);

//Set mines
void MineSet(char mine[ROWS][COLS], int row, int col);

//Look for thunder
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS],int row,int col);

               //The above is the header file part
//Test part
#define _CRT_SECURE_NO_WARNINGS

#include "game.h"

void menu()
{<!-- -->
printf("******************\
");
printf("**** 1.play ****\
");
printf("**** 0.exit ****\
");
printf("******************\
");
}

void game()
{<!-- -->
char show[ROWS][COLS];// '*'
char mine[ROWS][COLS];//'number'
//Initialization
InitBoard(show, ROWS, COLS, '*');
InitBoard(mine, ROWS, COLS, '0');
//Print the chessboard
//PrintBoard(mine, ROW, COL);
PrintBoard (show, ROW, COL);
//Set mines
MineSet (mine, ROW, COL);
//PrintBoard (mine, ROW, COL);
//Find mines
FindMine(mine,show, ROW, COL);
\t
}

int main()
{<!-- -->
int input=0;
srand((unsigned int)time(NULL));
do
{<!-- -->
menu();
printf("Please enter your choice:> ");
scanf("%d", & amp;input);
switch(input)
{<!-- -->
case 1:
printf("< Please note that there are %d mines in total in this round >\
", EASY_COUNT);
game();
break;
case 0:
printf("Game over\
");
break;
default:
printf("Input error, please re-enter!\
");
break;
}
} while (input);
\t
return 0;
}
                       //The above is the test part
//Main game part
#define _CRT_SECURE_NO_WARNINGS

#include "game.h"

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

void PrintBoard(char arr[ROWS][COLS], int row, int col)
{<!-- -->
int i = 0;
int j = 0;
printf("************************\
");
for (i = 0; i <= row; i + + )
{<!-- -->
printf("%d_", i);
}
printf("\
");
for (i = 1; i <= row; i + + )
{<!-- -->
printf("%d|", i );
for (j = 1; j <= col; j + + )
{<!-- -->
printf("%c ", arr[i][j]);
}
printf("\
");
}
printf("************************\
");
}

//Set mines
void MineSet(char mine[ROWS][COLS], int row, int col)
{<!-- -->
int count = 0;
while (count < EASY_COUNT)
{<!-- -->
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{<!-- -->
mine[x][y] = '1';
count + + ;
}
}
}


//Count the number of mines near this point
int MineCount(char mine[ROWS][COLS],int x,int y)
{<!-- -->
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i + + )
{<!-- -->
for (j = y - 1; j <= y + 1; j + + )
{<!-- -->
count =count + (mine[i][j] - '0');
}
}
return count;
}

//If there are no mines nearby, expand directly
void BlankExpansion(char mine[ROWS][COLS],char show[ROWS][COLS],int x,int y)
{<!-- -->
int i = 0;
int j = 0;
int count = MineCount(mine, x, y);
if (count == 0)
{<!-- -->
show[x][y] = ' ';
for (i = x - 1; i <= x + 1; i + + )
{<!-- -->
for (j = y - 1; j <= y + 1; j + + )
{<!-- -->
if (show[i][j] == '*')
{<!-- -->
BlankExpansion(mine, show, i, j);
}
}
}
}
else
{<!-- -->
show[x][y] = count + '0';
}

}

//Count the number of remaining *’
int LeftCount(char show[ROWS][COLS], int row, int col)
{<!-- -->
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i + + )
{<!-- -->
for (j = 1; j <= col; j + + )
{<!-- -->
if (show[i][j] == '*')
count + + ;
}
}
return count;
}

// Minesweeper
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{<!-- -->
int count = row * col;
int x = 0;
int y = 0;
while (count > EASY_COUNT)
{<!-- -->
printf("Please enter coordinates:> ");
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')
{<!-- -->
printf("What a pity, you were killed by lightning\
");
PrintBoard(mine, ROW, COL);
break;
}
else
{<!-- -->
BlankExpansion(mine, show, x, y);
count = LeftCount(show, ROW, COL);
PrintBoard(show, ROW, COL);
printf("Unknown points remaining: %d\
", count);
}
}
else
{<!-- -->
printf("Input coordinates are wrong, please re-enter\
");
}
}

if (count == EASY_COUNT)
{<!-- -->
printf("Congratulations, you won!\
");
}
\t
}
                      //Main game part

3. Detailed explanation

3.1 Menu section

Open the game program. The first step is to display the menu to remind the player to make a choice. The menu and code are as follows:

void menu()
{<!-- -->
printf("******************\
");
printf("**** 1.play ****\
");
printf("**** 0.exit ****\
");
printf("******************\
");
}

According to the player’s choice, different programs are entered. When the player selects 1, the game program is entered. When the player selects 0, the game ends. Considering that players cannot play the game just once, a loop part needs to be added at the beginning. The code is implemented as follows:

int main()
{<!-- -->
srand((unsigned int)time(NULL));//Generate random numbers
int input=0;
do
{<!-- -->
menu();
printf("Please enter your choice:> ");
scanf("%d", & amp;input);
switch(input)
{<!-- -->
case 1:
printf("< Please note that there are %d mines in total in this round >\
", EASY_COUNT);
game();
break;
case 0:
printf("Game over\
");
break;
default:
printf("Input error, please re-enter!\
");
break;
}
} while (input);
\t
return 0;
}

3.2 Main part of the game

3.2.1 Overall analysis

During the process of mine clearing, information about the mines deployed and the mines detected needs to be stored, so we need a certain data structure to store this information.
Because we need to arrange mine information and troubleshoot mines on a 9 * 9 chessboard, the first thing we think of is to create a 9 * 9 array to store the information.

Then if mines are arranged at this position, we will store 1, and if there are no mines, we will store 0.

Assume that when we check the coordinates (2, 5), we visit 8 locations in the surrounding circle, and the number of surrounding mines is 1.
Assume that when we check the coordinates (8, 6), we visit the surrounding 8 positions, and when counting the number of surrounding mines, the three lowest coordinates will cross the boundary. In order to prevent the boundary from crossing, we When designing, when expanding the array, the mines are still arranged at the 9 * 9 coordinates in the middle, and the mines are not arranged in the surrounding circles. This solves the problem of out-of-bounds. So it is more appropriate for us to create the array to store data as 11 * 11.


We have placed mines on the chessboard. The information of mines on the chessboard is (1) and the information of mines (0). Assume that after we check a certain position, this coordinate is not a mine, and there is 1 mine around this coordinate. Then we need to record and store the number of mines detected and print them out as important reference information for mine clearance. So where is the information about the number of mines stored? If stored in an array where mines are arranged, the mine information and the number of mines may be confused or cause printing difficulties.
We definitely have a way to solve this. For example: don’t use numbers for the information about thunder and thunder. Use certain characters instead. This will avoid conflicts. However, if you do this, there will be information about thunder and thunder on the chessboard. There is information on the number of mines detected, but it is more mixed and inconvenient.
At this time, we adopt another solution. We specifically store the arranged mine information on one chessboard (corresponding to two arrays mine), and then store the arranged mine information on another chessboard (corresponding to another array show). of thunder information. In this way, they will not interfere with each other, and the mines will be placed
mine array, check for mines in the mine array, store the checked data in the show array, and print the show array information for later troubleshooting reference.
At the same time, in order to maintain mystery, the show array is initialized to the character ‘*’ at the beginning. In order to keep the types of the two arrays consistent, the same set of functions can be used. The mine array is also initialized to the character ‘0’ at the beginning, and the layout is changed. into ‘1’. As follows:

The state after the mine is arranged in the mine array

show output initialization status

The corresponding array should be:

char mine[11][11] = {<!-- -->0};//? to store the arranged mine information

char show[11][11] = {<!-- -->0};//? to store the number information of the mines detected

In order to facilitate code management, the file content is divided into the following three aspects:

test.c //Write the test logic of the game in the file
game.c //?Write the implementation of functions in the game in the file, etc.
game.h //Write the data types and function declarations required by the game in the file

In order to facilitate later modification of the difficulty level, the row and column information can be modified using macros, as shown below:

//Chessboard length and width
#define ROW 9
#define COL 9

#define ROWS ROW + 2
#define COLS COL + 2

//Number of mines
#defineEASY_COUNT 10
 
//modified array
char show[ROWS][COLS];// '*'
char mine[ROWS][COLS];//'number'

3.2.2 Chessboard initialization

Before laying the groundwork, the two chessboards need to be initialized. In order not to affect the judgment when counting later, ROWS and COLS should be passed into the function at this time. In order for the initialization function to work on both arrays, the characters to be initialized must be passed in. code show as below:

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

3.2.3 Chessboard display

After initialization, you need to write a chessboard display function to display the initialization results of the chessboard and the subsequent display of different results. The code is as follows:

void PrintBoard(char arr[ROWS][COLS], int row, int col)
{<!-- -->
int i = 0;
int j = 0;
printf("************************\
");
for (i = 0; i <= row; i + + )
{<!-- -->
printf("%d_", i);
}
printf("\
");
for (i = 1; i <= row; i + + )
{<!-- -->
printf("%d|", i );
for (j = 1; j <= col; j + + )
{<!-- -->
printf("%c ", arr[i][j]);
}
printf("\
");
}
printf("************************\
");
}

It should be noted here that when passing in the array, you must pass in the whole 11 * 11 number in order to facilitate the overall control later, but when displaying, you only need to display The range of 9 * 9 is enough. The first and last lines are just added for the convenience of the statistics of mines later. The content of the first and last lines should not exist in the interface displayed to players /strong>.

3.2.4 Setting up mines

Randomly place the number of mines with the preselected setting EASY_COUBT in the mine array, that is, the number represented by EASY_COUBT. Use a random number generation function to generate random coordinates. If the symbol of this coordinate in the mine array is ’ 0 ’, put ’ 1 ’ in it, and use count to count so that the number of mines laid is less than the number represented by EASY_COUBT. code show as below:

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

It should be noted here that when laying out mines, the entire array is also passed over, but when performing mine operations, only the 1 to 9 row arrays are operated, and no operations are performed on the remaining two groups. In addition, because the result of rand() % row is a number between 0 ~ 8, one needs to be added to this to ensure that it only operates on 1 ~ 9.

3.2.5 Mine Clearance Phase

The player inputs a coordinate at will and first determines whether it is within the chessboard. If not, he is reminded to re-enter. If so, it is necessary to determine whether the point is mine. If so, the game ends directly. If not, then Count the number of mines nearby.

3.2.6 Code for counting the number of mines

int MineCount(char mine[ROWS][COLS],int x,int y)
{<!-- -->
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i + + )
{<!-- -->
for (j = y - 1; j <= y + 1; j + + )
{<!-- -->
count =count + (mine[i][j] - '0');
}
}
return count;
}

If the counted number is non-zero, the number of nearby mines will be directly displayed at the corresponding coordinates of the show array, as shown below:

If it is zero, the points near it need to be elevated, that is, all zero coordinates near it are changed to spaces in the show array until all nearby numbers are displayed as non-zero values, as shown below:

3.2.7 Expand using iteration:

When the number of mines near the coordinates entered by the player is zero, the eight coordinates near the coordinates will be judged to determine whether they are zero. If not, the number of mines near them will be directly displayed. If they are zero, , and call this function to judge the eight nearby coordinates, and keep looping until all nearby coordinates are non-zero. code show as below:

void BlankExpansion(char mine[ROWS][COLS],char show[ROWS][COLS],int x,int y)
{<!-- -->
int i = 0;
int j = 0;
int count = MineCount(mine, x, y);
if (count == 0)
{<!-- -->
show[x][y] = ' ';
for (i = x - 1; i <= x + 1; i + + )
{<!-- -->
for (j = y - 1; j <= y + 1; j + + )
{<!-- -->
if (show[i][j] == '*')
{<!-- -->
BlankExpansion(mine, show, i, j);
}
}
}
}
else
{<!-- -->
show[x][y] = count + '0';
}

}

3.2.8 Minesweeper part of the main code

void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{<!-- -->
int count = row * col;
int x = 0;
int y = 0;
while (count > EASY_COUNT)
{<!-- -->
printf("Please enter coordinates:> ");
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')
{<!-- -->
printf("What a pity, you were killed by lightning\
");
PrintBoard(mine, ROW, COL);
break;
}
else
{<!-- -->
BlankExpansion(mine, show, x, y);
count = LeftCount(show, ROW, COL);
PrintBoard(show, ROW, COL);
printf("Unknown points remaining: %d\
", count);
}
}
else
{<!-- -->
printf("Input coordinates are wrong, please re-enter\
");
}
}

if (count == EASY_COUNT)
{<!-- -->
printf("Congratulations, you won!\
");
}
\t
}

4. Summary

When passing parameters, you must remember that when passing an array, you must pass the entire array, but when operating on the array, only operate on lines 1 ~ 9, because the display interface that the player can see is only Lines 1 ~ 9, only the entire array needs to be operated during initialization.

The above is what the editor wants to share. If there is something wrong, you are welcome to discuss it in the message area.

syntaxbug.com © 2021 All Rights Reserved.