C language minesweeping

Posted by Catfish on Tue, 01 Feb 2022 00:40:15 +0100

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");
}

Topics: C Back-end