C language to achieve the "Minesweeper" game; Split the whole process;

Posted by LTJason on Fri, 18 Feb 2022 18:46:07 +0100

Read Suggestions

The Minesweeper game

Minesweeper games on Windows must be well known! Rules don't have to be said much, we write this game with the following analytical ideas

Analysis

Let's take a look at the Minesweeper interface, a half-played game

There are two parts in the picture, one that has been turned over (with mines) and the other that has not been turned over (without mines), which we can understand as two maps. So if we were to design a minesweeper game, would the first step be to create two binary arrays to represent the two maps?
Now that the map is created, let's look at it. There are small grids on the map. Do you want to record different information for each one? And are there two different states of lattices (flipped and unflipped)?

We found the starting point, can we start now?

Technological process:

Next let's comb the game process briefly:

Split Details

Step 1: Create a map and initialize ~

          1.Establish showMap,Initialize to All Yes' * . 
          2.Establish mineMap,Initialize all first'0',Randomly generate ten locations as mines, set as characters'1'. 

Let's see what we can do:

#include<stdio.h>
#include<time.h>
#define MINE_COUNT 10
#define MAX_ROW 9
#define MAX_COL 9 //Macros are set here to avoid magic numbers and make code more functional

void init(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL])
{
	for (int row = 0; row < MAX_ROW; row++)                         //In addition to circular assignment, we can also use the library function memset(ar,n,size) to assign all the variables of the array, noting that the header file <string is introduced. H>oh
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			showMap[row][col] = '*';                              	//memset(showMap, '*', MAX_ROW * MAX_COL);        
		}
	}
	for (int row = 0; row < MAX_ROW; row++)
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			mineMap[row][col] = '0';                               	//memset(mineMap, '0', MAX_ROW * MAX_COL);
		}
	}
	
	//Randomly generate ten locations as mines
	//Set random number seeds first
	srand((unsigned int)time(NULL));
	int mineCount = 0;                     //Here we need to define the number of mines in order to make a judgement about the following cycle
	while(mineCount<MINE_COUNT)
	{
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;        //There may be a problem here, if the ten random numbers are repeated? Ten mines must be in different locations, so we have the following actions
		//Determine if there is already a thunder at the current location
		if (mineMap[row][col] == '1')
		{
			continue;
		}
		mineMap[row][col] = '1';
		mineCount++;
	}
}

int main()
{
	//1. Create a map and initialize it
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };

	init(showMap, mineMap);

	return 0;
}

Step 2: Print the map showMap~

       To create a print function, it's best to have it print both maps at once

Let's see what we can do:

void Print(char theMap[MAX_ROW][MAX_COL])
{
	for (int row = 0; row < MAX_ROW; row++)
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			printf("*", theMap[row][col]);                       
		}
		printf("\n");
	}
}

Step 3: Ask the player to enter coordinates to indicate the position to be flipped~

 Enter coordinates The problem we will encounter here is: 
                  1.Does the player enter a position outside the range of the array?
                  2.Will the position entered by the player be turned over?
                 
        Then we need to make a validity decision! Let's take a look at the operation:
int main()	
{
	//1. Create a map and initialize it
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };

	init(showMap, mineMap);
	while (1)
	{
		//2. Print maps
		Print(showMap);

		// 3. Player input coordinates
		int row = 0;
		int col = 0;
		printf("Please enter coordinates(row, col):");
		scanf("%d %d", &row, &col);                 // Will the player make a mistake (out of range or the position entered has been turned over)? So we have to make a legality decision next
		//Make a legality decision                           
		if (row<0 || row>MAX_ROW || col<0 || col>MAX_COL)
		{
			printf("The coordinates you entered are incorrect! Please re-enter:\n");
			continue;
		}
		if (showMap[MAX_ROW][MAX_COL] != '*')
		{
			printf("The coordinates you entered have been flipped, please re-enter:\n");
			continue;
		}
	}
	return 0;
}

Step 4: Decide whether to step on a mine~

  It's very simple, using if A conditional sentence determines the current mineMap[row][col]Is 1 good?
		//4. Decide if you have trampled on a lightning
		if (mineMap[row][col] == '1')
		{
			printf("You stepped on the thunder, keep up!\n");
			break;
		}

Step 5: Update the showMap and turn it over to show how many mines are around it~

 The problem we are having here is:
     1.What is the range around this location? From the Minesweeper game we know there are eight grids around that location
     2.How does the location around it represent?
     3.What if this location appears on the edges and corners of the map? Is there a place around it that crosses the border?

I represent the coordinates of the surrounding locations on the following diagram:

Is it clear at a glance? We have to make a conditional judgment to look at this update function:

void update(char showMap[MAX_ROW][MAX_COL],
	char mineMap[MAX_ROW][MAX_COL], int row, int col)
{
	//Define the number of Mines
	int count = 0;
	//We need to make eight judgements here, which is apparently painful. We just need one circular judgement, traversing the eight locations around [row][col]
	for (int r = row - 1; r <= row + 1; r++)
	{
		for (int c = col - 1; c <= col + 1; c++)
		{
			if (r == row&&c == col)
			{
				//At this point [r][c] is in [row][col] position, directly next cycle without judgment
				continue;
			}
			if (r<0 || r>MAX_ROW || c<0 || c>MAX_COL)
			{
				//In this case, r, c coordinates are out of range of the array, beyond which they are skipped directly
				continue;
			}
			if (mineMap[r][c] == '1')
			{
				//R, the mineMap at C is a mine, count is added, the loop ends, and the value of count is passed to showMap[row][col];
				count++;
			}
		}
	}
	//If written as 	 showMap[row][col] ==count; At this time count=2, the current row, col position element is set to ASCII value of 2 "character", not 2
	//But in the ASCII code table, the ASCII value of n is exactly 48 bytes from the character n, and the character'0'is exactly 48 bytes.
	//So we can get n from'0'+ n
	//Note, however, that this is only an operation in the c language. In other mainstream programming languages, mixed operations of character and integer types are generally not allowed.
	showMap[row][col] = '0' + count;
}

Step 6: Decide if the player has opened all positions ~If not, go back to the second part of the process

 So how do we decide?  
 The easiest way to be rude is to set a counter and record it every time you turn it over.
 We have a total of 9*9=81 A grid, ten mines, is it true that when the counter reaches 71, only the mines remain unopened, and the game is won!
        int main()	
{
	while (1)
	{
        //6. Decide the victory of the game
		opendCount++;
		if (opendCount == MAX_ROW*MAX_COL-MINE_COUNT)
		{
			printf("Congratulations on your victory, how wonderful!\n");
			break;
		}
	}


	return 0;
}

Complete Code

We've finished all the steps, so let's clean up the code for entertainment!

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

#define _CRT_SECURE_NO_WARNINGS
#define MAX_ROW 9
#define MAX_COL 9 //Macros are set here to avoid magic numbers, make code clearer and easier to change
#define MINE_COUNT 10

void init(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL])
{
	for (int row = 0; row < MAX_ROW; row++)                         //In addition to circular assignment, we can also use the library function memset(ar,n,size) to assign values to all variables of an array
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			showMap[row][col] = '*';                              	//memset(showMap, '*', MAX_ROW * MAX_COL);        
		}
	}
	for (int row = 0; row < MAX_ROW; row++)
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			mineMap[row][col] = '0';                               	//memset(mineMap, '0', MAX_ROW * MAX_COL);
		}
	}

	//Randomly generate ten locations as mines
	//Set random number seeds first
	srand((unsigned int)time(0));
	int mineCount = 0;
	while (mineCount<MINE_COUNT)
	{
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;        //There may be a problem here, if the ten random numbers are repeated? Ten mines must be in different locations, so we have the following actions

		//Determine if there is already a thunder at the current location
		if (mineMap[row][col] == '1')
		{
			continue;
		}
		mineMap[row][col] = '1';
		mineCount++;
	}
}

//Hopefully this one will print two maps at the same time
//Depends on what the argument fills in
void Print(char theMap[MAX_ROW][MAX_COL])
{
	for (int row = 0; row < MAX_ROW; row++)
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			printf("%c ", theMap[row][col]);                       
		}
		printf("\n");
	}
}

void update(char showMap[MAX_ROW][MAX_COL],
	char mineMap[MAX_ROW][MAX_COL], int row, int col)
{
	//Define the number of Mines
	int count = 0;
	//We need to make eight judgements here, which is apparently painful. We just need one circular judgement, traversing the eight locations around [row][col]
	for (int r = row - 1; r <= row + 1; r++)
	{
		for (int c = col - 1; c <= col + 1; c++)
		{
			if (r == row&&c == col)
			{
				//At this point [r][c] is in [row][col] position, directly next cycle without judgment
				continue;
			}
			if (r<0 || r>MAX_ROW || c<0 || c>MAX_COL)
			{
				//In this case, r, c coordinates are out of range of the array, beyond which they are skipped directly
				continue;
			}
			if (mineMap[r][c] == '1')
			{
				//R, the mineMap at C is a mine, count is added, the loop ends, and the value of count is passed to showMap[row][col];
				count++;
			}
		}
	}
	//If written as 	 showMap[row][col] ==count; At this time count=2, the current row, col position element is set to ASCII value of 2 "character", not 2
	//But in the ASCII code table, the ASCII value of n is exactly 48 bytes from the character n, and the character'0'is exactly 48 bytes.
	//So we can get n from'0'+ n
	//Note, however, that this is only an operation in the c language. In other mainstream programming languages, mixed operations of character and integer types are generally not allowed.
	showMap[row][col] = '0' + count;
}

int main()	
{
	int opendCount = 0;
	//1. Create a map and initialize it
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };

	init(showMap, mineMap);
	while (1)
	{
		//2. Print maps
		Print(showMap);
		// 3. Player input coordinates
		int row = 0;
		int col = 0;
		printf("Please enter coordinates(row, col):");
		scanf("%d %d", &row, &col);                // Will the player make a mistake (out of range or the position entered has been turned over)? So we have to make a legality decision next
		//Make a legality decision                           
		if (row<0 || row>MAX_ROW || col<0 || col>MAX_COL)
		{
			printf("The coordinates you entered are incorrect! Please re-enter:\n");
			continue;
		}
		if (showMap[row][col] != '*')
		{
			printf("The coordinates you entered have been flipped, please re-enter:\n");
			continue;
		}

		//4. Decide if you have trampled on a lightning
		if (mineMap[row][col] == '1')
		{
			printf("You stepped on the thunder, keep up!\n");
			break;
		}

		//5. What if there were no mines? Do you want to update the showMap so that it shows how many mines are around it in the flip-up position? 
		//Let's make an update() function; What parameters do you want? We want to show that, so showMap is necessary, but we also need to know how many mines there are, so mineMap is also necessary, so don't bother with the rows and columns
		update(showMap,mineMap, row, col);
		//Clear the screen to make it clearer
		system("cls");

		//We can actually start playing here, but don't forget an important step,
		//That is to determine the success of the game, that is, to determine whether all positions that are not mines have been turned over

        //6. Decide the victory of the game
		opendCount++;
		if (opendCount == MAX_ROW*MAX_COL-MINE_COUNT)
		{
			printf("Congratulations on your victory, how wonderful!\n");
			break;
		}
	}


	return 0;
}

Topics: C Game Development