catalogue
Implementation of game operation
Determine whether the game is over
Calculate the number of nine palaces of gnere
preface
The original version of minesweeping can be traced back to 1973, a game called "square".
Soon, "square" was rewritten into the game "Rlogic". In "Rlogic", the player's task is to act as US Marine Corps Team members, find a safe route without mines for the command center. If all the roads are blocked by mines, you will lose. Two years later, Tom Anderson wrote the game "mine" on the basis of "Rlogic", which laid the prototype of modern mine clearance game.
In 1981, Robert Dole and Carter Johnson of Microsoft worked in windows 3 1 the game was loaded on the system, and the mine sweeping game was officially promoted all over the world.
This game is played by randomly arranging a certain number of mines in a 9 * 9 (primary), 16 * 16 (intermediate), 16 * 30 (Advanced) or custom size square matrix (10 for primary, 40 for intermediate and 99 for advanced). Players open the boxes one by one to find out all mines as the final goal of the game. If the player opens a box with mines, the game is over.
Realization idea
When we realize the minesweeping game, we should first master its rules of the game.
Taking the following figure as an example, we choose the position of the red circle. If it is not a thunder, the number of all thunder in the nine palace grid centered on it will be displayed in this position. If he is ray, the game is over. If this position shows n, it indicates that there are n mines in the eight positions around him.
The following figure is an example
The small red flag must be thunder, but the three positions on the right of number 2 are not thunder, but the one in the lower right corner can't judge who is thunder in the two positions above. We can check the position (4, 3) first, and then make further reasoning.
After mastering the rules of the game, let's implement this program.
Design of game framework
After the program runs, we need to have a main menu. After the game is over, we can return to the main menu and choose to start the game or exit the game.
Game interface design
At the beginning of the game, we should have a minefield interface (here I use the minefield of 9 * 9 lines. If you want to change it, you can modify the values of ROW and COL in the header file), and then there is a prompt to select the operation. In order to make it convenient for players to find the corresponding position, I have made an output of ROW and column numbers here. After each operation, the player uses the system("cls") screen clearing function.
Before outputting the minefield interface, two two-dimensional arrays are used to store the mine position information mine[ROWS][COLS] and the character show[ROWS][COLS] of the output interface respectively. (here, ROWS = ROW + 2 and COLS = COL + 2 are used to prevent boundary array elements from crossing the boundary when calculating the number of mines)
In the end interface, the minelaying map needs to be displayed to the player for success or failure of minesweeping, and the corresponding prompt is given. Here I use the Sleep(3000) function to make the end interface stay for three seconds. (the parameter of Sleep() function is in milliseconds in VC environment, but in Linux environment, it is in seconds, which should be noted here.)
Implementation of game operation
Lay thunder
Before conducting mine screening, mines should be randomly arranged in the minefield. (the number of Mines cannot exceed the space in the minefield) the timestamp is used here to randomly generate mines. Obtain the timestamp through time(), and then through srand() rand() The combined use of produces false random number Sequence and arrange the mine.
Check thunder
First of all, it should be clear that only the locations that have not been checked and marked can be checked.
If the location checked is thunder, the game is over.
If the detected location is not a mine, the number of surrounding mines will be displayed at this location.
However, in the mine sweeping game, there will actually be a function of expanding one area. When the number of mines in a circle around the position to be checked is zero, it will continue to check eight positions in a circle around and display the number of mines around those positions.
Mark mine
After judging that a location is a mine, we should mark it to prevent stepping on it next time.
So we design a function to mark thunder.
1. We can only mark locations that have not been checked
2. The marked position cannot be checked
3. The marked position can be unmarked
Judgment of game state
There are only two situations that can end the game when we conduct mine clearance:
1. If the location of the player's investigation is thunder, the player is killed and the game is over
2. After the player checks all non mine areas, the player wins and the game ends, that is, the total number of unchecked positions and marked positions is equal to the total number of Mines arranged.
Function function
Initialization function
//One more parameter set is convenient for arranging thunder and printing chessboard void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set) { int i = 0, j = 0; for (i = 0; i < rows;i++) { for (j = 0;j < cols;j++) { arr[i][j] = set; } } }
Print chessboard
void ShowBoard(char show[ROWS][COLS], int row, int col) { printf("------------------mine clearance------------------\n"); int i = 0, j = 0; printf(" |"); //Print line number for (i = 1;i <= row;i++) { printf(" %d ", i); if (i<row) { printf("|"); } } printf("\n"); for (i = 1;i <= row;i++) { for (j = 0;j <= col;j++) { printf("---"); if (j < col) { printf("|"); } } //Print column number printf("\n %d |", i); //Minefield for (j = 1;j <= col;j++) { printf(" %c ", show[i][j]); if (j < col) { printf("|"); } } printf("\n"); } printf("------------------mine clearance------------------\n"); }
Lay thunder
void SetMine(char mine[ROWS][COLS], int row, int col) { int count = MINES; int x = 0, y = 0; //The count of each thunder is reduced by 1 until the thunder cloth is set while (count) { x = rand() % row + 1; y = rand() % row + 1; //It can only be arranged if there is no thunder at this position if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } }
Determine whether the game is over
//When the player wins, the game returns 0 when the game is over, and 1 when the game is not over int IsWin(char show[ROWS][COLS], int row, int col) { int i = 0, j = 0; int count = 0; for (i = 1;i <= row;i++) { for (j = 1;j <= col;j++) { //Only when the position is * or #, it will be recorded as the remaining operable area, //When the remaining operable area is equal to the number of mines, the game wins if (show[i][j] == '*' || show[i][j] == '#') { count++; } } } //If the unopened area and marked area are equal to the number of mines, it returns 0, otherwise it returns 1 if (count == MINES) return 0; else return 1; }
Calculate the number of nine palaces of gnere
int GetMines(char mine[ROWS][COLS], int x, int y) { //If it is thunder, the position is character 1, and the number of thunder can be obtained by subtracting eight characters 0 return mine[x-1][y-1] + mine[x-1][y] + mine[x-1][y+1] + mine[x][y-1] + mine[x][y+1] + mine[x+1][y-1] + mine[x+1][y] + mine[x+1][y+1] - 8 * '0'; }
Extended demining
void ExpandMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { //If there is no thunder around the location, search and expand the surrounding 8 blocks if (GetMines(mine, x, y) == 0) { //All expanded positions are set to 0 show[x][y] = '0'; int i = 0; int j = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { //Only when the position is not opened can it be retrieved, and the retrieval position should be within the chessboard if (show[i][j] == '*' && i > 0 && i <= ROW && j > 0 && j <= COL) { ExpandMine(mine, show, i, j); } } } } else { //If it is not necessary to expand, the number of nearby mines will be displayed show[x][y] = GetMines(mine, x, y) + '0'; } }
Mark mine
void SignMine(char show[ROWS][COLS], int row, int col) { int x = 0, y = 0; printf("Please enter coordinates;>"); scanf("%d %d", &x, &y); //Mark mine if (show[x][y] == '*') { show[x][y] = '#'; } //Unmark else if (show[x][y] == '#') { show[x][y] = '*'; } //If this position is opened, it cannot be marked else printf("Marking failed"); }
Check thunder
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0, y = 0; while (IsWin(show, row, col)) { int input = 0; //1. Mine detection //2. Marking mine //For each operation, you can choose whether to check mines or mark mines do { printf("Please select action 1.Check thunder 2.Mark mine:>"); scanf("%d", &input); switch (input) { //Check thunder case 1: printf("Please enter coordinates;>"); scanf("%d %d", &x, &y); if (x > 0 && x <= row && y > 0 && y <= col && show[x][y] != '#') { if (mine[x][y] == '1') { system("cls"); printf("I'm sorry you were killed\n"); ShowBoard(mine, ROW, COL); Sleep(3000); //Get blown up and quit return ; } else { ExpandMine(mine, show, x, y); system("cls"); ShowBoard(show, ROW, COL); } } else { //If this position is marked, it cannot be checked if (show[x][y] == '#') { printf("This position is marked as mine, please re-enter\n"); } //If the inspection position is out of bounds, an error will be reported else printf("Illegal coordinates, please re-enter\n"); } break; //Mark mine case 2: SignMine(show, row, col); system("cls"); ShowBoard(show, ROW, COL); break; default: break; } } while (IsWin(show, row, col));//The cycle ends when the player wins or steps on thunder } //If the player sweeps the mine successfully, the minelaying map will be displayed if (!IsWin(show, row, col)) { system("cls"); printf("Congratulations on your successful mine clearance!:>\n"); ShowBoard(mine, ROW, COL); Sleep(3000); } }
source file
game.h
#pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #include<windows.h> #define ROW 9 #define COL 9 #define ROWS ROW + 2 #define COLS COL + 2 //The number of mines shall be less than or equal to ROW*COL #define MINES 80 //1. Marking //2. Expand one //Initialize chessboard void InitBoard(char arr[ROWS][COLS], int row, int col, char set); //Print chessboard void ShowBoard(char show[ROWS][COLS], int row, int col); //Lay thunder void SetMine(char show[ROWS][COLS], int row, int col); //Check thunder void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //Mark mine void SignMine(char show[ROWS][COLS], int row, int col);
game.c
#include"game.h" //Initialize chessboard //One more parameter set is convenient for arranging thunder and printing chessboard void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set) { int i = 0, j = 0; for (i = 0; i < rows;i++) { for (j = 0;j < cols;j++) { arr[i][j] = set; } } } //Print chessboard void ShowBoard(char show[ROWS][COLS], int row, int col) { printf("------------------mine clearance------------------\n"); int i = 0, j = 0; printf(" |"); for (i = 1;i <= row;i++) { printf(" %d ", i); if (i<row) { printf("|"); } } printf("\n"); for (i = 1;i <= row;i++) { for (j = 0;j <= col;j++) { printf("---"); if (j < col) { printf("|"); } } printf("\n %d |", i); for (j = 1;j <= col;j++) { printf(" %c ", show[i][j]); if (j < col) { printf("|"); } } printf("\n"); } printf("------------------mine clearance------------------\n"); } //Lay thunder void SetMine(char mine[ROWS][COLS], int row, int col) { int count = MINES; int x = 0, y = 0; //The count of each thunder is reduced by 1 until the thunder cloth is set while (count) { x = rand() % row + 1; y = rand() % row + 1; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } } //Determine whether the game is over int IsWin(char show[ROWS][COLS], int row, int col) { int i = 0, j = 0; int count = 0; for (i = 1;i <= row;i++) { for (j = 1;j <= col;j++) { //Only when the position is * or #, it will be recorded as the remaining operable area, //When the remaining operable area is equal to the number of mines, the game wins if (show[i][j] == '*' || show[i][j] == '#') { count++; } } } //If the unopened area and marked area are equal to the number of mines, it returns 0, otherwise it returns 1 if (count == MINES) return 0; else return 1; } //Calculate the number of surrounding mines int GetMines(char mine[ROWS][COLS], int x, int y) { return mine[x-1][y-1] + mine[x-1][y] + mine[x-1][y+1] + mine[x][y-1] + mine[x][y+1] + mine[x+1][y-1] + mine[x+1][y] + mine[x+1][y+1] - 8 * '0'; } //Extended demining void ExpandMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { //If there is no thunder around the location, search and expand the surrounding 8 blocks if (GetMines(mine, x, y) == 0) { //All expanded positions are set to 0 show[x][y] = '0'; int i = 0; int j = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { //Only when the position is not opened can it be retrieved, and the retrieval position should be within the chessboard if (show[i][j] == '*' && i > 0 && i <= ROW && j > 0 && j <= COL) { ExpandMine(mine, show, i, j); } } } } else { //If it is not necessary to expand, the number of nearby mines will be displayed show[x][y] = GetMines(mine, x, y) + '0'; } } //Check thunder void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0, y = 0; while (IsWin(show, row, col)) { int input = 0; //1. Mine detection //2. Marking mine //For each operation, you can choose whether to check mines or mark mines do { printf("Please select action 1.Check thunder 2.Mark mine:>"); scanf("%d", &input); switch (input) { //Check thunder case 1: printf("Please enter coordinates;>"); scanf("%d %d", &x, &y); if (x > 0 && x <= row && y > 0 && y <= col && show[x][y] != '#') { if (mine[x][y] == '1') { system("cls"); printf("I'm sorry you were killed\n"); ShowBoard(mine, ROW, COL); Sleep(3000); //Get blown up and quit return ; } else { ExpandMine(mine, show, x, y); system("cls"); ShowBoard(show, ROW, COL); } } else { //If this position is marked, it cannot be checked if (show[x][y] == '#') { printf("This position is marked as mine, please re-enter\n"); } //If the inspection position is out of bounds, an error will be reported else printf("Illegal coordinates, please re-enter\n"); } break; //Mark mine case 2: SignMine(show, row, col); system("cls"); ShowBoard(show, ROW, COL); break; default: break; } } while (IsWin(show, row, col));//The cycle ends when the player wins or steps on thunder } //If the player sweeps the mine successfully, the minelaying map will be displayed if (!IsWin(show, row, col)) { system("cls"); printf("Congratulations on your successful mine clearance!:>\n"); ShowBoard(mine, ROW, COL); Sleep(3000); } } //Mark mine void SignMine(char show[ROWS][COLS], int row, int col) { int x = 0, y = 0; printf("Please enter coordinates;>"); scanf("%d %d", &x, &y); //Mark mine if (show[x][y] == '*') { show[x][y] = '#'; } //Unmark else if (show[x][y] == '#') { show[x][y] = '*'; } //If this position is opened, it cannot be marked else printf("Marking failed"); }
test.c
#include"game.h" void game() { char Mine[ROWS][COLS] = { 0 }; char Show[ROWS][COLS] = { 0 }; //Initialize the minefield and game interface first InitBoard(Mine, ROWS, COLS, '0'); InitBoard(Show, ROWS, COLS, '*'); //Lay thunder SetMine(Mine, ROW, COL); //Display hidden minefields ShowBoard(Show, ROW, COL); //If cheating is required, the mined area after arrangement can be displayed directly /*ShowBoard(Mine, ROW, COL);*/ //Game operation function FindMine(Mine, Show, ROW, COL); system("cls"); } //Main menu void menu() { printf("+---------------------------+\n"); printf("| 1. play |\n"); printf("| 0. exit |\n"); printf("+---------------------------+\n"); } //Test function void test() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("Please select:>\n"); scanf("%d", &input); switch (input) { case 1: system("cls"); game(); break; case 0: printf("Exit the game\n"); break; default: break; } } while (input); } int main() { test(); return 0; }
This is the end of the article. Thank you for reading.