程序大致四部分:
1、设置雷区 函数有 lei_set_sub(int x,int y) lei_set()
2、响应键盘 函数有key() move_()
3、显示 函数有gotoxy(int x,int y) HideCursor() cprintf()show()set_ground()show_lei_sub() show_lei() show_left()
4、检测是否游戏结束 函数有is_gameover()
还有一些比较杂的函数,像是open函数、up_fun函数等具体功能见注释
不说太多,代码奉上
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <cstdio>
#include <ctime>
#include <cstdio>
using namespace std;
const int x_max=5,y_max=5,x_base=3,y_base=4,num_lei=4;
int x_pos,y_pos;
int lei[y_max][x_max];
int lei_click[y_max][x_max];
int x_cursor,y_cursor;
char c;
class Basic
{
public:
void gotoxy(int x,int y) //将光标移动到指定位置
{
COORD c;
c.X=x;c.Y=y;
SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE),c);
}
void HideCursor() //隐藏光标
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(hOut, &cci);
}
void cprintf(string str, WORD color, ...) //输出带有颜色的字符
{
WORD colorOld;
HANDLE handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(handle, &csbi);
colorOld = csbi.wAttributes;
SetConsoleTextAttribute(handle, color);
cout << str;
SetConsoleTextAttribute(handle, colorOld);
}
void delay_s(int t) //秒级延时函数
{
clock_t t1=time(0);
while(time(0)-t1<t);
}
void show(int x,int y,int show_type,int num,bool is_cursor) //将上面几个输出函数综合起来
{
gotoxy(x,y);
string s;
int color=2;
s='0'+num;
if (show_type==0&&is_cursor==false)
{
cout<<"@";
}
if (show_type==0&&is_cursor==true)
{
cprintf("@",color);
}
if (show_type==1&&is_cursor==false)
{
cout<<num;
}
if (show_type==1&&is_cursor==true)
{
cprintf(s,color);
}
if (show_type==2&&is_cursor==false)
{
cout<<"#";
}
if (show_type==2&&is_cursor==true)
{
cprintf("#",color);
}
}
void setground() //设置背景
{
for(int i=0;i<y_max+2;++i)
{
for (int j=0;j<x_max+2;++j)
{
if (i==0||i==y_max+1)
show(j+x_base,i+y_base,3,0,false);
else if (j==0||j==x_max+1)
show(j+x_base,i+y_base,3,0,false);
}
}
}
int lei_set_sub(int x,int y) //下面的函数要用到这个函数,返回lei[y][x]应该填的数字
{
int result=0;
if (lei[y][x]==9)
return 9;
for (int i=y-1;i<=y+1;++i)
{
for (int j=x-1;j<=x+1;++j)
{
if(j>=0&&j<x_max&&i>=0&&i<y_max)
{
if (lei[i][j]==9)
result++;
}
}
}
return result;
}
void lei_set() //向lei这个数组中赋值把雷填满,然后为雷周边的元素也赋上值
{
srand(time(0));
int pos_x,pos_y;
memset(lei,0,sizeof(lei));
memset(lei_click,0,sizeof(lei_click));
for(int i=0;i<num_lei;++i)
{
pos_x=rand()%x_max;
pos_y=rand()%y_max;
if (lei[pos_y][pos_x]!=9)
lei[pos_y][pos_x]=9;
else
--i;
}
for(int i=0;i<y_max;++i)
{
for (int j=0;j<x_max;++j)
{
lei[i][j]=lei_set_sub(j,i);
}
}
x_cursor=rand()%x_max;
y_cursor=rand()%y_max;
}
void show_lei_sub(int x,int y) //(x,y) 这个位置这个应该显示什么
{
if (x==x_cursor&&y==y_cursor)
{
show(x_base+1+x,y_base+1+y,lei_click[y][x],lei[y][x],true);
}
else
{
show(x_base+1+x,y_base+1+y,lei_click[y][x],lei[y][x],false);
}
}
void show_lei() //整个扫雷区域应该怎么显示
{
for(int i=0;i<y_max;++i)
{
for (int j=0;j<x_max;++j)
{
show_lei_sub(j,i);
}
}
}
void open() //一旦点开一个并且这个数是0,会将周围都是0的元素也显示出来
{
for (int i=0;i<100;++i)
{
for (int y=0;y<y_max;++y)
{
for (int x=0;x<x_max;++x)
{
if(lei[y][x]==0&&lei_click[y][x]==1)
{
if (y-1>=0)
lei_click[y-1][x]=1;
if (y+1<y_max)
lei_click[y+1][x]=1;
if (x-1>=0)
lei_click[y][x-1]=1;
if (x+1<x_max)
lei_click[y][x+1]=1;
}
}
}
}
}
void key(clock_t& t,int tt) //检测键盘输入
{
if(clock()-t>tt)
{
t=clock();
if(GetAsyncKeyState(VK_ESCAPE)) exit(0);
if(GetAsyncKeyState(VK_LEFT))c='a';
if(GetAsyncKeyState(VK_RIGHT))c='d';
if(GetAsyncKeyState(VK_UP))c='w';
if(GetAsyncKeyState(VK_DOWN))c='s';
if(GetAsyncKeyState(VK_RETURN)&0x8000)c='o';
if(GetAsyncKeyState(VK_SHIFT))c='p';
}
}
void up_fun() //一旦确定是雷,就自动插上旗
{
int num_ge,count_kong,count_open;
int x,y;
for (int i=0;i<y_max;++i)
{
for (int j=0;j<x_max;++j)
{
num_ge=0;
count_kong=0;
count_open=0;
for (y=i-1;y<=i+1;++y)
{
for(x=j-1;x<=j+1;++x)
{
if (x>=0&&x<x_max&&y>=0&&y<y_max)
{
num_ge++;
if(lei_click[y][x]==1&&lei[y][x]!=9)
count_open++;
}
}
}
if (lei[i][j]+count_open==num_ge&&lei_click[i][j]==1&&lei[i][j]!=9)
for (y=i-1;y<=i+1;++y)
{
for(x=j-1;x<=j+1;++x)
{
if (x>=0&&x<x_max&&y>=0&&y<y_max&&lei_click[y][x]==0)
{
lei_click[y][x]=2;
}
}
}
}
}
}
void move_() //相应键盘
{
switch(c)
{
case 'd':
x_cursor+=1;
if (x_cursor>=x_max)
x_cursor=x_max-1;
break;
case 'a':
x_cursor-=1;
if(x_cursor<0)
x_cursor=0;
break;
case 'w':
y_cursor-=1;
if (y_cursor<0)
y_cursor=0;
break;
case 's':
y_cursor+=1;
if (y_cursor>=y_max)
y_cursor=y_max-1;
break;
case 'o':
if (lei_click[y_cursor][x_cursor]==0)
lei_click[y_cursor][x_cursor]=1;
open(); //open函数在这里调用
up_fun(); //up_fun 函数在这里调用
break;
case 'p':
if (lei_click[y_cursor][x_cursor]==0)
lei_click[y_cursor][x_cursor]=2;
else if (lei_click[y_cursor][x_cursor]==2)
lei_click[y_cursor][x_cursor]=0;
break;
}
c=0;
}
bool gameover() //判断游戏是否结束,游戏结束则返回true
{
int flag=0,count_=0;
for (int i=0;i<y_max;++i)
{
for (int j=0;j<x_max;++j)
{
if (lei[i][j]==9&&lei_click[i][j]==1)
{
gotoxy(x_base+1+j,y_base+1+i);
cout<<"!";
gotoxy(0,4);
cout<<"矮油,踩到雷了!即将退出游戏";
return true;
}
if (lei_click[i][j]==0)
flag=1;
if (lei_click[i][j]==2)
count_++;
}
}
if (flag==0&&count_==num_lei)
{
gotoxy(0,4);
cout<<"恭喜你获得游戏的胜利!即将退出游戏!";
return true;
}
return false;
}
void running() //最体现大局的一个函数,建议大家从这里看起
{
clock_t t1;
t1=clock();
lei_set();
gotoxy(0,0);
cout<<"---------扫雷小游戏----------"<<endl;
cout<<"雷的个数是"<<num_lei<<" "<<"为"<<x_max<<"*"<<y_max<<"的扫雷区域"<<endl;
cout<<"游戏规则: 上下左右控制移动,按Enter键打开该格子,按Shift键插旗";
while(true)
{
HideCursor();
show_lei();
key(t1,80);
move_();
show_left();
if (gameover())
break;
}
show_lei();
gameover();
delay_s(2);
}
void show_left() /显示还剩下的雷的个数
{
int count__=0;
for (int i=0;i<y_max;++i)
for (int j=0;j<x_max;++j)
{
if (lei_click[i][j]==2)
count__++;
}
gotoxy(0,3);
count__=num_lei-count__;
if (count__<0)
count__=0;
cout<<"剩余雷的数量:"<<count__<<" ";
}
};
int main()
{
Basic b;
b.running();
}