扫雷
程序员文章站
2022-04-07 21:54:23
...
C语言马上学完,找了个课设的题目练练手。
一、功能描述:
1、使用方格显示,利于坐标输入。
2、分三个级别的难度。(初级 10个雷,中级 20个雷 ,高级 35)
3、第一次输入如果是雷,就随机移到非雷区,保证第一次不会被炸死。
4、可以显示一周雷的个数。
5、可以标记雷、取消标记。
6、输入坐标如果一周无雷,即展开,遇到有雷就停止展开。
7、保证屏幕上不累计出现多框图,每次显示前做清屏处理。
二、采用多文件方式实现,分为主函数,游戏函数,头文件函数
三、代码展示:
1、game.h
#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include <Windows.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
#define mine_count 10
#define mid_count mine_count+10
#define high_count mine_count+25
int select_level(); //选择等级
void init_str(char arr[ROWS][COLS],int row,int col,int set); //初始化数组
void display_board(char arr[ROWS][COLS],int row,int col); //打印数组
void insert_mine(char arr[ROWS][COLS],int row,int col,int count); //布雷
void clear_mine(char minearr[ROWS][COLS],char showarr[ROWS][COLS],int number); //展开
int get_minecount(char arr[ROWS][COLS],int x,int y); //统计雷
void open_board(char showmine[ROW][COLS],char minearr[ROWS][COLS],int x,int y); //展开
int sign_mine(char arrshow[ROWS][COLS],char arrmine[ROWS][COLS],int num); //标记
int cancel_sign(char arrshow[ROWS][COLS],char arrmine[ROWS][COLS],int num); //取消标记
#endif //__GAME_H__
2、main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void print_menu()
{
printf("****************************welcome you !****************************\n");
printf("******************** 1、play 0、exit ********************\n");
printf("****************************good luck !****************************\n");
}
void game()
{
int number = 0;
char mine[ROWS][COLS]={0}; //放雷的数组
char show[ROWS][COLS]={0}; //显示的数组
number = select_level();
init_str(mine,ROWS,COLS,'0'); //初始化雷组
init_str(show,ROWS,COLS,'*'); //初始化非雷组
display_board(show,ROW,COL); //显示
insert_mine(mine,ROW,COL,number); //布雷
//display_board(mine,ROW,COL); //显示雷数组,用于测试
clear_mine(mine,show,number); //排雷
}
int main ()
{
int input = 0;
srand((unsigned)time(NULL)); //产生种子,布雷时使用
do
{
print_menu();
printf("please select:>");
scanf("%d",&input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("enter error !\n");
}
} while (input);
return 0;
}
3、game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
int select_level() //选择等级
{
int input= 0;
int num = 0;
int flag = 1;
printf("************************* 1、Simple (10 mines) *************************\n");
printf("************************* 2、Middle (15 mines) *************************\n");
printf("************************* 3、trouble(35 mines) *************************\n");
while (flag)
{
printf("please select:>");
scanf("%d",&input);
switch (input)
{
case 1:
{
num=mine_count;
flag = 0;
break;
}
case 2:
{
num=mid_count;
flag = 0;
break;
}
case 3:
{
num=high_count;
flag = 0;
break;
}
default:
printf("enter error !\n");
}
}
return num;
}
void init_str(char arr[ROWS][COLS],int row,int col,int set) //初始化雷的数组和显示的数组
{
int i = 0;
int j = 0;
for (i=0; i<row; i++)
{
for (j=0; j<col; j++)
{
arr[i][j]=set;
}
}
}
void display_board(char arr[ROWS][COLS],int row,int col) //打印显示数组
{
int i = 0;
int j = 0;
printf(" ");
for (i=1; i<=row; i++)
{
printf(" %d ",i);
}
printf("\n");
printf(" ");
for (i=0; i<row; i++)
{
printf("----");
}
printf("\n");
for (i=1; i<=row; i++)
{
printf("%2d|",i);
for (j=1; j<=col; j++)
{
printf(" %c |",arr[i][j]);
}
printf("\n");
printf(" ");
for (j=0; j<row; j++)
{
printf("----");
}
printf("\n");
}
}
void insert_mine(char arr[ROWS][COLS],int row,int col,int count) //布雷
{
int x = 0;
int y = 0;
while (count)
{
x=(rand()%row)+1; //判断坐标是否合法
y=(rand()%col)+1;
if (arr[x][y]=='0')
{
arr[x][y]='1';
count--;
}
}
}
int get_minecount(char arr[ROWS][COLS],int x,int y) //统计雷的个数
{
return (arr[x][y-1]+arr[x][y+1]
+arr[x-1][y-1]+arr[x-1][y]+arr[x-1][y+1]
+arr[x+1][y-1]+arr[x+1][y]+arr[x+1][y+1]-8*'0');
}
void open_board(char showarr[ROW][COLS],char minearr[ROWS][COLS],int x,int y) //展开
{
int count = 0;
int i = 0;
int j = 0;
if (showarr[x][y]=='*') //防止重复展开
{
count = get_minecount(minearr,x,y);
if (count!=0) //雷的个数不为零就停止
{
showarr[x][y]=count+'0';
}
else
{
showarr[x][y]=' ';
for (i=-1;i<=1; i++)
{
for (j=-1; j<=1; j++)
{
if (x + i >= 1 && x + i <=ROW && y + j >= 1 && y + j <=COL) //递归展开时不能越界
{
if (i!=j)
{
open_board(showarr,minearr,x+i,y+j); //递归调用
}
}
}
}
}
}
}
int sign_mine(char arrshow[ROWS][COLS],char arrmine[ROWS][COLS],int num) //标记
{
int x = 0;
int y = 0;
while (1)
{
printf("please enter coordinate:");
scanf("%d%d",&x,&y);
if (x>=1 && x<=ROW && y>=1 && y<=COL && arrshow[x][y]=='*' && arrshow[x][y]!='-') //合法标记
{
arrshow[x][y]='-';
if (arrmine[x][y]=='1')
{
num--;
}
break;
}
else
printf("enter error !\n");
}
return num;
}
int cancel_sign(char arrshow[ROWS][COLS],char arrmine[ROWS][COLS],int num) //取消标记
{
int x = 0;
int y = 0;
while (1)
{
printf("please enter coordinate(example:2 2):>");
scanf("%d%d",&x,&y);
if (x>=1 && x<=ROW && y>=1 && y<=COL && arrshow[x][y]!='*' && arrshow[x][y]=='-') //防止重复标记和错误标记
{
arrshow[x][y]='*';
if (arrmine[x][y]=='1')
{
num++;
}
break;
}
else
printf("enter error !\n");
}
return num;
}
void clear_mine(char minearr[ROWS][COLS],char showarr[ROWS][COLS],int number) //排雷
{
int x = 0;
int y = 0;
int x0 = 0;
int y0 = 0;
int flag = 0;
while (number)
{
printf("please enter coordinate(example 2 2):>");
scanf("%d%d",&x,&y);
//防止重复输入和错误输入,被标记处不能展开
if (x>=1 && x<=ROW && y>=1 && y<=COL && showarr[x][y]=='*' && showarr[x][y]!='-')
{
flag++;
if (flag==1 && minearr[x][y]=='1') //第一次不被炸死,增加可玩性
{
minearr[x][y]='0';
while (1)
{
x0=(rand()%ROW)+1; //判断坐标是否合法
y0=(rand()%COL)+1;
if (minearr[x0][y0]=='0')
{
minearr[x0][y0]='1'; //移走第一个雷
break;
}
}
}
if (minearr[x][y]=='1')
{
printf("\n**************************** game over ! ****************************\n");
display_board(minearr,ROW,COL); //显示雷
break;
}
else //输入坐标不是雷
{
int tmp = 1;
system("cls"); //清屏
open_board(showarr,minearr,x,y); //展开不是雷的区域
display_board(showarr,ROW,COL);
while (tmp)
{
printf("\n**************************** 是 否 标 记 ****************************\n");
printf("*********************** 1、yes 2、cancel 0、no ***********************\n");
printf("please select:>");
scanf("%d",&tmp);
//根据需求标记、取消标记和不标记
switch (tmp)
{
case 1:
{
number=sign_mine(showarr,minearr,number); //标记雷
if (number==0)
{
tmp=0;
display_board(showarr,ROW,COL);
printf("**************************** you win ! ****************************\n\n");
break;
}
system("cls"); //清屏
display_board(showarr,ROW,COL);
break;
}
case 2:
{
number = cancel_sign(showarr,minearr,number);
if (number==0)
{
tmp=0;
display_board(showarr,ROW,COL);
printf("**************************** you win ! ****************************\n\n");
break;
}
system("cls"); //清屏
display_board(showarr,ROW,COL);
break;
}
case 0:
break;
default:
printf("enter error !\n");
break;
}
}
}
}
else
printf("enter error !\n");
}
}
四、效果展示:
1、菜单展示
2、排雷开始
3、展开图展示
4、游戏胜利
5、游戏失败
五、本项目难点展示(难点是展开部分)
void open_board(char showarr[ROW][COLS],char minearr[ROWS][COLS],int x,int y) //展开
{
int count = 0;
int i = 0;
int j = 0;
if (showarr[x][y]=='*') //防止重复展开
{
count = get_minecount(minearr,x,y);
if (count!=0) //雷的个数不为零就停止
{
showarr[x][y]=count+'0';
}
else
{
showarr[x][y]=' ';
for (i=-1;i<=1; i++)
{
for (j=-1; j<=1; j++)
{
if (x + i >= 1 && x + i <=ROW && y + j >= 1 && y + j <=COL) //递归展开时不能越界
{
if (i!=j) //只要衡纵坐标不等就递归展开
{
open_board(showarr,minearr,x+i,y+j); //递归调用
}
}
}
}
}
}
}
六、学习了c语言感觉很爽,女朋友天天写我玩的游戏,还能帮我找bug,更重要的是增进感情。
上一篇: JS将滑动门改为选项卡的实现方法
下一篇: 程序员