C language minesweeping
The code implementation of mine sweeping is similar to that of Sanzi chess. The main difference lies in the implementation of game code
Divided into three files to write test c ,game.h ,game.c
test.c: Used to implement the overall framework and test code
game.h: Used for symbol definition, function declaration and header file reference
game.c: Implement game code with
Overall framework
First, print the menu for players to choose
- Select 1: enter the game, the game ends, break jumps out of multiple branches, at this time, the input value is 1, and the cycle continues. It realizes the need to play another one after playing one
- Select 0: the print prompt break jumps out of multiple branches. At this time, the input value is 0 and the cycle stops. Program end
- Select other: the print prompt break jumps out of multiple branches. At this time, the input value is non-0, and the cycle continues
// Create menu -- you can modify it to the desired style void menu() { printf("**************************\n"); printf("******** 1.play ********\n"); printf("******** 0.exit ********\n"); printf("**************************\n"); } int main() { int input = 0; srand((unsigned int)time(NULL)); // Used to seed random numbers do { menu(); printf("Please select:>"); scanf("%d", &input); switch (input) { case 1: system("cls"); // Clear screen - you can add it where you want game(); break; case 0: printf("Exit the game\n"); break; default: printf("Wrong selection, please re-enter\n"); break; } } while (input); return 0; }
Game framework
Clarify the execution order of the game
- Define two arrays. Mine array is used to store mine information and show array is used to display to players. Macro definition is adopted to facilitate future expansion.
- Initialize two arrays, mine array to '0' and show array to '*'.
- Set the mine and store the mine information in the mine array.
- Print the chessboard, which is stored in the show array.
- Specific details of demining
void game() { char mine[ROWS][COLS] = { 0 }; // Location for storing mines char show[ROWS][COLS] = { 0 }; // For display to users // Initialize array InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); // Set mine SetMine(mine, ROW, COL); //PrintBoard(mine, ROW, COL); // If you need an answer, remove the comment from this line PrintBoard(show, ROW, COL); // Print the chessboard for players to start the game // mine clearance FindMine(mine, show, ROW, COL); }
Concrete implementation
Initialize chessboard
Sets the chessboard to the specified initialization format
All show arrays are initialized to '0'
All mine arrays are initialized to '*'
// Initialize chessboard void InitBoard(char board[ROWS][COLS], int row, int col, char set) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = set; // Initially in the specified format } } }
Set mine
Use random numbers to generate mines – set the coordinates of mines to '1'
// Set mine void SetMine(char board[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1; // 1 ~ 9 int y = rand() % col + 1; // 1 ~ 9 if ('0' == board[x][y]) { board[x][y] = '1'; count--; } } }
Print chessboard
Print out the chessboard for players to start minesweeping. The format can be designed by themselves. Here, it is ensured that there will be no dislocation of the chessboard in the size of 1 ~ 99. The size of the chessboard is not recommended to exceed 70, otherwise the program is easy to crash
// Print chessboard void PrintBoard(char board[ROWS][COLS], int row, int col) { int i = 0; // Print column labels for (i = 0; i <= row; i++) { printf(" %-3d", i); } printf("\n\n"); // Print each line for (i = 1; i <= row; i++) { int j = 0; printf("%2d", i); // Print line mark for (j = 1; j <= col; j++) { printf("%4c", board[i][j]); } printf("\n\n"); } }
mine clearance
The main realization of mine clearance. In this paper, mine clearance mainly uses three inputs to play the game (horizontal and vertical coordinates and whether to mark - 1 is the mark, this coordinate is mine, the other numbers are not marked, and they are opened normally). At the same time, it also realizes the functions of never stepping on mine for the first time and expanding a large area at a time
// Check thunder void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int flag = 0; // Used to determine whether to mark int first = 1; // It is used to ensure that the first time is not thunder, and it is only executed once while (IsWin(show, ROW, COL) != 1) { printf("Please enter the coordinates to check:>"); scanf("%d %d %d", &x, &y, &flag);// Three inputs are used, the abscissa and ordinate and whether to mark the mine as 1. Mark it as mine, and other numbers are not marked as normal opening if (x >= 1 && x <= row && y >= 1 && y <= col) // Judge whether the input is legal { if (1 == flag) // Judge whether to mark mine { SignMine(show, x, y); continue; } // Judge whether to step on Thunder for the first time if (1 == first) { IsFirstStepMine(mine, x, y); first = 0; } if ('1' == mine[x][y]) { printf("I'm sorry, you were killed by thunder!\n"); PrintBoard(mine, ROW, COL); break; } else { system("cls"); // Clear screen show[x][y] = '0' + GetMineCount(mine, x, y); // Display the thunder number in the nine palaces to the user // Expand a piece if ('0' == show[x][y]) CleanMore(mine, show, x, y); PrintBoard(show, ROW, COL); } } else { printf("The coordinates entered are illegal, please re-enter!\n"); } } if (IsWin(show, ROW, COL) == 1) printf("Congratulations, you won!\n"); }
Number of Mines acquired
The problem here is how to deal with the edges and corners, and it is impossible to traverse the nearby Jiugong lattice. There are two main methods - the second one is used in this paper
- Judge the coordinates, and return the number of mines in the legal coordinates if the boundary is ignored
- In order to prevent the cross-border problem, we can also add a circle directly outside the chessboard. The original 9 * 9 chessboard is changed into 11 * 11 chessboard, so that the cross-border problem will not occur
// Get the number of nine palaces of gnere static int GetMineCount(char mine[ROWS][COLS], int x, int y) { int count = 0; int i = 0; for (i = x - 1; i <= x + 1; i++) { int j = 0; for (j = y - 1; j <= y + 1; j++) { count += mine[i][j]; } } return count - 9 * '0'; // The characters stored on the chessboard are converted into numbers by subtracting the character 0 }
Judge whether to step on Thunder for the first time
If the first coordinate is mine, first find a coordinate that is not mine, set the mine here, and then set the original coordinate as mine coordinate and set it as non mine
// Judge whether to step on Thunder for the first time static void IsFirstStepMine(char mine[ROWS][COLS], int x, int y) { while ('1' == mine[x][y]) { int m = rand() % ROW + 1; int n = rand() % COL + 1; if ('0' == mine[m][n]) { mine[m][n] = '1'; mine[x][y] = '0'; } } }
Mark mine
Because the keyboard operation is not convenient, only one layer of marks is set
Mark the specified coordinates and set it to '?', Mark again and restore to '*'
// Mark mine static SignMine(char show[ROWS][COLS], int x, int y) { if ('*' == show[x][y]) show[x][y] = '?'; else if ('?' == show[x][y]) show[x][y] = '*'; system("cls"); PrintBoard(show, ROW, COL); }
Judge whether to win
Traverse the chessboard and count the number of unchecked and marked mines to see if it is the same as the set number of mines. The same is the win
// Judge whether to win static int IsWin(char show[ROWS][COLS], int row, int col) { int count = 0; int i = 0; for (i = 1; i <= row; i++) { int j = 0; for (j = 1; j <= col; j++) { if ('*' == show[i][j] || '?' == show[i][j]) // Count the number of Mines marked and unchecked count++; // Equal to the total number of mines, win } } return count == EASY_COUNT; }
Expand a piece
If there is no thunder in the nine palace grid, uncover the rest of the grid, and then judge whether there is thunder. If there is no thunder, continue to expand and implement recursively
// Use recursion to expand a piece static void CleanMore(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { int i = 0; show[x][y] = ' '; // Replace '0' with '' for beauty for (i = x - 1; i <= x + 1; i++) { int j = 0; for (j = y - 1; j <= y + 1; j++) { if (i < 1 || i > ROW || j < 1 || j > COL) // Illegal coordinates continue; if ('*' == show[i][j]) // Expand unexpanded, expanded, skipped { show[i][j] = '0' + GetMineCount(mine, i, j); if ('0' == show[i][j]) CleanMore(mine, show, i, j); } } } }
Complete code
test.c
#include "game.h" // Print menu - self designed void menu() { printf("************************\n"); printf("******** 1.play ********\n"); printf("******** 0.exit ********\n"); printf("************************\n"); } void game() { char mine[ROWS][COLS] = { 0 }; // Location for storing mines char show[ROWS][COLS] = { 0 }; // For display to users // Initialize array InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); // Set mine SetMine(mine, ROW, COL); //PrintBoard(mine, ROW, COL); // If you need an answer, remove the comment from this line PrintBoard(show, ROW, COL); // mine clearance FindMine(mine, show, ROW, COL); } int main() { int input = 0; srand((unsigned int)time(NULL)); // Set random number seed do { menu(); printf("Please select:>"); scanf("%d", &input); switch (input) { case 1: system("cls"); game(); break; case 0: printf("Exit the game\n"); break; default: printf("Wrong selection, please re-enter\n"); break; } } while (input); return 0; }
game.h
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #include <Windows.h> // Define the size of the chessboard -- it is not recommended to exceed 60 ~ 70, otherwise the program will crash #define ROW 9 #define COL 9 // Expand the size of the chessboard to prevent cross-border #define ROWS ROW + 2 #define COLS COL + 2 // Define the number of Mines -- the number of Mines cannot exceed the size of the chessboard #define EASY_COUNT 10 // Initialize array void InitBoard(char board[ROWS][COLS], int row, int col, char set); // Print array void PrintBoard(char board[ROWS][COLS], int row, int col); // Set mine void SetMine(char board[ROWS][COLS], int row, int col); // mine clearance void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c
#include "game.h" // Initialize chessboard void InitBoard(char board[ROWS][COLS], int row, int col, char set) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = set; // Initially in the specified format } } } // Print chessboard void PrintBoard(char board[ROWS][COLS], int row, int col) { int i = 0; // Print column labels for (i = 0; i <= row; i++) { printf(" %-3d", i); } printf("\n\n"); // Print each line for (i = 1; i <= row; i++) { int j = 0; printf("%2d", i); // Print line mark for (j = 1; j <= col; j++) { printf("%4c", board[i][j]); } printf("\n\n"); } } // Set mine void SetMine(char board[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1; // 1 ~ 9 int y = rand() % col + 1; // 1 ~ 9 if ('0' == board[x][y]) { board[x][y] = '1'; count--; } } } // Get the number of nine palaces of gnere static int GetMineCount(char mine[ROWS][COLS], int x, int y) { int count = 0; int i = 0; for (i = x - 1; i <= x + 1; i++) { int j = 0; for (j = y - 1; j <= y + 1; j++) { count += mine[i][j]; } } return count - 9 * '0'; } // Judge whether to step on Thunder for the first time static void IsFirstStepMine(char mine[ROWS][COLS], int x, int y) { while ('1' == mine[x][y]) { int m = rand() % ROW + 1; int n = rand() % COL + 1; if ('0' == mine[m][n]) { mine[m][n] = '1'; mine[x][y] = '0'; } } } // Use recursion to expand a piece static void CleanMore(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { int i = 0; show[x][y] = ' '; // Replace '0' with '' for beauty for (i = x - 1; i <= x + 1; i++) { int j = 0; for (j = y - 1; j <= y + 1; j++) { if (i < 1 || i > ROW || j < 1 || j > COL) // Illegal coordinates continue; if ('*' == show[i][j]) // Expand unexpanded { show[i][j] = '0' + GetMineCount(mine, i, j); if ('0' == show[i][j]) CleanMore(mine, show, i, j); } } } } // Judge whether to win static int IsWin(char show[ROWS][COLS], int row, int col) { int count = 0; int i = 0; for (i = 1; i <= row; i++) { int j = 0; for (j = 1; j <= col; j++) { if ('*' == show[i][j] || '?' == show[i][j]) // Count the number of Mines marked and unchecked count++; // Equal to the total number of mines, win } } return count == EASY_COUNT; } // Mark mine static SignMine(char show[ROWS][COLS], int x, int y) { if ('*' == show[x][y]) show[x][y] = '?'; else if ('?' == show[x][y]) show[x][y] = '*'; system("cls"); PrintBoard(show, ROW, COL); } // Check thunder void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int flag = 0; // Used to determine whether to mark int first = 1; // It is used to ensure that the first time is not thunder, and it is only executed once while (IsWin(show, ROW, COL) != 1) { printf("Please enter the coordinates to check:>"); scanf("%d %d %d", &x, &y, &flag); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (1 == flag) { SignMine(show, x, y); continue; } // Judge whether to step on Thunder for the first time if (1 == first) { IsFirstStepMine(mine, x, y); first = 0; } if ('1' == mine[x][y]) { printf("I'm sorry, you were killed by thunder!\n"); PrintBoard(mine, ROW, COL); break; } else { system("cls"); // Clear screen show[x][y] = '0' + GetMineCount(mine, x, y); // Expand a piece if ('0' == show[x][y]) CleanMore(mine, show, x, y); PrintBoard(show, ROW, COL); } } else { printf("The coordinates entered are illegal, please re-enter!\n"); } } if (IsWin(show, ROW, COL) == 1) printf("Congratulations, you won!\n"); }