Minesweeping (recursive implementation version) - Happy New Year

Posted by rar_ind on Sun, 23 Jan 2022 10:01:28 +0100

  • catalogue

thinking

Clear logic.

menu

checkerboard

Initialization of two checkerboards

Lay thunder

mine clearance

Judge whether to win or lose

text.c implementation

game.c implementation

game.h implementation

Detailed explanation of recursive part

  • thinking

  • Clear logic.

For convenience, it is divided into three files: text C (test) game C (function implementation) game H (header file declaration)

In order to facilitate demining, we need to print the number of rows and columns corresponding to each row and column.

#define LEI 10
#define ROW 10
#define LOW 10

#define ROWS ROW+2
#define LOWS LOW+2
//When defining the length and width of the chessboard, 2 is specially added to mark the number of rows and columns.

 

 

  • menu

The printed menu only needs to have the options of starting the game and exiting the game

void menu()
{
	printf("*************************************\n");
	printf("************1.Start the game***************\n");
	printf("************0.Exit the game***************\n");
	printf("*************************************\n");

}
  • checkerboard

  1. Leipan
  2. checkerboard

Mine clearance needs to record mine information before demining. If using one chessboard is too complex, we use two chessboards, one for mine layout and one for player demining.

  • Initialization of two checkerboards

The chessboard initialization of the layout mine takes the character '0' as a non mine and the character '1' as a mine.

The player disk takes the character '*' as the place that has not been scanned

    board(arr1, ROWS, LOWS, '0');//Leipan
	board(arr2, ROWS, LOWS, '*');//Player disk

Because the initialization methods of the two are different, we use the parameter ret initialization

//Initialize chessboard
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < lows; j++)
		{
			arr1[i][j] = ret;
		}
	}
  • Lay thunder

The mine placement needs to be random, so two random numbers are used to locate the coordinates.

//Lay thunder
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
	int count = LEI;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % low + 1;
		if (arr1[x][y] == '0')
		{
			arr1[x][y] = '1';
			count--;
		}
	}
	//displayboard(arr1, ROW, LOW);// For testing
}
  • mine clearance

When we enter a coordinate, we need to know the number of mines around the coordinate and define a Get_num function to obtain the number of mines. However, at this time, only one coordinate information can be obtained. We know that general minesweeping will expand if the number of current coordinate mines is 0. This process is more complex, so we use recursive implementation

//Player disk
static int Get_num(char arr1[ROWS][LOWS],int x, int y)//Get the number of mines around the current coordinate
{
	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++)
		{
			if (arr1[i][j] == '1')
			{
				count++;
			}
		}

	}
	return count;
}
//Judge whether to expand and implement the function
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
	{
		int ret = Get_num(arr1, x, y);
		if (ret != 0)
			arr2[x][y] = ret + '0';//Record the number of mines
		//Recursive spreading
		else if (arr1[x][y] != ' ')
		{
			arr2[x][y] = '0';
			arr1[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					Judge(arr2, arr1, i, j);
				}
			}
		}
		else
		{
			return;
		}
	}
}
  • Judge whether to win or lose

Input: check the information corresponding to the mine disk once per row. If it is a mine, it will be killed. If not, continue to demine.

Win: when the player checks out all non mine areas, it is judged to win. (a counter is used here. The counter is used + + without discharging a mine. When the counter is the same as the total number of non mine areas, it is judged as winning)

void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("Please enter coordinates:>");
		scanf("%d,%d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
		{
			if (arr1[x][y] == '1')
			{
				arr2[x][y] = '#';
				displayboard(arr2, ROW, LOW);//mine clearance
				printf("I'm sorry you lost\n");
				break;
			}
			else
			{
				Judge(arr2, arr1, x, y);
				displayboard(arr2, ROW, LOW);//mine clearance
			}
		}
		else
		{
			printf("Input error!\n");
		}

		//Judge whether minesweeping wins
		int i = 0, flag = 0;
		for (i = 1; i <= ROW; i++)
		{
			int j = 0;
			for (j = 1; j <= LOW; j++)
			{
				if (arr2[i][j] != '*')
				{
					flag++;
				}
			}
		}
		if (flag == ROW*LOW - LEI)
		{
			printf("You win!\n");
			break;
		}
	}
}
  • text.c implementation

#define  _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
//menu
void menu()
{
	printf("*************************************\n");
	printf("************1.Start the game***************\n");
	printf("************0.Exit the game***************\n");
	printf("*************************************\n");

}


void game()
{
	//Initialize chessboard
	char arr1[ROWS][LOWS] = { 0 };//Leipan
	char arr2[ROWS][LOWS] = { 0 };//Player disk
	board(arr1, ROWS, LOWS, '0');
	board(arr2, ROWS, LOWS, '*');
	//Print chessboard
	//displayboard(arr1, ROW, LOW);// Lay thunder
	displayboard(arr2, ROW, LOW);//mine clearance
	//Lay thunder
	Get_lei(arr1,ROW,LOW);
	//mine clearance
	Out_lei(arr2,ROW,LOW, arr1);

}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("Please select:>");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
		{
			printf("mine clearance\n");
			game();
			break;
		}
		case 0:
		{
			printf("Exit the game\n");
			break;
		}
		default:
		{
			printf("Selection error\n");
			break;
		}
		}
	} while (input);

	return 0;
}
  • game.c implementation

#define  _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

//Initialize chessboard
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < lows; j++)
		{
			arr1[i][j] = ret;
		}
	}
}

//Print chessboard
void displayboard(char arr1[ROWS][LOWS], int row, int low)
{
	printf("<-—Minesweeper game -——>\n");
	int i = 0;
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		if (i == 1)
		{
			for (j = 0; j <= low; j++)
			{
				printf("%2d ", j);
			}
			printf("\n");
		}

		for (j = 1; j <= low; j++)
		{
			if (j == 1)
			{
				printf("%2d ", i);
			}
			
			printf("%2c ", arr1[i][j]);
		}
		printf("\n");
	}
	printf("<-—Minesweeper game -——>\n");

}

//Lay thunder
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
	int count = LEI;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % low + 1;
		if (arr1[x][y] == '0')
		{
			arr1[x][y] = '1';
			count--;
		}
	}
	//displayboard(arr1, ROW, LOW);
}
//Player disk
static int Get_num(char arr1[ROWS][LOWS],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++)
		{
			if (arr1[i][j] == '1')
			{
				count++;
			}
		}

	}
	return count;
}
//Determine whether to expand and implement the function
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
	{
		int ret = Get_num(arr1, x, y);
		if (ret != 0)
			arr2[x][y] = ret + '0';
		//Recursive scatter
		else if (arr1[x][y] != ' ')
		{
			arr2[x][y] = '0';
			arr1[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					Judge(arr2, arr1, i, j);
				}
			}
		}
		else
		{
			return;
		}
	}
}
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("Please enter coordinates:>");
		scanf("%d,%d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
		{
			if (arr1[x][y] == '1')
			{
				arr2[x][y] = '#';
				displayboard(arr2, ROW, LOW);//mine clearance
				printf("I'm sorry you lost\n");
				break;
			}
			else
			{
				Judge(arr2, arr1, x, y);
				displayboard(arr2, ROW, LOW);//mine clearance
			}
		}
		else
		{
			printf("Input error!\n");
		}

		//Judge whether minesweeping wins
		int i = 0, flag = 0;
		for (i = 1; i <= ROW; i++)
		{
			int j = 0;
			for (j = 1; j <= LOW; j++)
			{
				if (arr2[i][j] != '*')
				{
					flag++;
				}
			}
		}
		if (flag == ROW*LOW - LEI)
		{
			printf("You win!\n");
			break;
		}
	}
}


  • game.h implementation

#pragma once

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

#define LEI 10
#define ROW 10
#define LOW 10

#define ROWS ROW+2
#define LOWS LOW+2

//Initialize chessboard
void board(char arr1[ROWS][LOWS],int rows,int lows,char ret);

//Print chessboard
void displayboard(char arr1[ROWS][LOWS], int row, int low);

//Lay thunder
void Get_lei(char arr1[ROWS][LOWS], int row, int low);
//Player disk
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS]);
  • Detailed explanation of recursive part

Recursion condition: 1 There are conditions to stop. 2. Every recursion will approach this condition.

So what are the stop conditions here?

Recursion: when the number of returned mines is 0, it meets the condition of continuing recursion. We need to exclude all points around the current coordinate. And you need to mark the coordinates that have been checked, otherwise you will keep checking, and dead recursion will be formed. therefore

Stop condition: if the current coordinate has been checked, stop recursion.

Because each troubleshooting will be marked, this is the process of moving closer to the stop condition.

//Determine whether to expand and implement the function
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
	{
		int ret = Get_num(arr1, x, y);
		if (ret != 0)
			arr2[x][y] = ret + '0';
		//Recursive spreading
		else if (arr1[x][y] != ' ')
		{
			arr2[x][y] = '0';//Player disk
			arr1[x][y] = ' ';//Leipan
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					Judge(arr2, arr1, i, j);
				}
			}
		}
		else
		{
			return;
		}
	}
}

 

Topics: C Back-end