"Game" Summary of Thoughts on Writing Minesweeper

Sorted out mind map

Insert picture description heregame.h

#define _CRT_SECURE_NO_WARNINGS 1
 
#ifndef __GAME_H__
#define __GAME_H__
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
 
#define ROW 9
#define COL 9
#define ROWS (ROW+2)
#define COLS (COL+2)
#define EASY_MODE 10
 
 
int book[ROWS][COLS];
 
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void Init(char board[ROWS][COLS],  int row, int col, char ch);
void setMine(char mine[ROWS][COLS], int row, int col);
int FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int GetCount(char mine[ROWS][COLS], int x, int y);
void SafeMove(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void open(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
int CountShow(char show[ROWS][COLS], int row, int col);
 
#endif //__GAME_H_

test.c

#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()
{
	int is = 0;
 
	//mine 数组存储雷的位置 0 为空,1 为雷
	char mine[ROWS][COLS] = { 0 };
	//show 数组存储游戏盘,并且在每次点击后显示周围雷的个数
	char show[ROWS][COLS] = { 0 };
	
	//初始化mine 数组所有元素为'0',show 数组所有元素为'*'
	//Init(mine, show, ROWS, COLS);
	Init(mine, ROWS, COLS, '0');
	Init(show, ROWS, COLS, '*');
 
	//设置地雷
	setMine(mine, ROWS, COLS);
 
	//打印mine 数组
	DisplayBoard(mine, ROWS, COLS);
 
	printf("\n");
	printf("-------------------------\n");
	printf("\n");
 
	//打印游戏面板
	DisplayBoard(show, ROWS, COLS);
	//第一步不被炸死
	SafeMove(mine, show, ROWS, COLS);
 
	//如果面板上剩下的'*' 与地雷的总数相同时,玩家赢
	if (CountShow(show, ROWS, COLS) == EASY_MODE)
	{
		printf("-------------------------\n");
		DisplayBoard(mine, ROWS, COLS);
		printf("恭喜你!你赢了!\n");
		return;
	}
	
	/*DisplayBoard(mine, ROWS, COLS);
	printf("\n");
	printf("-------------------------\n");
	printf("\n");*/
	DisplayBoard(show, ROWS, COLS);
	
 
	while (1)
	{
		//判断玩家选择的坐标是不是地雷,若是则返回1,若不是则展开附近地雷信息
		is = FindMine(mine, show, ROWS, COLS);
		//如果面板上剩下的'*' 与地雷的总数相同时,玩家赢
		if (CountShow(show, ROWS, COLS) == EASY_MODE)
		{
			printf("-------------------------\n");
			DisplayBoard(mine, ROWS, COLS);
			printf("恭喜你!你赢了!\n");
			break;
		}
		
		if (is == 1)
		{
			printf("BOOM!!!!!!!!!!\n");
			printf("很遗憾,你被炸死了!\n");
			DisplayBoard(mine, ROWS, COLS);
			break;
		}
 
	/*	DisplayBoard(mine, ROWS, COLS);
		printf("\n");
		printf("-------------------------\n");
		printf("\n");*/
		DisplayBoard(show, ROWS, COLS);
 
	}
}
 
 
int main(void)
{
	int i = 0;
	int j = 0;
	int input = 0;
 
	srand((unsigned int)time(NULL));
 
	//调用菜单函数,打印游戏菜单
	menu();
 
	do
	{
		printf("请输入您要选的选项:");
		scanf("%d", &input);
		switch (input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("退出游戏!\n");
				break;
			default:
				printf("输入错误!请重新输入!\n");
				break;
		}
 
	} while (input);
 
	system("pause");
	return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
 
#include "game.h"
 
void Init(char board[ROWS][COLS],   int row, int col, char ch)
{
	memset(&board[0][0], ch, row*col*sizeof(board[0][0]));
}
 
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
 
	//打印横坐标
	printf("0 ");
	for (i = 1; i < row - 1; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
 
	for (i = 1; i < row - 1; i++)
	{
		printf("%d ", i);
		
		for (j = 1; j < col - 1; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
		
	}
}
 
void setMine(char mine[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = EASY_MODE;
 
 
	while (count)
	{
		//我们需要9个数字,如果%10产生的是0~8, 9个数字
		//但是我们需要1~9,所以先%9产生8个数字,再加1就好
		x = rand() % 9 + 1;
		y = rand() % 9 + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
 
//踩到雷返回1,没有踩到雷返回0
int FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = 0;
 
	
	printf("请输入您选择的坐标:");
	scanf("%d%d", &x, &y);
 
	if (x < 1 && x > COL && y < 1 && y > ROW)
	{
		printf("您输入的坐标超过当前地图,请重新输入!\n");
			
	}
	else
	{
		if (mine[x][y] == '0')
		{
			char ch = GetCount(mine, x, y);
			show[x][y] = ch + '0';
			book[x][y] = 1;
			open(mine, show, x, y);
			if (CountShow(show, row, col) == EASY_MODE)
			{
				return 0;
			}
		}
		else if (mine[x][y] == '1')
		{
			return 1;
		}
 
	}
	return 0;
}
 
int GetCount(char mine[ROWS][COLS], int x, int y)
{
	int count = 0;
	//分别对(x,y)坐标周围8个格子进行判断,如果是雷则count + 1
	//最后返回count就是(x,y)周围的地雷个数
	if (mine[x - 1][y] == '1')
		count++;
	if (mine[x - 1][y - 1] == '1')
		count++;
	if (mine[x][y - 1] == '1')
		count++;
	if (mine[x + 1][y - 1] == '1')
		count++;
	if (mine[x + 1][y] == '1')
		count++;
	if (mine[x + 1][y + 1] == '1')
		count++;
	if (mine[x][y + 1] == '1')
		count++;
	if (mine[x - 1][y + 1] == '1')
		count++;
 
	return count;
}
 
//SafeMove函数是保证玩家输入第一个坐标时不被炸死
void SafeMove(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int flag = 1;
	int count = 0;
	char ch = 0;
 
	while (1)
	{
		printf("请输入您要选择的坐标:");
		scanf("%d%d", &x, &y);
 
		if (x < 1 && x > COL && y < 1 && y > ROW)
		{
			printf("您输入的坐标超过当前地图,请重新输入!\n");
			continue;
		}
 
		if (mine[x][y] == '1')
		{
			//如果玩家输入的坐标是1,则强行把这个坐标改为0
			mine[x][y] = '0';
			char ch = GetCount(mine, x, y);
			show[x][y] = ch + '0';
			book[x][y] = 1;
			open(mine, show, x, y);
			//将一个地雷改为了空地,则需要再随机填一个雷
			while (flag)
			{
				x = rand() % 9 + 1;
				y = rand() % 9 + 1;
				if (mine[x][y] == '0')
				{
					mine[x][y] = '1';
					flag--;
					break;
				}
			}break;
		}
		else if (mine[x][y] == '0')
		{
			char ch = GetCount(mine, x, y);
			show[x][y] = ch + '0';
			book[x][y] = 1;
			open(mine, show, x, y);
			break;
		}
 
	}
 
}
 
//用深度优先搜索来对面板展开
void open(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	
	int tx = 0;
	int ty = 0;
	int k = 0;
	//定义next数组,用来对四个方向进行搜索
	int next[4][2] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
 
	//在展开的时候如果GetCount函数返回的不是0,则给show数组赋返回的值
	if (GetCount(mine, x, y) != 0)
	{
		show[x][y] = GetCount(mine, x, y) + '0';
	}
	//如果是0,给show数组那个位置赋空格
	else if (GetCount(mine, x, y) == 0)
	{
		show[x][y] = ' ';
	}
	
	for (k = 0; k <= 3; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
 
		if (tx < 1 || tx > ROW || ty < 1 || ty > COL)
		{
			continue;
		}
		if (mine[tx][ty] == '0' && book[tx][ty] == 0 && GetCount(mine, tx, ty) < 1)
		{
			
			book[tx][ty] = 1;
			open(mine, show, tx, ty);
		
		}
		//这一步很关键,是展开时遇到数字停下来的一步
		if (mine[tx][ty] == '0' && book[tx][ty] == 0 && GetCount(mine, tx, ty) > 0)
		{
			show[tx][ty] = GetCount(mine, tx, ty) + '0';
			continue;
		}
		
	}
	return;
}
 
//统计面板上剩下的'*'
int CountShow(char show[ROWS][COLS], int row, int col)//判断剩余未知区域的个数,个数为雷数时玩家赢
{
	int count = 0;
	int i = 0;
	int j = 0;
	for (i = 1; i < row - 1; i++)
	{
		for (j = 1; j < col - 1; j++)
		{
			if (show[i][j] == '*')
			{
				count++;
			}
		}
 
	}
	return count;
}

Guess you like

Origin blog.csdn.net/NanlinW/article/details/88781586