catalogue
preface
It's good to write a small Minesweeper today, which is roughly the same as that used in Sanzi last time. It adopts the method of dividing documents. It's recommended to eat this one after the last one. Some of the contents repeated last time will be briefly mentioned. Today, I don't say much and go straight to the point.
Code overview
test.c file
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void menu() { printf("************************\n"); printf("****** 1.game ******\n"); printf("****** 0.exit ******\n"); printf("************************\n"); } void game() { //Create an array of mines and an array displayed to the player char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; //Initialize mine array to all '0', show array to all '*' InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //Print chessboard DisplayBoard(show, ROW, COL); //Lay thunder SetMine(mine, ROW, COL); //mine clearance SweepMine(mine,show, ROW, COL); } void test_game() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("Please select->\n"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("Exit the game\n"); break; default: printf("Selection error, please re select\n"); break; } } while (input); } int main() { test_game(); return 0; }
game.c file
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = set; } } } void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 0; i <= row; i++) { printf("%2d ", i); } printf("\n"); for (i = 1; i <= row; i++) { printf("%2d ", i); for (j = 1; j <= col; j++) { printf("%2c ", board[i][j]); } printf("\n"); } } void SetMine(char mine[ROWS][COLS], int row, int col) { int CountMine = N;//N mines are needed while (CountMine) { int x = rand() % row + 1;//Number of 1-16 int y = rand() % col + 1;//Number of 1-16 if (mine[x][y] == '0') { mine[x][y] = '1';//Thunder is' 1 ' CountMine--; } } } void Open(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { int count = GetMine(mine, x, y); if (count == 0) { show[x][y] = ' ';//Change the position to a space so that the next recursion will not check the position if (show[x - 1][y] == '*') Open(mine, show, x - 1, y); if (show[x + 1][y] == '*') Open(mine, show, x + 1, y); if (show[x - 1][y + 1] == '*') Open(mine, show, x - 1, y + 1); if (show[x - 1][y - 1] == '*') Open(mine, show, x - 1, y - 1); if (show[x + 1][y - 1] == '*') Open(mine, show, x + 1, y - 1); if (show[x + 1][y + 1] == '*') Open(mine, show, x + 1, y + 1); if (show[x][y - 1] == '*') Open(mine, show, x , y - 1); if (show[x][y + 1] == '*') Open(mine, show, x , y + 1); } else show[x][y] = GetMine(mine, x, y)+'0'; } int GetMine(char mine[ROWS][COLS], int x, int y) { int count = mine[x - 1][y] + mine[x + 1][y] + mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y + 1] -8*'0'; return count; } void SweepMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0; int n = 1;//Prevent being killed for the first time while (win < row * col - N) { printf("Please enter the coordinates of the mine to be checked\n"); scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1' && n == 1) { mine[x][y] == '0';//The first time I met ray, I changed his position Open(mine, show, x, y);//Start with the input coordinates and expand around until you encounter thunder DisplayBoard(show, ROW, COL);//Print the current chessboard } if (mine[x][y] == '1') { printf("Congratulations on being blown up\n"); DisplayBoard(mine, ROW, COL);//Print the thunder disk again after being killed break; } else { Open(mine, show, x, y);//Start with the input coordinates and expand around until you encounter thunder DisplayBoard(show, ROW, COL);//Print the current chessboard } } else { printf("The coordinates are incorrect, please re-enter\n"); } n++; } if (win == row * col - N) { printf("Congratulations, you won\n"); DisplayBoard(mine, ROW, COL);//Print the thunder disk again after victory and have a look } }
game.h file
#define _CRT_SECURE_NO_WARNINGS 1 //Reference header file #include <stdio.h> #include <time.h> #include <stdlib.h> //Define constants #define ROW 16 #define COL 16 #define ROWS ROW+2 #define COLS COL+2 #define N 30 //Function declaration void InitBoard(char board[ROWS][COLS], int rows, int cols, char set); void DisplayBoard(char board[ROWS][COLS], int row, int col); void SetMine(char mine[ROWS][COLS], int row, int col); void SweepMine(char mine[ROWS][COLS],char show[ROWS][COLS] ,int row, int col);
Code analysis
Let's start to analyze the code. Oh, with the foreshadowing of the previous Sanzi chess, it should be easy to understand this time and open the whole game
The code of the panel part is the same as that of Sanzi chess, which is no longer explained
Let's start with the game () function
Here, first initialize two arrays, one is the mine array and the other is the show array. The mine array is used to place thunder and the show array is used to display to players. Note that ROWS and COLS are used to define the ROWS and columns of the array, and the values are ROW+2 and COL+2 respectively. Add two ROWS and two columns to the array for subsequent demining operations, which will be explained below
The initialization function is the same as that of Sanzi chess, respectively initializing the thunder disk as all '0' and the display disk as all '*'
The function of printing chessboard. Note that only ROW and COL columns need to be printed here, that is, we don't need to show the players the two additional rows and columns above. The printing format of% 2D and% 2C is used here for alignment and beauty. In order to allow players to input coordinates more intuitively, line numbers are added
Operation results:
Layout thunder: the operation is roughly the same as that of the last Sanzi chess
The following focuses on the demining function
First, sort out the logic:
1. We must not sweep the thunder to death in the first step of minesweeping, otherwise we will not be able to continue the game
2. If we are killed by thunder, we should have a look at the thunder disk
3. The winning condition is that the remaining positions on the chessboard that have not been swept are exactly equal to the total number of mines
4. We hope to achieve the following results:
That is, when there is no thunder around when sweeping a position, spread it around
Let's start gradually
First of all, if you encounter thunder for the first time, turn this thunder into no thunder! (because I'm too lazy to write here, that's it. In fact, it can be optimized)
It's similar to demining after not the first time
Let's look at the Open function, that is, if there is no thunder around, it will become blank
It should be noted here that if there are no mines around the eight positions of the input coordinates, first change this position to '' to prevent dead recursion from entering this position again during the next recursive call. Always check the eight positions around until there are mines around the eight positions. Here is the function to calculate the number of mines around:
Note that '1' in the mine array represents thunder. Here is the character number 1, and '0' needs to be subtracted to change the character number into a decimal number. Because the thunder disk is cleverly set with two rows and two columns, even if the coordinates entered here are at the edge of the chessboard, it can be calculated in this way,
Array out of bounds will not be generated
effect:
So far, all functions have been explained
summary
With the foundation of Sanzi chess, the difficulty of mine sweeping mainly lies in the application of recursion for blank expansion, but it is also easy to solve with a little understanding.
Sleep, sleep, roll again tomorrow