Using C language to realize the of small games -- [mine sweeping]

Posted by babybird11 on Tue, 25 Jan 2022 20:13:49 +0100

Use C language to realize a simple minesweeping game!

[game requirements]

[mine sweeping game]:

  1. Layout Thunder - 10
  2. Minesweeping: enter coordinates

It was thunder - > killed! game over!

Not Thunder - > tell you how many thunder there are on the eight coordinates around this coordinate.

Until all the non mine positions are found out, the mine sweeping is successful! game over!

[code implementation]

※ similar to the previous blog, the code of this game will also be completed in modules! That is, it is divided into three parts: function implementation (game.c), function declaration and symbol definition (game.h) and test (test.c)

The first is in test C to write a simple start menu. Use do While loop to get the correct input, use switch Case determines whether to start the game, exit the game, or reselect.

void menu()
{
	printf("*******************\n");
	printf("****** 1.play *****\n");
	printf("****** 0.exit *****\n");
	printf("*******************\n");

}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("Please enter:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("Exit the game\n");
			break;
		default:
			printf("Wrong choice, reselect!\n");
			break;
		}
	} while (input);
	return 0;
}

Then we're going to set up ray. How do we store data? We can use the array (9 * 9 two-dimensional array) to store it. Set the thunder place in the array to 1 and the non thunder place to 0, but this will be confused with the 1 indicating that there is a thunder around after clicking. We can change the marks of thunder and non thunder as * and # to solve this problem, but in this way, it needs to be screened when printing. The place of thunder cannot be printed as thunder, which is very troublesome. So we use the method of [two arrays] to solve it. Let's make another array separately. The two arrays are the same size and the coordinates correspond. One is an array char show [] [], which is specially used for printing (the information of detected mines, and the information of unchecked mines is represented by *), and the other is an array char mine [] [], which is specially used for storing (the information of arranged mines) of Mines ('1 ') or non mines ('0'). Now we need to solve another problem. Because we want to display the number of mines in the surrounding circle, we need to traverse the surrounding eight positions, but if it is a grid on the boundary, there will be an out of boundary problem, which is an out of boundary access for the array. So how can we solve this problem? Since you are afraid of boundary crossing, you might as well [open up one more circle] array, that is, two more rows and two more columns on the original basis. 9 * 9 - > 11 * 11. The middle 9 * 9 is really used. When detecting the number of mines, it will not cross the boundary. Then we can play in game In H, define ROW and COL are 9, and define ROWS and COLS are 11.

Then you can focus on the game() function. First define two arrays, and then initialize the array. We can write a function to initialize the array. Because the initialization contents of show array (initialized to '0') and mine array (initialized to '*') are different, we can use the initialization contents as a parameter of the function and define void init when writing the function_ board(char arr[ROWS][COLS], int rows, int cols, char set).

void init_board(char arr[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++)
		{
			arr[i][j] = set;
		}
	}
}

Then we need [print chessboard], and we define another function to print chessboard (only print 9 * 9). In order to enhance the playability of the game, we will add the serial numbers of the rows and columns in the first row and first column of the printing part, so as to make it clearer.

void show_board(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("--------mine clearance--------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
	printf("--------mine clearance--------\n");
}

This effect can be achieved:

 

Next, we will [lay out thunder], and we will use a set_mine function, which only needs to arrange mines in the middle 9 * 9 area. We can start at game The Symbolic Constant easy is defined in H_ Count is 10, which means that ten mines will be set in this minesweeping game. We choose to use random numbers to generate the location where the computer places the mine. Random numbers use rand () and srand() and time stamps. The specific principle can be seen in the introduction of random numbers in my last blog. First, do in our test function Before the loop of while, use srand((unsigned int)time(NULL)), and in game Add the relevant header files (stdlib.h and time.h) in H, and then you can use rand() function to generate random numbers in the function of laying mines to lay mines~

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

You can print out the mine array and check it:

 

Next, we're going to start [checking thunder]. You can write a find_mine(mine, show, ROW, COL) function to check the thunder. The first is to obtain the coordinates of the mine to be checked, and then judge whether it is legal. If it is not legal, it needs to be re entered. Therefore, a cycle is required. The condition for the cycle to jump out is to open all non mine places. Therefore, we use a variable win to count. Check this place after entering the correct coordinates. If this place is thunder, it will be killed. The game is over! If it's not a mine, count the number of mines by traversing the surrounding eight coordinates (we can define another function to calculate this value), then put the value in the show array, print the current show array, variable win+1, and finally judge whether to continue or jump out of the loop after all scanning.

The code implementation is as follows:

int get_mine_count(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';
}

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<row*col-EASY_COUNT)
	{
		printf("Please enter the coordinates to check:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("Unfortunately, he was killed!\n");
				show_board(mine, ROW, COL);
				break;
			}
			else
			{
				int count = get_mine_count(mine, x, y);
				show[x][y] = count + '0';
				show_board(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("Illegal coordinates, re-enter!\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("Congratulations on your success\n");
		show_board(mine, ROW, COL);
	}
}

[summary]

The symbolic constants, defined functions and header files used in our little game are roughly these

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

#define ROW 9
#define COL 9
#define EASY_COUNT 10

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

//initialization
void init_board(char arr[ROWS][COLS], int rows, int cols, char set);

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

//Lay thunder
void set_mine(char mine[ROWS][COLS], int row, int col);

//Check thunder
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

test.c is the framework of game execution

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void menu()
{
	printf("*******************\n");
	printf("****** 1.play *****\n");
	printf("****** 0.exit *****\n");
	printf("*******************\n");

}

void game()
{
	//Implementation of mine sweeping game
	char mine[ROWS][COLS] = { 0 };//Store the information of the arranged mine
	char show[ROWS][COLS] = { 0 };//Store the information of the detected mine
	//Initialize chessboard
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');
	//Print chessboard
	show_board(show, ROW, COL);
	//Lay thunder
	set_mine(mine, ROW, COL);
	//Check thunder
	find_mine(mine, show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("Please enter:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("Exit the game\n");
			break;
		default:
			printf("Wrong choice, reselect!\n");
			break;
		}
	} while (input);
	return 0;
}

The specific function code is in the above ~ I wish you a happy reading~

Another: there are two parts of the game that can be optimized and upgraded: the first is about [expand a piece], It can be realized recursively (as long as it is satisfied that the coordinates are not thunder and the eight surrounding are not thunder, it can be expanded, and the expanded coordinates can continue to expand as a new starting point. However, the expanded coordinates should be marked and will not be recursive the next time they arrive. That is, it can be expanded if it is satisfied that they are not thunder and the eight surrounding are not thunder and have not been checked.) The second is about the realization of [marker mine]. These are the optimizations that the code can make~

Topics: C Back-end