本次用c语言完成扫雷游戏的最初版
在开始要先有计划,对自己写的代码要有一个基本逻辑,对要写的游戏也需要有一个具体的逻辑,要是埋头就写结束后就可能有很多问题。
所有的代码我放在最后一段了。下面是我在学习后的理解想看的可以看下。
本次将扫雷分两部分来写。分别为:1、游戏框架?2、游戏主体函数和实现
1、游戏框架
首先一个游戏进入要有菜单,进入游戏和退出游戏可供玩家选择
我们也可以用一do while循环来供玩家选择多轮游戏
进入游戏就是游戏主体函数
退出就是退出游戏
最后就是对玩家的选项进行判断
#include"game.h"
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//用于随机数
do
{
menu();//菜单
printf("\n\n请选择:>\n");
scanf("%d", &input);
switch(input)
{
case 1:
game();//游戏主体函数
break;
case 0:
printf("游戏已退出!\n");
break;
default:
printf("输入有误!请重新输入!\n");
break;
};
}while(input);
return 0;
}
void menu()//菜单函数实现
{
printf("*************************************\n");
printf("**** ****\n");
printf("**** 1、play 0、exit ****\n");
printf("**** ****\n");
printf("*************************************\n");
}
2、游戏主体
void game()//主体实现
{
//需要两个数组
//一个用来存放地雷
//另一个用来存放提示
char mine[Wids][Lens] = {0};//地雷
char show[Wids][Lens] = {0};//提示
//初始化数组
initboard(mine, Wids, Lens, '0');
initboard(show, Wids, Lens, '*');
//打印棋盘
displayboard(mine, Wid, Len);
displayboard(show, Wid, Len);
//埋雷
setmine(mine, Wid, Len);
//displayboard(mine, Wid, Len);
//查雷
findmine(mine, show, Wid, Len);
}
首先要对扫雷这个游戏进行逻辑分析,我们要将扫雷分解成为两部分来进行
第一个部分:我们要埋雷,将地雷随机埋进棋盘中
第二个部分:我们要查雷,锁定坐标得到提示,提示即周围一格内所有的地雷总数
所以我们需要两个二维数组来存放
一个存放地雷,一个存提示
char mine[9][9] = {0};//地雷
char show[9][9] = {0};//提示
接着我们需要对齐进行初始化
在初始化的时候我们知道数组的规格
首先我们要知道如果我们想创建一个9*9的棋盘,那么在扫雷中我们需要一个11*11的数组才可以存下。我们知道,提示是得到周围一格内所有的地雷数,如果我们想要的到9*9最边边那一列的提示的话那么数组可能会溢出。例如,我们要得到最右下角的那一块的提示,那么它需要将周围一格内所有的地雷进行判断和计数,但我们给的只有一格9*9的棋盘,所以可能溢出。为此我们需要将棋盘行和列各加两个,保证数组不会溢出。两个数组都加是因为我们要保证其坐标一致,方便后续操作。
这时我们就可以在头文件中进行宏定义。
#define Len 9
#define Wid 9
#define Lens 11
#define Wids 11
在我们的到这些参数后就可以进行数组初始化和棋盘打印了
我们在初始化的时候需要考虑我们要送进去的内容,我们上面使用的是char型数组,所以我们这里也都使用字符来送入。
地雷 = ‘1’? ? ? ? 无地雷 = ‘0’? ? ? 未提示 = ?? ? ? 提示 = ‘0’ ~ ‘9’
//需要两个数组
//一个用来存放地雷
//另一个用来存放提示
char mine[Wids][Lens] = {0};//地雷
char show[Wids][Lens] = {0};//提示
//初始化数组
initboard(mine, Wids, Lens, '0');
initboard(show, Wids, Lens, '*');
下面是对其函数的实现
void initboard(char board[Wids][Lens], int wids, int lens, char set)//初始化数组实现
{
int i, j;
for(i = 0; i < wids; i++)
{
for(j = 0; j < lens; j++)
{
board[i][j] = set;
}
}
}
接着我们将打印棋盘的函数也写出
//打印棋盘
displayboard(mine, Wid, Len);
displayboard(show, Wid, Len);
? ? ? 对其实现
void displayboard(char board[Wids][Lens], int wid, int len)//打印棋盘实现
{
int i, j;
printf("------棋盘-------\n");
for(i = 0; i <= len; i++)
{
printf("%d ", i);
}
printf("\n");
for(i = 1; i <= wid; i++)
{
printf("%d ", i);
for(j = 1; j <= len; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------棋盘-------\n");
}
最后就是我们重要的两部分 埋地雷和查地雷了
首先埋地雷
我们的目标是将10个地雷随机的埋入9*9的格子中
//埋雷
setmine(mine, Wid, Len);
下面是实现
void setmine(char board[Wids][Lens], int wid, int len)//埋雷实现
{
//需要随机值
int count = setmine_count;
while(count)
{
int x = rand() % wid + 1;
int y = rand() % len + 1;
if(board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
接着是查地雷
//查雷
findmine(mine, show, Wid, Len);
在实现函数时,我们要知道首先需要:
玩家输入坐标,接着对坐标进行判断,是否在1-9这个范围内。
若符合,则对坐标进行是否有地雷的判断
有地雷,游戏结束
无地雷,进行周围一格内所有的地雷进行检测并计数,并对棋盘进行提示
下面是对函数的实现
static findmine_count(char board[Wids][Lens], int x, int y)//查雷实现
{
return board[x - 1][y - 1] +
board[x - 1][y] +
board[x - 1][y + 1] +
board[x][y - 1] +
board[x][y + 1] +
board[x + 1][y - 1] +
board[x + 1][y] +
board[x + 1][y - 1] - 8 * '0';
}
void findmine(char mine[Wids][Lens], char show[Wids][Lens], int wid, int len)
{
//需要玩家输入坐标,对坐标进行判断
//对有雷和无雷进行实现
int x = 0;
int y = 0;
int count = 0;
while(count != wid * len - setmine_count)
{
printf("\n\n请输入要查的坐标:>\n");
scanf("%d %d", &x, &y);
if(x >= 1 && x <= wid && y >= 1 && y <= len)
{
//有雷 被炸死
//没有雷 计算周围一格内的雷数并显示
if(mine[x][y] == '1')
{
printf("\n\n\n*****************\n");
printf("*** 菜 菜***\n");
printf("*** ***\n");
printf("*** 菜 ***\n");
printf("*** ***\n");
printf("***菜 菜***\n");
printf("*****************\n\n\n\n");
break;
}
else
{
int set = findmine_count(mine, x, y);//计算周围一周的雷数
show[x][y] = set + '0';//一个数字 + '0'字符零 = 当前数字的字符形式
displayboard(show, wid, len);
count++;
}
}
else
{
printf("\n\n输入的坐标有误!请重新输入!\n\n");
}
}
if(count == wid * len - setmine_count)
{
printf("\n\n打得好啊!\n\n");
displayboard(show, wid, len);
printf("\n\n\n");
}
}
使用static可以对当前函数进行修饰,使其只能在本文件内使用,不会导致其他文件内出现重名等现象。
至此,完成扫雷游戏,其中还可以有很多优化,碍于本人技术有限,琢磨半天递归也没给点一下如果周围没有0则全部点亮提示给整出来。还有上面的那个查雷其实可以用循环实现看起来厉害一点,这里可以直接把board[x][y]排除的,我这里直接在后面多 - '0' 也可以吧。
static findmine_count(char board[Wids][Lens], int x, int y)//查雷实现
{
int i,j;
int sum = 0;
for(i = -1; i < 2; i++)
{
for(j = -1; j < 2; j++)
{
sum = sum + board[x + i][y + j];
}
}
return sum - 9 * '0';
}
下面是所有的代码
主函数:main.c
/** 扫雷 **/
#include"game.h"
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();//菜单
printf("\n\n请选择:>\n");
scanf("%d", &input);
switch(input)
{
case 1:
game();//游戏主体函数
break;
case 0:
printf("游戏已退出!\n");
break;
default:
printf("输入有误!请重新输入!\n");
break;
};
}while(input);
return 0;
}
game.h
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Len 9
#define Wid 9
#define Lens 11
#define Wids 11
#define setmine_count 10 //地雷数
void menu();//菜单函数声明
void game();//主体函数声明
void initboard(char board[Wids][Lens], int wids, int lens, char set);//初始化数组声明
void displayboard(char board[Wids][Lens], int wid, int len);//打印棋盘声明
void setmine(char board[Wids][Lens], int wid, int len);//埋雷声明
void findmine(char mine[Wids][Lens], char show[Wids][Lens], int wid, int len);//查雷声明
#endif // GAME_H_INCLUDED
game.c
#include"game.h"
void menu()//菜单函数实现
{
printf("*************************************\n");
printf("**** ****\n");
printf("**** 1、play 0、exit ****\n");
printf("**** ****\n");
printf("*************************************\n");
}
void game()//主体实现
{
//需要两个数组
//一个用来存放地雷
//另一个用来存放提示
char mine[Wids][Lens] = {0};//地雷
char show[Wids][Lens] = {0};//提示
//初始化数组
initboard(mine, Wids, Lens, '0');
initboard(show, Wids, Lens, '*');
//打印棋盘
displayboard(mine, Wid, Len);
displayboard(show, Wid, Len);
//埋雷
setmine(mine, Wid, Len);
//displayboard(mine, Wid, Len);
//查雷
findmine(mine, show, Wid, Len);
}
void initboard(char board[Wids][Lens], int wids, int lens, char set)//初始化数组实现
{
int i, j;
for(i = 0; i < wids; i++)
{
for(j = 0; j < lens; j++)
{
board[i][j] = set;
}
}
}
void displayboard(char board[Wids][Lens], int wid, int len)//打印棋盘实现
{
int i, j;
printf("------棋盘-------\n");
for(i = 0; i <= len; i++)
{
printf("%d ", i);
}
printf("\n");
for(i = 1; i <= wid; i++)
{
printf("%d ", i);
for(j = 1; j <= len; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------棋盘-------\n");
}
void setmine(char board[Wids][Lens], int wid, int len)//埋雷实现
{
//需要随机值
int count = setmine_count;
while(count)
{
int x = rand() % wid + 1;
int y = rand() % len + 1;
if(board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
static findmine_count(char board[Wids][Lens], int x, int y)//查雷实现
{
int i,j;
int sum = 0;
for(i = -1; i < 2; i++)
{
for(j = -1; j < 2; j++)
{
sum = sum + board[x + i][y + j];
}
}
return sum - 9 * '0';
// return board[x - 1][y - 1] +
// board[x - 1][y] +
// board[x - 1][y + 1] +
// board[x][y - 1] +
// board[x][y + 1] +
// board[x + 1][y - 1] +
// board[x + 1][y] +
// board[x + 1][y - 1] - 8 * '0';
}
void findmine(char mine[Wids][Lens], char show[Wids][Lens], int wid, int len)
{
//需要玩家输入坐标,对坐标进行判断
//对有雷和无雷进行实现
int x = 0;
int y = 0;
int count = 0;
while(count != wid * len - setmine_count)
{
printf("\n\n请输入要查的坐标:>\n");
scanf("%d %d", &x, &y);
if(x >= 1 && x <= wid && y >= 1 && y <= len)
{
//有雷 被炸死
//没有雷 计算周围一格内的雷数并显示
if(mine[x][y] == '1')
{
printf("\n\n\n*****************\n");
printf("*** 菜 菜***\n");
printf("*** ***\n");
printf("*** 菜 ***\n");
printf("*** ***\n");
printf("***菜 菜***\n");
printf("*****************\n\n\n\n");
break;
}
else
{
int set = findmine_count(mine, x, y);//计算周围一周的雷数
show[x][y] = set + '0';//一个数字 + '0'字符零 = 当前数字的字符形式
displayboard(show, wid, len);
count++;
}
}
else
{
printf("\n\n输入的坐标有误!请重新输入!\n\n");
}
}
if(count == wid * len - setmine_count)
{
printf("\n\n打得好啊!\n\n");
displayboard(show, wid, len);
printf("\n\n\n");
}
}
|