程序设计时做得没有界面的扫雷。
快期末考试了,刚创博客没啥好写的,就放个以前的代码吧。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <algorithm>
#include <conio.h>
#include <windows.h>
using namespace std;
struct GamePlayer //游戏用户
{
char Name[10]; //用户名
char Password[10]; //密码
double Time; //当前游戏所用时间
double AllTime; //累计游戏时间
double BestTime; //最佳成绩,即最短时间
int GameCount; //总游戏局数
int NumOfWin; //历史胜利次数
int NumOfLose; //历史失败次数
double Rate; //总胜率
}Gameplayer, gameplayer[1010]; //Gameplayer存储当前游戏用户,gameplayer存储用户文件中的用户
struct GRAPH //雷区地图
{
int s[110][110]; //矩阵存储,0表示没有雷,1表示有雷
char Show[110][110]; //显示给用户的雷区地图
int Row; //雷区的行数
int Col; //雷区的列数
int Lei; //雷的个数
}Graph; //雷区地图
struct RANK //存储排行榜
{
char Name[10]; //用户名
double Time; //时间
bool operator < (const RANK& r) const //重载小于号,使排序更简单
{
if(Time != r.Time) //先按照时间从小到大排序
return Time < r.Time;
else //时间相同则按照用户名从短到长排序
{
int len1 = strlen(Name);
int len2 = strlen(r.Name);
return len1 < len2;
}
}
}Rank[6]; //用于排名的结构体数组
FILE *Easy, *Medium, *Hard, *Player; //文件指针,运行前需创建4个文件
char level[10]; //存储所选的游戏难度,用char数组防止用户输错
int iswin; //存储本局游戏是否赢了
int isok; //用户信息是否合法,若合法则存储用户的位置
int Num; //存储用户文件中的用户个数
bool ison = false; //存储用户是否已经登录
void Open(); //打开程序要用到的文件
void Delay(); //延时函数
int InitPlayer(int &i); //初始化玩家信息,i表示文件中用户的个数,返回玩家在文件中的位置
void InitGraph(int row, int col, int lei); //初始化雷区,row行col列,lei个雷
bool SelectLevel(); //选择难度等级,可以自定义
int NumOfMine(int x, int y); //返回x,y周围的雷的个数
void Display(); //显示玩家看到的地图
void DisplayPlayer(); //显示用户信息
void DisplayRank(); //显示排行榜
bool Sweep(int x, int y, int k); //扫雷的一次操作,第x行第y列,k表示是否有雷
void Sweep1(int x, int y, int k); //开局第一次点击,肯定没有雷,如果有会把雷随机到其他地方
bool Judge(); //判断是否已经赢得游戏
void PlayGame(); //开始游戏并计时
void SaveRanking(); //将成绩录入排行榜
void Update(); //更新用户信息,保存到文件
bool ChangePassword(); //修改密码
void End(); //结束画面
void Close(); //关闭文件
void Test(); //测试用函数,开始游戏时可注释
int gotoxyWithFullwidth(short x,short y); //以控制台左上角为坐标原点,定位光标位置
void setColor(unsigned short ForeColor=7,unsigned short BackGroundColor=0);
//设置字体颜色
int main() //需要事先创建4个txt文件
{
char Begin[10]; //存储用户的操作,用char数组防止用户输入错误
printf("\t===============挖地雷小游戏===============\n");
printf("\t^_^进入游戏请输入1,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1');
while(Begin[0] == '1')
{
Open(); //打开文件
srand((int)time(NULL)); //随机种子
if(!ison) //如果还没有登录
{
printf("\t^_^登录或注册请输入1, 查看排行榜请输入2,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2');
if(Begin[0] == '2')
{
DisplayRank(); //显示排行榜
printf("\t^_^登录或注册请输入1,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1');
}
if(Begin[0] != '1' && Begin[0] != '2')
{
Close();
break;
}
isok = InitPlayer(Num); //初始化用户信息
}
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t^_^开始游戏请输入1,查看用户信息请输入2,查看排行榜请输入3,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '3');
if(Begin[0] == '0') //退出游戏
{
Close();
break;
}
else if(Begin[0] == '2') //查看用户信息
{
if(isok == -1) //是新用户
{
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t用户名:%s\n", Gameplayer.Name);
printf("\t总游戏时长:0 seconds\n");
printf("\t最好成绩:NULL seconds\n");
printf("\t胜利次数:0\n");
printf("\t失败次数:0\n");
printf("\t总胜率:0\n");
}
else //是老用户
DisplayPlayer(); //显示玩家信息
printf("\t^_^开始游戏请输入1,查看排行榜请输入2,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2');
if(Begin[0] == '0') //退出游戏
{
Close();
break;
}
else if(Begin[0] == '2') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^开始游戏请输入1,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1');
if(Begin[0] != '1')
{
Close();
break;
}
}
}
else if(Begin[0] == '3') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^开始游戏请输入1,查看用户信息请输入2,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2');
if(Begin[0] != '1' && Begin[0] != '2')
{
Close();
break;
}
else if(Begin[0] == '2') //查看用户信息
{
DisplayPlayer(); //显示用户信息
printf("\t^_^开始游戏请输入1,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1');
if(Begin[0] != '1')
{
Close();
break;
}
}
}
while(!SelectLevel()); //选择难度或自定义难度
PlayGame(); //开始游戏
SaveRanking(); //更新排行榜
Update(); //更新用户信息
Delay(); //延时
Delay(); //延时
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t^_^继续游戏请输入1,查看用户信息请输入2,查看排行榜请输入3\n\t切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '3' && Begin[0] != '4');
if(Begin[0] == '2') //查看用户信息
{
DisplayPlayer(); //显示用户信息
printf("\t^_^继续游戏请输入1,修改密码请输入2,查看排行榜请输入3\n\t切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '3' && Begin[0] != '4');
if(Begin[0] == '2') //用户选择修改密码
{
while(!ChangePassword());
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t修改完成~\n"); //修改完成,给予用户提示
Delay(); //延时
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t^_^继续游戏请输入1,查看排行榜请输入2,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4');
if(Begin[0] == '2') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^继续游戏请输入1,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '4');
}
if(Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4')
{
Close();
break;
}
}
else if(Begin[0] == '3') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^继续游戏请输入1,查看用户信息请输入2,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4');
if(Begin[0] == '2') //查看用户信息
{
DisplayPlayer(); //显示用户信息
printf("\t^_^继续游戏请输入1,修改密码请输入2,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4');
if(Begin[0] == '2') //修改密码
{
while(!ChangePassword());
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t修改完成~\n");
Delay(); //延时
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t^_^继续游戏请输入1,查看排行榜请输入2,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin);
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4');
if(Begin[0] == '2') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^继续游戏请输入1,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin);
}while(Begin[0] != '0' && Begin[0] != '1');
}
}
}
if(Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4')
{
Close();
break;
}
}
else if(Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '3' && Begin[0] != '4')
{
Close();
break;
}
}
else if(Begin[0] == '3') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^继续游戏请输入1,查看用户信息请输入2,修改密码请输入3\n\t切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '3' && Begin[0] != '4');
if(Begin[0] == '2') //查看用户信息
{
DisplayPlayer(); //显示用户信息
printf("\t^_^继续游戏请输入1,修改密码请输入2,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin); //询问用户操作
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4');
if(Begin[0] == '2') //修改密码
{
while(!ChangePassword());
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t修改完成~\n");
Delay(); //延时
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t^_^继续游戏请输入1,查看排行榜请输入2,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin);
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '4');
if(Begin[0] == '2') //查看排行榜
{
DisplayRank(); //显示排行榜
printf("\t^_^继续游戏请输入1,切换账号请输入4,退出请输入0\n");
do //防止用户输入错误
{
scanf("%s", Begin);
}while(Begin[0] != '0' && Begin[0] != '1' && Begin[0] != '4');
}
}
}
if(Begin[0] != '1' && Begin[0] != '2' && Begin[0] != '3' && Begin[0] != 4)
{
Close();
break;
}
}
if(Begin[0] == '1') //继续游戏
{
ison = true; //已经登录
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
}
if(Begin[0] == '4') //切换账号
{
ison = false; //还未登录
Begin[0] = '1';
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
}
Close(); //关闭文件
}
End(); //结束画面
return 0;
}
void Open() //打开程序要用到的文件
{
Easy = fopen("Easy.txt", "r+"); //Easy.txt存储简单模式的排行榜
if(!Easy) //若打开失败则输出失败并退出
{
printf("Can not open Easy.txt.\n");
exit(1);
}
Medium = fopen("Medium.txt", "r+"); //Medium.txt存储普通模式的排行榜
if(!Medium) //若打开失败则输出失败并退出
{
printf("Can not open Medium.txt.\n");
exit(1);
}
Hard = fopen("Hard.txt", "r+"); //Hard.txt存储困难模式的排行榜
if(!Hard) //若打开失败则输出失败并退出
{
printf("Can not open Hard.txt.\n");
exit(1);
}
Player = fopen("Player.txt", "r+"); //Player.txt存储用户信息
if(!Player) //若打开失败则输出失败并退出
{
printf("Can not open Player.txt.\n");
exit(1);
}
}
void Delay() //延时函数
{
for(int t = 0; t < 1e9; t++);
}
int InitPlayer(int &i) //初始化玩家信息,i表示文件中用户的个数,返回玩家在文件中的位置
{
char mm; //存储被隐藏的密码
int p = 0; //存储密码位数
bool Find = false; //Find存储是否在文件中找到了用户
int num; //num存储顽疾所在文件中的位置
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t^_^请输入用户名(不多于10个字符),回车结束。(新用户自动注册)\n");
printf("\t用户名:");
scanf("%s", Gameplayer.Name);
printf("\t^_^请输入密码(不多于10个字符),回车结束。\n");
printf("\t密码:");
while(1) //输入密码,显示星号*
{
mm = getch(); //输入m且隐藏
if(mm == '\r') //遇到回车,停止输入
{
printf("\n"); //回车被mm吃了,输出回车
break; //退出循环
}
if(mm == '\b') //遇到退格键
{
p--; //j往前移一位
printf("\b \b"); //输出退格然后用空格覆盖原来的*再输出退格
continue; //跳过这次循环
}
Gameplayer.Password[p++] = mm; //将密码赋值给Password
printf("*"); //输出'*'
}
// printf("%s\n", Gameplayer.Password); //调试用
while(~fscanf(Player, "%d", &i))
{
fscanf(Player, "%s%s%lf%lf%d%d%d%lf", gameplayer[i].Name, gameplayer[i].Password, &gameplayer[i].AllTime, &gameplayer[i].BestTime,
&gameplayer[i].GameCount, &gameplayer[i].NumOfWin, &gameplayer[i].NumOfLose, &gameplayer[i].Rate);
if(strcmp(gameplayer[i].Name, Gameplayer.Name) == 0)
{
Find = true;
num = i;
}
}
if(Find) //判断密码是否正确
{
int j = 1; //记录输错了多少次
while(strcmp(gameplayer[num].Password, Gameplayer.Password) != 0)
{ //如果输入错误,就重新输入
if(j++ % 3 == 0) //输错三次,就会要求过一会儿再输入
{
printf("\t输错太多啦,歇会儿吧。\n");
Delay();
continue;
}
printf("\t密码错误,请重新输入密码:");
p = 0; //初始化p与Password
int len = strlen(Gameplayer.Password);
for(int k = 0; k < len; k++)
Gameplayer.Password[k] = '\0';
while(1) //输入密码,显示星号*
{
mm = getch(); //输入m且隐藏
if(mm == '\r') //遇到回车,停止输入
{
printf("\n"); //回车被mm吃了,输出回车
break; //退出循环
}
if(mm == '\b') //遇到退格键
{
p--; //p往前移一位
printf("\b \b"); //输出退格然后用空格覆盖原来的*再输出退格
continue; //跳过这次循环
} //将密码赋值给Password
Gameplayer.Password[p++] = mm;
printf("*"); //输出'*'
}
// printf("%s\n", Gameplayer.Password); //调试用
}
return num; //有玩家信息,返回玩家所在文件中的位置
}
else
return -1; //返回-1表示无玩家信息,需要录入
}
void InitGraph(int row, int col, int lei) //初始化雷区,row行col列,lei个雷
{
Graph.Row = row; //row行
Graph.Col = col; //col列
Graph.Lei = lei; //lei雷的个数
for(int i = 0; i < Graph.Row; i++)
{
for(int j = 0; j < Graph.Col; j++)
{
Graph.s[i][j] = 0; //初始化雷区为0
Graph.Show[i][j] = '.'; //初始化显示给用户的雷区为'.'
}
}
int x, y; //随机在(x,y)处生成雷
for(int i = 0; i < Graph.Lei; ) //随机雷所在行列,直到满足个数
{
x = rand() % Graph.Row; //随机行
y = rand() % Graph.Col; //随机列
if(Graph.s[x][y] == 1) //如果随机到了相同的行列
continue; //就跳过这个点重新随机
else
{
Graph.s[x][y] = 1; //将随机点置为1
i++; //已经布置的地雷个数+1
}
}
}
bool SelectLevel() //选择难度等级,可以自定义
{
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t简单 1 普通 2 困难 3 自定义(没有排行榜) 4\n");
printf("\t简单难度:5*5,2颗雷。\n");
printf("\t普通难度:7*7,5颗雷。\n");
printf("\t困难难度:10*10,15颗雷。\n");
do //防止用户输入错误
{
scanf("%s", level); //询问用户操作
}while(level[0] != '1' && level[0] != '2' && level[0] != '3' && level[0] != '4');
if(level[0] == '1') //难度1为5*5,2颗雷
InitGraph(5, 5, 2);
else if(level[0] == '2') //难度2为7*7,5颗雷
InitGraph(7, 7, 5);
else if(level[0] == '3') //难度3为10*10,15颗雷
InitGraph(10, 10, 15);
else if(level[0] == '4') //自定义
{
printf("\t请输入行数,列数,地雷个数(用空格隔开,换行结束)\n");
printf("\t行数太多影响游戏体验哦~最好不超过10行\n");
int row, col, lei;
scanf("%d%d%d", &row, &col, &lei);
InitGraph(row, col, lei); //调用初始化雷区的函数
}
else //输入错误
return false;
return true;
}
int NumOfMine(int x, int y) //返回x,y周围的雷的个数
{
if(Graph.s[x][y] == 1) //如果自己是雷
return -1; //就返回-1
int num = 0; //初始化周围雷的个数为0
if(x-1>=0 && y-1>=0 && Graph.s[x-1][y-1]==1)
num++; //左上角有雷则num++
if(x+1<Graph.Row && y-1>=0 && Graph.s[x+1][y-1]==1)
num++; //左下角有雷则num++
if(x-1>=0 && y+1<Graph.Col && Graph.s[x-1][y+1]==1)
num++; //右上角有雷则num++
if(x+1<Graph.Row && y+1<Graph.Col && Graph.s[x+1][y+1]==1)
num++; //右下角有雷则num++
if(x - 1 >= 0 && Graph.s[x - 1][y] == 1)
num++; //上面有雷则num++
if(y - 1 >= 0 && Graph.s[x][y - 1] == 1)
num++; //左边有雷则num++
if(x + 1 < Graph.Row && Graph.s[x + 1][y] == 1)
num++; //下面有雷则num++
if(y + 1 < Graph.Col && Graph.s[x][y + 1] == 1)
num++; //右边有雷则num++
return num; //返回x,y周围雷的个数
}
void Test() //测试用函数,开始游戏时可注释
{
printf("雷区,10表示:\n");
for(int i = 0; i < Graph.Row; i++)
{
for(int j = 0; j <Graph.Col; j++)
{
printf("%d ", Graph.s[i][j]);
}
printf("\n");
}
printf("\n去掉安全区后的雷区:\n");
for(int i = 0; i < Graph.Row; i++)
{
for(int j = 0; j <Graph.Col; j++)
{
if(Graph.s[i][j] == 0)
printf(" ");
else
printf("%d ", Graph.s[i][j]);
}
printf("\n");
}
printf("\n显示周围的雷数目:\n");
for(int i = 0; i < Graph.Row; i++)
{
for(int j = 0; j <Graph.Col; j++)
{
int num = NumOfMine(i, j);
if(num == -1)
printf("* ");
else if(num == 0)
printf(" ");
else
printf("%d ", num);
}
printf("\n");
}
printf("\n");
}
void Display() //显示玩家看到的地图
{
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t地图大小:%d * %d 雷的数目:%d\n", Graph.Row, Graph.Col, Graph.Lei);
if(Graph.Row <= 5) //输入第一行的数字,方便用户看行列
printf("\t\t\t");
else if(Graph.Row <= 10)
printf("\t\t");
else if(Graph.Row <= 20)
printf("\t");
printf(" ");
for(int i = 1; i <= Graph.Col; i++)
{
printf("%d ", i);
}
printf("\n\n");
for(int i = 0; i < Graph.Row; i++)
{
if(Graph.Row <= 5)
printf("\t\t\t");
else if(Graph.Row <= 10)
printf("\t\t");
else if(Graph.Row <= 20)
printf("\t");
if(i >= 9) //是两位数
{
printf("%d ", i + 1);
}
else
{
printf("%d ", i + 1); //输入第一列的数字,方便用户看行列
}
for(int j = 0; j < Graph.Col; j++)
{
printf("%c ", Graph.Show[i][j]);
}
printf("\n");
}
}
void DisplayPlayer() //显示用户信息
{
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t用户名:%s\n", gameplayer[isok].Name);
printf("\t总游戏时长:%.2f seconds\n", gameplayer[isok].AllTime);
printf("\t最好成绩:%.2f seconds\n", gameplayer[isok].BestTime);
printf("\t游戏局数:%d\n", gameplayer[isok].GameCount);
printf("\t胜利次数:%d\n", gameplayer[isok].NumOfWin);
printf("\t失败次数:%d\n", gameplayer[isok].NumOfLose);
printf("\t总胜率:%.2f\n", gameplayer[isok].Rate);
}
void PlayGame() //开始游戏并计时
{
int x, y, k; //x,y是用户输入的行列,k是用户输出的有无地雷
bool ok = 0; //ok存储是否踩雷
bool first = true; //first表示是否是第一次点击
double t; //t用来存储所用时间
clock_t start, finish; //start,finish用来计时
// Test(); //调用测试函数,测试时可开启
Display(); //给用户显示雷区
start = clock(); //开始计时
while(1)
{
printf("\t请输入k x y,k为1表示在(x,y)点有雷,k为0表示在(x,y)点没有雷\n");
printf("\t如果输入之后按了回车,雷区没有变化,那就是你输入错啦~\n");
scanf("%d%d%d", &k, &x, &y);
if(first) //如果是第一次输入
{
if(k == 0) //如果用户判定没有雷
{
Sweep1(x - 1, y - 1, k); //保证第一次一定不踩雷
Display(); //给用户显示雷区
first = false; //first置为false
continue; //进行下一次输入
}
else //如果用户判定有雷
first = false; //first置为false
}
ok = Sweep(x - 1, y - 1, k);
if(ok == false) //ok = false表示踩雷了
{
iswin = 0;
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
setColor(12, 0); //设置为红色
printf("\tGame Over.\n"); //游戏失败
Delay(); //延时
setColor(7, 0); //设置颜色
finish = clock(); //结束计时
Gameplayer.Time = (double)(finish - start) / CLOCKS_PER_SEC;
return; //记录时间
}
if(Judge()) //赢了
{
iswin = 1;
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
setColor(12, 0); //设置为红色
printf("\tYou win!\n"); //游戏胜利
setColor(7, 0); //设置颜色
finish = clock(); //结束计时
Gameplayer.Time = (double)(finish - start) / CLOCKS_PER_SEC;
printf("\tUsing %f seconds!\n", Gameplayer.Time);
return; //记录时间
}
else
Display(); //给用户显示雷区
}
}
bool Sweep(int x, int y, int k) //扫雷的一次操作,第x行第y列,k表示是否有雷
{
if(x < 0 || x >= Graph.Row) //已超出边界
return true;
if(y < 0 || y >= Graph.Col) //已超出边界
return true;
if(Graph.Show[x][y] != '.') //如果已经翻开过
{
if(Graph.Show[x][y] == '@' && k == 0)
{
Graph.Show[x][y] = '.'; //如果已经标记过,就取消标记
return true;
}
else //已经翻开过此点,跳过
return true;
}
int num = NumOfMine(x, y); //周围雷的个数
if(k == 1) //如果玩家判定是地雷
{
Graph.Show[x][y] = '@'; //直接标记
return true;
}
else //如果玩家判定不是地雷
{
if(num == -1) //踩雷了,返回false
return false;
else if(num > 0) //周围的8格有雷
{
Graph.Show[x][y] = (char)num + '0';
return true;
}
else //周围的8格没有雷
{ //标记为0并判断周围八格
Graph.Show[x][y] = '0'; //标记为0
Sweep(x - 1, y - 1, k); //判断左上角
Sweep(x - 1, y, k); //判断上面
Sweep(x - 1, y + 1, k); //判断右上角
Sweep(x, y - 1, k); //判断左边
Sweep(x, y + 1, k); //判断右边
Sweep(x + 1, y - 1, k); //判断左下角
Sweep(x + 1, y, k); //判断下面
Sweep(x + 1, y + 1, k); //判断右下角
}
}
}
void Sweep1(int x, int y, int k) //开局第一次点击,肯定没有雷,如果有会把雷随机到其他地方
{
int i = 0, p, q; //i存储已经重新生成的雷的个数,(p,q)为重新随机生成雷的坐标
if(Graph.s[x][y] == 1) //如果开局第一次点击到了地雷
{
Graph.s[x][y] = 0; //把该点雷移除,重新随机一个雷
while(i != 1)
{
p = rand() % Graph.Row;
q = rand() % Graph.Col;
if(Graph.s[p][q] == 1) //如果随机到了已经有雷的地方
continue; //就跳过,进行下一次随机
else
{
Graph.s[p][q] = 1;
i++;
}
}
}
Sweep(x, y, k); //调用Sweep进行一次扫雷操作
}
bool Judge() //判断是否已经赢得游戏
{ //赢得游戏的条件是,如果有n个地雷
for(int i = 0; i < Graph.Row; i++) //则所有有地雷的点都被标记了@
{ //且一共有n个@标记
for(int j = 0; j < Graph.Col; j++)
{ //如果有雷还没有被@标记,则还未赢得游戏
if(Graph.s[i][j] == 1 && Graph.Show[i][j] != '@')
return false; //如果有被@标记的地方不是雷,则还未赢得游戏
if(Graph.s[i][j] == 0 && Graph.Show[i][j] == '@')
return false;
}
}
return true; //赢得游戏,返回true
}
void DisplayRank() //显示排行榜
{
int i = 0; //记录排行榜中用户数量
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
rewind(Easy);
rewind(Medium);
rewind(Hard);
if(fscanf(Easy, "%d", &i) == EOF) //若排行榜为空
{
printf("\t简单难度排行榜为空\n");
}
else
{
printf("\t简单难度排行榜:\n");
while(~fscanf(Easy, "%d", &i))
{
fscanf(Easy, "%s%lf", Rank[i].Name, &Rank[i].Time);
printf("\t第%d名:\t%s——%.2f seconds\n", i, Rank[i].Name, Rank[i].Time);
i++;
}
}
printf("\n");
if(fscanf(Medium, "%d", &i) == EOF) //若排行榜为空
{
printf("\t普通难度排行榜为空\n");
}
else
{
printf("\t普通难度排行榜:\n");
while(~fscanf(Medium, "%d", &i))
{
fscanf(Medium, "%s%lf", Rank[i].Name, &Rank[i].Time);
printf("\t第%d名:\t%s——%.2f seconds\n", i, Rank[i].Name, Rank[i].Time);
i++;
}
}
printf("\n");
if(fscanf(Hard, "%d", &i) == EOF) //若排行榜为空
{
printf("\t困难难度排行榜为空\n");
}
else
{
printf("\t困难难度排行榜:\n");
while(~fscanf(Hard, "%d", &i))
{
fscanf(Hard, "%s%lf", Rank[i].Name, &Rank[i].Time);
printf("\t第%d名:\t%s——%.2f seconds\n", i, Rank[i].Name, Rank[i].Time);
i++;
}
}
printf("\n");
}
void SaveRanking() //将成绩录入排行榜
{
int i = 0; //用来记录已经读取的排行榜中用户数
if(iswin == 1) //胜利,则与排行榜比较
{
rewind(Easy); //文件位置指针移动至文件开头
rewind(Medium); //文件位置指针移动至文件开头
rewind(Hard); //文件位置指针移动至文件开头
if(level[0] == '1') //难度等级为1
{ //如果原排行榜为空
if(fscanf(Easy, "%d", &i) == EOF)
{ //直接将用户信息写入文件
strcpy(Rank[0].Name, Gameplayer.Name);
Rank[0].Time = Gameplayer.Time;
rewind(Easy);
fprintf(Easy, "1\t%s\t%.2f\n", Rank[0].Name, Rank[0].Time);
}
else //如果原排行榜不为空
{ //则将排行榜读入Rank[]
rewind(Easy); //文件位置指针移动至文件开头
while(~fscanf(Easy, "%d", &i))
{
i--;
fscanf(Easy, "%s%lf", Rank[i].Name, &Rank[i].Time);
} //将此次游戏信息也存入Rank[]
strcpy(Rank[++i].Name, Gameplayer.Name);
Rank[i].Time = Gameplayer.Time;
sort(Rank, Rank + i + 1); //排序
rewind(Easy); //文件位置指针移动至文件开头
if(i >= 4) //排行榜中大于等于五个人
{ //依次写入前五名
for(int j = 0; j < 5; j++)
fprintf(Easy, "%d\t%s\t%.2f\n", j + 1, Rank[j].Name, Rank[j].Time);
}
else //排行榜中小于五个人
{ //依次写入
for(int j = 0; j < i + 1; j++)
fprintf(Easy, "%d\t%s\t%.2f\n", j + 1, Rank[j].Name, Rank[j].Time);
}
}
}
if(level[0] == '2') //难度等级为2
{ //如果原排行榜为空
if(fscanf(Medium, "%d", &i) == EOF)
{ //直接将用户信息写入文件
strcpy(Rank[0].Name, Gameplayer.Name);
Rank[0].Time = Gameplayer.Time;
rewind(Medium);
fprintf(Medium, "1\t%s\t%.2f\n", Rank[0].Name, Rank[0].Time);
}
else //如果原排行榜不为空
{ //则将排行榜读入Rank[]
rewind(Medium); //文件位置指针移动至文件开头
while(~fscanf(Medium, "%d", &i))
{
i--;
fscanf(Medium, "%s%lf", Rank[i].Name, &Rank[i].Time);
} //将此次游戏信息也存入Rank[]
strcpy(Rank[++i].Name, Gameplayer.Name);
Rank[i].Time = Gameplayer.Time;
sort(Rank, Rank + i + 1); //排序
rewind(Medium); //文件位置指针移动至文件开头
if(i >= 4) //排行榜中大于等于五个人
{ //依次写入前五名
for(int j = 0; j < 5; j++)
fprintf(Medium, "%d\t%s\t%.2f\n", j + 1, Rank[j].Name, Rank[j].Time);
}
else //排行榜中小于五个人
{ //依次写入
for(int j = 0; j < i + 1; j++)
fprintf(Medium, "%d\t%s\t%.2f\n", j + 1, Rank[j].Name, Rank[j].Time);
}
}
}
if(level[0] == '3') //难度等级为3
{ //如果原排行榜为空
if(fscanf(Hard, "%d", &i) == EOF)
{ //直接将用户信息写入文件
strcpy(Rank[0].Name, Gameplayer.Name);
Rank[0].Time = Gameplayer.Time;
rewind(Hard);
fprintf(Medium, "1\t%s\t%.2f\n", Rank[0].Name, Rank[0].Time);
}
else //如果原排行榜不为空
{ //则将排行榜读入Rank[]
rewind(Hard); //文件位置指针移动至文件开头
while(~fscanf(Hard, "%d", &i))
{
i--;
fscanf(Hard, "%s%lf", Rank[i].Name, &Rank[i].Time);
} //将此次游戏信息也存入Rank[]
strcpy(Rank[++i].Name, Gameplayer.Name);
Rank[i].Time = Gameplayer.Time;
sort(Rank, Rank + i + 1); //排序
rewind(Hard); //文件位置指针移动至文件开头
if(i >= 4) //排行榜中大于等于五个人
{ //依次写入前五名
for(int j = 0; j < 5; j++)
fprintf(Hard, "%d\t%s\t%.2f\n", j + 1, Rank[j].Name, Rank[j].Time);
}
else //排行榜中小于五个人
{ //依次写入
for(int j = 0; j < i + 1; j++)
fprintf(Hard, "%d\t%s\t%.2f\n", j + 1, Rank[j].Name, Rank[j].Time);
}
}
}
}
}
void Update() //更新用户信息,保存到文件
{
if(isok == -1) //是新用户
{
isok = ++Num; //更新Num和isok
fseek(Player, 0L, SEEK_END); //将文件位置指针移动到文件末尾
strcpy(gameplayer[isok].Name, Gameplayer.Name);
strcpy(gameplayer[isok].Password, Gameplayer.Password);
gameplayer[isok].AllTime = Gameplayer.Time;
gameplayer[isok].BestTime = Gameplayer.Time;
gameplayer[isok].GameCount = 1;
if(iswin == 1) //更新用户各项数据
{
gameplayer[isok].NumOfWin = 1;
gameplayer[isok].NumOfLose = 0;
gameplayer[isok].Rate = 1;
}
else
{
gameplayer[isok].NumOfWin = 0;
gameplayer[isok].NumOfLose = 1;
gameplayer[isok].Rate = 0;
} //将用户数据写入文件
fprintf(Player, "%d\t%s\t%s\t%.2f\t%.2f\t%d\t%d\t%d\t%.2f\n", isok, gameplayer[isok].Name, gameplayer[isok].Password, gameplayer[isok].AllTime,
gameplayer[isok].BestTime, gameplayer[isok].GameCount, gameplayer[isok].NumOfWin, gameplayer[isok].NumOfLose, gameplayer[isok].Rate);
}
else //是老用户
{ //更新用户各项数据
gameplayer[isok].AllTime += Gameplayer.Time;
gameplayer[isok].BestTime = min(gameplayer[isok].BestTime, Gameplayer.Time);
gameplayer[isok].GameCount++;
if(iswin == 1)
gameplayer[isok].NumOfWin++;
else
gameplayer[isok].NumOfLose++;
gameplayer[isok].Rate = (double)gameplayer[isok].NumOfWin / (gameplayer[isok].NumOfLose + gameplayer[isok].NumOfWin);
rewind(Player); //讲文件位置指针移动至文件开头
for(int j = 1; j <= Num; j++) //讲用户数据写入文件
fprintf(Player, "%d\t%s\t%s\t%.2f\t%.2f\t%d\t%d\t%d\t%.2f\n", j, gameplayer[j].Name, gameplayer[j].Password, gameplayer[j].AllTime,
gameplayer[j].BestTime, gameplayer[isok].GameCount, gameplayer[j].NumOfWin, gameplayer[j].NumOfLose, gameplayer[j].Rate);
}
}
bool ChangePassword() //修改密码
{
char ch1[10], ch2[10]; //ch1存储第一次输入的密码,ch2存储第二次输入的密码
char mm; //存储被隐藏的密码
int p = 0; //存储密码位数
system("cls"); //清屏
printf("\t===============挖地雷小游戏===============\n");
printf("\t\t\t\t用户:%s\n", Gameplayer.Name);
printf("\t请输入新密码,密码不超过10个字符:");
while(1) //输入新密码,显示星号*
{
mm = getch(); //输入m且隐藏
if(mm == '\r') //遇到回车,停止输入
{
printf("\n"); //回车被mm吃了,输出回车
ch1[p] = '\0'; //给ch1数组结尾符'\0'
break; //退出循环
}
if(mm == '\b') //遇到退格键
{
p--; //j往前移一位
printf("\b \b"); //输出退格然后用空格覆盖原来的*再输出退格
continue; //跳过这次循环
}
ch1[p++] = mm; //将密码赋值给Password
printf("*"); //输出'*'
}
// printf("%s\n", ch1); //调试用
p = 0;
printf("\t请再次输入新密码:"); //再次输入新密码
while(1) //输入密码,显示星号*
{
mm = getch(); //输入m且隐藏
if(mm == '\r') //遇到回车,停止输入
{
printf("\n"); //回车被mm吃了,输出回车
ch2[p] = '\0'; //给ch2数组结尾符'\0'
break; //退出循环
}
if(mm == '\b') //遇到退格键
{
p--; //j往前移一位
printf("\b \b"); //输出退格然后用空格覆盖原来的*再输出退格
continue; //跳过这次循环
}
ch2[p++] = mm; //将密码赋值给Password
printf("*"); //输出'*'
}
// printf("%s\n", ch2); //调试用
if(strcmp(ch1, ch2) != 0) //比较两次输入是否相同
{
printf("\t输入有误!\n"); //若不同则重新输入
Delay(); //延时
return false;
}
strcpy(gameplayer[isok].Password, ch1); //更新用户的密码
rewind(Player); //将文件位置指针移动至文件开头
for(int j = 1; j <= Num; j++) //将更新后的用户数据写入文件
fprintf(Player, "%d\t%s\t%s\t%.2f\t%.2f\t%d\t%d\t%d\t%.2f\n", j, gameplayer[j].Name, gameplayer[j].Password, gameplayer[j].AllTime,
gameplayer[j].BestTime, gameplayer[j].GameCount, gameplayer[j].NumOfWin, gameplayer[j].NumOfLose, gameplayer[j].Rate);
return true;
}
void Close() //关闭文件
{
fclose(Easy); //关闭Easy.txt文件
fclose(Medium); //关闭Mediun.txt文件
fclose(Hard); //关闭Hard.txt文件
fclose(Player); //关闭Player.txt文件
}
void End() //结束画面
{
system("cls"); //清屏
printf("-------------------------------------------------------------\n");
printf("-------------------------------------------------------------\n");
for(int i = 1; i <= 5; i++) //画菱形
{
printf("\t");
for(int j = 6; j > i; j--)
{
printf(" ");
}
for(int k = 1; k <= 2 * i - 1; k++)
{
printf("*");
}
printf("\n");
}
for(int i = 1; i <= 6; i++)
{
printf("\t");
for(int j = 1; j <= i - 1; j++)
{
printf(" ");
}
for(int k = 1; k <= 13 - 2 * i; k++)
{
printf("*");
}
printf("\n");
}
gotoxyWithFullwidth(8, 2); //定位坐标
printf("\t挖地雷小游戏 *");
gotoxyWithFullwidth(8, 3); //定位坐标
printf("\t制作者: ***");
gotoxyWithFullwidth(8, 4); //定位坐标
printf("\tB16040224 *****");
gotoxyWithFullwidth(9, 5); //定位坐标
printf("\t赵立昌 *******");
gotoxyWithFullwidth(9, 6); //定位坐标
printf("\tB16040216 *********");
gotoxyWithFullwidth(9, 7); //定位坐标
printf("\t刘奎炎 ***********");
gotoxyWithFullwidth(8, 8); //定位坐标
printf("\t *********");
gotoxyWithFullwidth(8, 9); //定位坐标
printf("\t *******");
gotoxyWithFullwidth(8, 10); //定位坐标
printf("\t谢谢使用~~~ *****");
gotoxyWithFullwidth(8, 11); //定位坐标
printf("\t ***");
gotoxyWithFullwidth(8, 12); //定位坐标
printf("\t *\n");
printf("-------------------------------------------------------------\n");
printf("-------------------------------------------------------------\n");
}
int gotoxyWithFullwidth(short x, short y) //以控制台左上角为坐标原点,定位光标位置
{
static COORD cd;
cd.X = (x << 1);
cd.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cd);
return 0;
}
void setColor(unsigned short ForeColor,unsigned short BackGroundColor)
{
//获取当前窗口句柄,设置颜色
HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle,ForeColor+BackGroundColor*0x10);
}