java递归排雷_C语言实现扫雷小游戏
源代码链接:https://github.com/Sasura321/Minesweeper
扫雷游戏也算是一个简单的小项目,这儿是之前写的代码,来写成博文回顾一下。首先,代码要实现几个功能:
第一下扫雷时,即使踩中了雷也不能直接炸死;
扫雷时,坐标周围没有雷的地方可以实现展开;
统计展开的地方边缘处可能存在的雷的个数;
每次进入游戏,雷分布的地方都是随机的。
1.效果图
1)、程序总的构架:
2)、设计两个棋盘,一个是置放雷的棋盘,在测试中可以查看雷分布在哪些地方,不打印,如果玩家最终失败或者取得胜利,可以打印出来给玩家展示雷的分布。一个是展示给玩家的棋盘,打印,且会不断更新。
3)、游戏效果:
2.菜单
// 菜单
menu()
{
printf("*******************************\n");
printf("**** 欢迎来到扫雷游戏! ****\n");
printf("**** 1.进入游戏 ****\n");
printf("**** 0.退出游戏 ****\n");
printf("*******************************\n");
}
3.初始化棋盘
把棋盘初始化为0:
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
memset(board, set, rows*cols*sizeof(board[0][0]));
}
4.打印棋盘
棋盘的打印要用到二维数组的知识,这里会涉及到数组越界的问题,比如我们如果要打印 (10 x 10)的棋盘,我们在设计算法时需要统计周围 8 个方位的雷的个数,那么在统计边界周围雷的个数时就产生了数组越界的问题。为了解决这个问题,在棋盘周围多加一圈,即是如果是10x10,就变成了12x12,多出来的已全部打印出来。
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 0; i < row; i++)
{
printf(" %d ", i + 1);
}
printf("\n");
for (j = 0; j < col+1; j++)
{
printf("---|");
}
printf("\n");
for (i = 0; i < row; i++)
{
printf(" %d |", i + 1);
for (j = 0; j < col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\n");
printf(" |", i + 1);
for (j = 0; j < col; j++)
{
printf("---|");
}
printf("\n");
}
printf("\n");
}
5.在棋盘上布雷
利用函数 strand() 函数和 rand() 函数在棋盘上随机地方布置雷,有雷的地方标记为 1 ,没有雷的地方标记为 0。
//布置雷
void ScMinc(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY_COUNT;
while (count)
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
6.一次展开周围无雷的地方
扫雷时,坐标周围没有雷的地方展开,并统计展开的地方边缘处可能存在的雷的个数。
先设计一个函数 GetMineCount()用来统计雷周围雷的的数,如果为 0,则排除这个区域即置为 ‘ ’ ,并递归周围的 8 个位置,如果还出现为 0 的情况则继续递归,递归完成后打印展开的地方边缘处可能存在的雷的个数。
//统计周围雷的个数
static int GetMineCount(char mine[ROWS][COLS],int x,int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0';
}
//用递归排除周围没有雷的区域
static void NoMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int ret = GetMineCount(mine, x, y);
if (ret == 0)
{
show[x][y] = ' ';
if ((x-1)>0 && (y-1)>0 && (show[x-1][y-1] == '*'))
NoMine(mine, show, x - 1, y - 1);
if ((x - 1)>0 && (y)>0 && (show[x - 1][y] == '*'))
NoMine(mine, show, x - 1, y);
if ((x - 1)>0 && (y + 1)>0 && (show[x - 1][y + 1] == '*'))
NoMine(mine, show, x - 1, y + 1);
if ((x)>0 && (y - 1)>0 && (show[x][y - 1] == '*'))
NoMine(mine, show, x, y - 1);
if ((x)>0 && (y + 1)>0 && (show[x][y + 1] == '*'))
NoMine(mine, show, x, y + 1);
if ((x + 1)>0 && (y - 1)>0 && (show[x + 1][y - 1] == '*'))
NoMine(mine, show, x + 1, y - 1);
if ((x + 1)>0 && (y)>0 && (show[x + 1][y] == '*'))
NoMine(mine, show, x + 1, y);
if ((x + 1)>0 && (y + 1)>0 && (show[x + 1][y + 1] == '*'))
NoMine(mine, show, x + 1, y + 1);
}
else
show[x][y] = ret + '0';
}
7.排雷
在排雷过程中,用一个循环,如果踩中的不是雷,用 win 来统计非雷个数 ,如果踩中雷,立即炸死,结束循环。在循环结束后,如果非雷个数 win 正好等于使用的棋盘区域个数减去雷的个数的值,则成功排雷。
//排雷
void FindMind(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0; //统计不是雷的个数
int ret = 0; //统计周围雷的个数
while (win < ROW*COL - EASY_COUNT)
{
int select = 0;
system("CLS"); //清屏,优化界面
DisplayBoard(show, ROW, COL);
printf("----- 1.扫雷 --- 2.标记雷 -----\n");
printf("请选择:>");
scanf("%d", &select);
if (select == 1)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x-1][y-1] == '0' && show[x-1][y-1] == '*')
{
NoMine(mine, show, x-1, y-1);
DisplayBoard(show, ROW, COL);
win = win + 8;
}
if (mine[x-1][y-1] == '1' && show[x-1][y-1] == '*')
{
show[x-1][y-1] = 'S';
DisplayBoard(show, ROW, COL);
printf("很遗憾,你被炸死了\n\n");
DisplayBoard(mine, row, col);
break;
}
}
else
{
printf("坐标非法\n");
}
}
if (select == 2)
{
printf("请输入要标记雷的坐标:>");
scanf("%d %d", &x, &y);
if (show[x-1][y-1] == '*')
{
show[x-1][y-1] = '@'; //用于玩家标记已经确定的雷
DisplayBoard(show, ROW, COL);
}
else
{
printf("坐标非法\n");
}
}
}
//只剩下有雷的区域(EASY_COUNT:雷的总个数)
if (win = ROW*COL - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(mine, row, col);
}
}
8.游戏执行
void game()
{
char mine[ROWS][COLS] = { 0 }; //置放雷的棋盘
char show[ROWS][COLS] = { 0 }; //展示给玩家的棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS, '*');
ScMinc(mine, ROW, COL); //置雷
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
FindMind(mine, show, ROW, COL);//排雷
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
9.头文件
#ifndef __GAME_H__
#define __GAME_H__
# define _CRT_SECURE_NO_WARNINGS
#include #include #include #include #define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void ScMinc(char board[ROWS][COLS], int row, int col);
void FindMind(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
char FistStep(char mine[ROWS][COLS], int row, int col, int x, int y);
#endif __GAME_H__
10.附:game.c 的源码
#include "game.h"
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
memset(board, set, rows*cols*sizeof(board[0][0]));
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 0; i < row; i++)
{
printf(" %d ", i + 1);
}
printf("\n");
for (j = 0; j < col+1; j++)
{
printf("---|");
}
printf("\n");
for (i = 0; i < row; i++)
{
printf(" %d |", i + 1);
for (j = 0; j < col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\n");
printf(" |", i + 1);
for (j = 0; j < col; j++)
{
printf("---|");
}
printf("\n");
}
printf("\n");
}
//布置雷
void ScMinc(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY_COUNT;
while (count)
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
//统计周围雷的个数
static int GetMineCount(char mine[ROWS][COLS],int x,int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0';
}
//用递归排除周围没有雷的区域
static void NoMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int ret = GetMineCount(mine, x, y);
if (ret == 0)
{
show[x][y] = ' ';
if ((x-1)>0 && (y-1)>0 && (show[x-1][y-1] == '*'))
NoMine(mine, show, x - 1, y - 1);
if ((x - 1)>0 && (y)>0 && (show[x - 1][y] == '*'))
NoMine(mine, show, x - 1, y);
if ((x - 1)>0 && (y + 1)>0 && (show[x - 1][y + 1] == '*'))
NoMine(mine, show, x - 1, y + 1);
if ((x)>0 && (y - 1)>0 && (show[x][y - 1] == '*'))
NoMine(mine, show, x, y - 1);
if ((x)>0 && (y + 1)>0 && (show[x][y + 1] == '*'))
NoMine(mine, show, x, y + 1);
if ((x + 1)>0 && (y - 1)>0 && (show[x + 1][y - 1] == '*'))
NoMine(mine, show, x + 1, y - 1);
if ((x + 1)>0 && (y)>0 && (show[x + 1][y] == '*'))
NoMine(mine, show, x + 1, y);
if ((x + 1)>0 && (y + 1)>0 && (show[x + 1][y + 1] == '*'))
NoMine(mine, show, x + 1, y + 1);
}
else
show[x][y] = ret + '0';
}
//排雷
void FindMind(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0; //统计不是雷的坐标数
int ret = 0; //统计周围雷的个数
while (win < ROW*COL - EASY_COUNT)
{
int select = 0;
//system("CLS"); //清屏,优化界面
DisplayBoard(show, ROW, COL);
printf("----- 1.扫雷 --- 2.标记雷 -----\n");
printf("请选择:>");
scanf("%d", &select);
if (select == 1)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x-1][y-1] == '0' && show[x-1][y-1] == '*')
{
NoMine(mine, show, x-1, y-1);
DisplayBoard(show, ROW, COL);
win = win + 8;
}
if (mine[x-1][y-1] == '1' && show[x-1][y-1] == '*')
{
show[x-1][y-1] = 'S';
DisplayBoard(show, ROW, COL);
printf("很遗憾,你被炸死了\n\n");
DisplayBoard(mine, row, col);
break;
}
}
else
{
printf("坐标非法\n");
}
}
if (select == 2)
{
printf("请输入要标记雷的坐标:>");
scanf("%d %d", &x, &y);
if (show[x-1][y-1] == '*')
{
show[x-1][y-1] = '@'; //用于玩家标记已经确定的雷
DisplayBoard(show, ROW, COL);
}
else
{
printf("坐标非法\n");
}
}
}
if (win > ROW*COL - EASY_COUNT)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(mine, row, col);
}
}
相关文章:

任意角度旋转图片
/// <summary> /// 任意角度旋转 /// </summary> /// <param name"bmp">原始图Bitmap</param> /// <param name"angle">旋转角度</param> /// <param name"bkColor"…

如何切分用户故事
在把用户故事切分成小块,从而更好地利用敏捷技术时,很多新组建的敏捷团队都会遇到困难。 敏捷社区的成员在多篇文章中为如何有效地切分用户故事提供了指导。 当把庞大的用户故事切分成小块时,是否有一些一般的准则供我们遵循呢? Rachel D…
【机器学习】基于人工鱼群算法的非线性函数寻优
本微信图文介绍了人工鱼群算法的基本原理并对一元非线性函数进行极值寻优。

java9可执行jar_单个java文件打成可执行jar包
1 概述使用JDK自带的jar与java将单个java文件打成可执行jar包并运行。 当然也可以使用IDE完成,使用Maven只需要一个简单的package,但是单个文件嘛,没必要这么“凶狠”。2 新建测试文件著名的Hello World:public class Main{public…

简评游戏人工智能相关的中文书(下)
赖勇浩(http://laiyonghao.com) 游戏开发中的人工智能 2006 年 9 月第一版 AI for Game Develpoers 应该算得上一本质量在中等偏上的书,可惜的是即使中文版是由 O’Reilly Taiwan 公司编译,中文版的质量依然差强人意。小的翻译错误…

化敌为友 运营商组团拥抱OTT为哪般
2月15日,全球9大电信运营商宣布,成立“合作运营联盟”(Partnering Operator Alliance),协力挖掘互联网企业为电信业带来的增长潜力。从几年前的抵御OTT进攻到如今的“合作运营”,这个180度的态度转变后面有…
【机器学习】基于自适应变异粒子群算法的非线性函数寻优
本微信图文详细介绍了自适应变异粒子群算法的基本原理以及在非线性函数寻优中的应用。 —————————–华丽分割线—————————— 我们免费提供本文介绍方法的源码,你可以私信我们领取,如果你在领取源码后觉得有帮助,希望能够转…

php fastcgi配置_IIS7.5配置php(FastCGI)- 自动配置
操作系统是 Windows 2008 R2(Windows7),IIS版本是7.5,php版本是 php-5.3.2-Win32-VC9-x86(安装包),数据库是 mysql-5.5.12-win32。具体配置步骤如下:1、安装IIS7.51)Windows 2008(R2)安装步骤:桌面左下角“服务器管理器…

silverlight之How To:设置ComboBox控件的数据源当ComboBox用来作为DataGrid的某列的编辑控件时...
DataGrid是个可编辑的列表控件,而且可以用已有的输入控件来作为某一列的编辑控件,比如用ComboBox控件来作为某列的编辑控件供用户选择数据,这个时候就要先设置好ComboBox控件的下拉列表项了,在silverlight里怎么做呢? …
【Matlab与线性代数】Matlab中对数组元素引用方法总结
本微信图文主要介绍了Matlab中三种对数组元素的引用方法–下标法、索引法和布尔法。

预计2020年传感器需求超一万亿个
据勒克斯研究报告,移动设备的激增,可穿戴设备的日益流行以及连接式物联网的出现促使对传感器的预期需求向一万亿推进。然而,为了充分发挥这些或其他产品的潜能,仍需对传感器进行创新,以满足功率消耗、敏感度、外形因素…

php文本分割成csv,怎么在php中将文本文件转换为csv文件并输出
怎么在php中将文本文件转换为csv文件并输出发布时间:2021-02-19 17:30:27来源:亿速云阅读:88作者:Leah本篇文章给大家分享的是有关怎么在php中将文本文件转换为csv文件并输出,小编觉得挺实用的,因此分享给大…

一些技术图书编写、推荐、出版人员需要自重
最近在互联网上出现了一个让我比较气愤的技术图书相关的事件,事情由《JavaScript征途》一书在51JS上的贴子引起,有人提出这本书的样张里出现了太多错误,但是慢慢的由于作者(即css8)的“死撑”,“事态慢慢升…
【机器学习】基于人工鱼群算法的多元非线性函数寻优
基于人工鱼群算法的多元非线性函数寻优

媲美光纤!WiFi传输速度已可达100Gbps
当前WiFi的最高传输速率是多少?是11ac技术标准的三频5300Mbps?还是11ad的7Gbps?亦或是11ax的10Gbps?答案是100Gbps!没错,这一足以媲美光纤的传输速度,近日在日本研究人员的努力下成为现实&#…

php sharepoint,如何使用php连接sharepoint
试试这个API在SharePoint中下载WSDL.通常位于以下位置:< sharepoint.url> /subsite/_vti_bin/Lists.asmx?WSDL下载API确保同时保存SoapClientAuth.php和SharePointAPI.php在PHP中// 0: include api in your php script.require_once(SharePointAPI.php);// 1…

使用微波炉的十大忌讳
一、忌超时加热:食品放入微波炉解冻或加热,若忘记取出,如果时间超过2小时,则应丢掉不要,以免引起食物中毒。 二、忌将普通塑料容器放入微波炉加热:一是热的食物会使容器变形,二是普通塑料会放出…

匿名黑客Anonymous实施的8次最强攻击
有 研究证明,Anonymous黑客团体的规模比人们的预期要大的多,并且正在成为全世界范围内最流行一群人。关于他们存在这一事实的新闻首先在社交媒体上 公布于众,上面显示了成员之一盖伊福克斯(Guy Fawkes)炫耀他们的面具。…
【怎样写代码】参数化类型 -- 泛型(一):泛型概述
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn togethe.

php redis set集合操作,php对redis的set(集合)操作
<?phprequire (redistest.php);/*** Class setcache*集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是0(1)。*/classsetcacheext…

ASP.NET MVC 重点教程一周年版 第九回 HtmlHelper 【转】
许多时候我们会遇到如下场景 在写一个编辑数据的页面时,我们通常会写如下代码 1: <input type"text" value<%ViewData["title"] %> name"title" />由前篇我们所讲的Helper演化,我们思考,对于这种代…

最佳DevOps工具获奖者:CloudBees Jenkins平台
最新一期《IT新架构》宣布了第三届影响力奖的最终结果。这些获奖的产品和技术由我们读者、行业专家和编辑人员参与投票评选,并且预计将对2016年的IT运营产生显著影响。首先向所有的获胜者表示祝贺。 最佳DevOps工具 获奖者:CloudBees Jenkins平台 开源Je…
【怎样写代码】参数化类型 -- 泛型(二):泛型的优点
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

php 对象json中文乱码,解决php json中文乱码问题
php json中文乱码的解决办法:首先将类中的中文字段进行url编码;然后再将对象进行json编码;最后进行url解码即可解决乱码问题。PHP中json中文乱码问题解决问题:众所周知使用json_encode可以方便快捷地将对象进行json编码࿰…

前两天去A公司面试,面试管问的题目一下子闷了。很郁闷。重新答题。在这里分享一下...
前两天去A公司面试,面试管问的题目一下子闷了。很郁闷。重新答题。在这里分享一下。 1) 问:请问你最近做过什么项目,介绍一下大致的情况? 答:做了http://www.chinatravel.net,由2个人一起开发,其…

数据挖掘公司D square nv 完成500万欧元B轮融资
D square nv日前完成 500 万欧元 B 轮融资,融资方为 Gemma Frisius Fonds, Jrgen Ingels, Limburgse Reconversie Maatschappij, Fortino Capital。 D square nv 成立于 2007年12月,总部位于比利时哈瑟尔特。当时由创始团队自掏腰包 13.5 万欧元作为种子…
【怎样写代码】参数化类型 -- 泛型(三):泛型之类型参数
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

java 获取init参数,Java如何读取servlet init参数?
在web.xml文件中配置servlet时,我们可以在servlet配置部分中定义一些初始化参数。此init参数可用于定义应用程序配置文件的存储位置。下面的这个简单的servlet展示了如何获取这些init参数值。package org.nhooo.example.servlet;import javax.servlet.ServletExcept…

C#实现一个用于开机启动其他程序的Windows服务
今天决定写写博客,不为别的,只当自己的积累,如果与此同时能不误导他人甚至给了朋友们一些启发,那真是更好了! 程序的目的和用途: 很多开机启动程序仅仅加在启动项里面,只有登陆后才真正启动。wi…

Mythic推出“万能”芯片,任何设备都能一秒变身智能产品
我们身边已经出现了一些能够实现语音控制的设备。不过,无论是智能手机还是智能扬声器,都必须先连接到云端,才能实现语音控制。现在,一家叫做Mythic的初创公司推出的新型的芯片和软件将改变这一情况。它无需通过云端就能在本地设备…