包含但不仅限于:
标记地点和取消
可随时返回的主界面
起手生成地图自动避雷
难度选择和自定义地图
检测键盘移动光标(毕竟不能直接检测鼠标)
雷数和标记数显示
颜色的设置等等 (虽然就只是扫雷全部该有的hhhhh)
PS:现在还加入了商店和复活币,还有存档
源码如下,可以直接编译运行
本人大一学生,基础差,好多地方写的烂,尽管骂
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <windows.h>
#include <fstream>
#include <iomanip>
using namespace std;
//版本号
double version_num = 3.0;
//全局变量cdt
int cdt = 0;
//金币数
int goldcoin = 0;
//道具数
int tool_num = 0;
//标记数
int allsign = 0;
//主菜单
void mainmenu(int &cdt);
void colorshow(unsigned int num);
void backlok();
class Position {
public:
//构造函数
Position(unsigned int x = 0, unsigned int y = 0) {
this->x = x;
this->y = y;
ifclicked = 0;
ifedge = 0;
sign_cdt = 0;
ifbomb = 0;
num = 0;
};
//点击这个点,返回是否点击成功,已经点过的就不成功
bool click() {
if (ifclicked) {
return false;
} else {
ifclicked = 1;
return true;
}
}
//设置为地雷,返回是否成功,已经过的就不成功
bool setbomb() {
if (ifbomb) {
return false;
} else {
ifbomb = 1;
return true;
}
}
//标记为边界
void setedge() {
ifedge = 1;
}
//转换标记,0,1,2
void sign() {
sign_cdt = (sign_cdt + 1) % 3;
}
//显示点
void showposition() {
if (ifedge) {
cout << "- ";
} else if ((sign_cdt == 1 || sign_cdt == 2) && !ifclicked) {
if (sign_cdt == 1) {
cout << "\033[91mF\033[0m ";
allsign++;
} else if (sign_cdt == 2) {
cout << "\033[91m?\033[0m ";
}
} else if (!ifclicked) {
cout << "#\033[0m ";
} else if (ifbomb) {
cout << "\033[91m!\033[0m ";
} else {
colorshow(num);
}
};
//结束时的展示
void showposition_clean() {
if (ifedge) {
cout << "- ";
} else if (ifbomb) {
cout << "\033[91m!\033[0m ";
} else {
colorshow(num);
}
}
friend class Ground;
private:
unsigned int x, y, num;
bool ifclicked;
bool ifedge;
int sign_cdt;
bool ifbomb;
};
class Ground {
public:
//构造函数
Ground(unsigned int _Long = 0, unsigned int _Wide = 0) {
Long = _Long + 2;
Wide = _Wide + 2;
tab_line = 1;
tab_list = 1;
Num = 0;
reward = 0;
//创建二维数组
for (unsigned int i = 0; i < Long; i++) {
vector<Position> tmp(Wide);
positions.push_back(tmp);
}
for (unsigned int i = 0; i < Long; i++) {
for (unsigned int j = 0; j < Wide; j++) {
if (i == 0 || j == 0 || i == Long - 1 || j == Wide - 1) {
positions[i][j].setedge();
}
}
}
};
//显示地图
void showground() {
allsign = 0;
cout << "0 ";
for (int t = 0; t < positions[0].size(); t++) {
cout << t % 10 << ' ';
}
cout << '\n';
for (int i = 0; i < positions.size(); i++) {
cout << i % 10 << ' ';
for (int j = 0; j < positions[i].size(); j++) {
if (i == tab_line && j == tab_list) {
//显示光标背景
cout << "\033[5m\033[103m";
positions[i][j].showposition();
cout << "\033[0m";
} else {
positions[i][j].showposition();
}
}
cout << '\n';
}
cout << "总雷数:\033[91m" << Num << "\033[0m 当前总标记:\033[92m" << allsign << " \033[0m 复活币:\033[93m" <<
tool_num << "\033[0m" << '\n';
allsign = 0;
}
//点击某点,包括连锁反应
void click(unsigned int x, unsigned int y) {
//坐标在范围内
if (1 <= x && x <= Long - 2 && 1 <= y && y <= Wide - 2) {
positions[x][y].click();
//检查并点击一大块
bool needclick = 0;
do {
needclick = 0;
//遍历每一个地点
for (int i = 1; i < positions.size() - 1; i++) {
for (int j = 1; j < positions[i].size() - 1; j++) {
bool click_around0 = 0;
//遍历这个点周围的九宫格区域
for (int m = i - 1; m <= i + 1; m++) {
for (int n = j - 1; n <= j + 1; n++) {
//如果点击成功就说明还需要点击
if (positions[m][n].ifclicked && positions[m][n].num == 0) {
click_around0 = 1;
}
}
}
if (click_around0 && !positions[i][j].ifclicked) {
positions[i][j].click();
needclick = 1;
}
}
}
} while (needclick);
}
//输入坐标错误,do nothing
}
//设置一个地雷
bool setbomb_1(unsigned int x, unsigned int y) {
if (1 <= x && x <= Long - 2 && 1 <= y && y <= Wide - 2) {
return positions[x][y].setbomb();
} else {
return false;
}
}
//设置全部地雷;同时设置奖励
void setbomb(unsigned int x, unsigned int y, unsigned int num) {
Num = num;
reward = 10 * Num * Num / ((Long - 2) * (Wide - 2));
//输入可用的数字
if (1 <= x && x <= Long - 2 && 1 <= y && y <= Wide - 2 && num <= (Long - 2) * (Wide - 2)) {
srand((unsigned)time(NULL));
for (unsigned int i = 0; i < num;) {
int rx = 1 + rand() % (Long - 2);
int ry = 1 + rand() % (Wide - 2);
if (rx != x || ry != y) {
if (positions[rx][ry].setbomb()) {
i++;
}
}
}
}
}
//设置数字
void setnum() {
//遍历每一个地点
for (int i = 1; i < positions.size() - 1; i++) {
for (int j = 1; j < positions[i].size() - 1; j++) {
positions[i][j].num = 0;
//遍历这个点周围的九宫格区域
for (int m = i - 1; m <= i + 1; m++) {
for (int n = j - 1; n <= j + 1; n++) {
//周围有雷就加雷数
if (positions[m][n].ifbomb) {
positions[i][j].num++;
}
}
}
//减去自己的雷
if (positions[i][j].ifbomb) {
positions[i][j].num--;
}
}
}
}
//标记或取消雷
void setsign(unsigned int x, unsigned int y) {
if (1 <= x && x <= Long - 2 && 1 <= y && y <= Wide - 2) {
positions[x][y].sign();
}
}
//移动一次光标
void move_tab_1(char ch) {
if (ch == 'w' && tab_line > 1) {
tab_line--;
} else if (ch == 's' && tab_line < Long - 2) {
tab_line++;
} else if (ch == 'a' && tab_list > 1) {
tab_list--;
} else if (ch == 'd' && tab_list < Wide - 2) {
tab_list++;
}
}
//移动光标
bool move_tab() {
while (true) {
if (GetAsyncKeyState('W') & 0x8000) {
move_tab_1('w');
backlok();
Sleep(150);
return 1;
} else if (GetAsyncKeyState('S') & 0x8000) {
move_tab_1('s');
backlok();
Sleep(150);
return 1;
} else if (GetAsyncKeyState('A') & 0x8000) {
move_tab_1('a');
backlok();
Sleep(150);
return 1;
} else if (GetAsyncKeyState('D') & 0x8000) {
move_tab_1('d');
backlok();
Sleep(150);
return 1;
} else if (GetAsyncKeyState('J') & 0x8000) {
click(tab_line, tab_list);
backlok();
Sleep(150);
return 1;
} else if (GetAsyncKeyState('K') & 0x8000) {
setsign(tab_line, tab_list);
backlok();
Sleep(150);
return 1;
} else if (GetAsyncKeyState('0') & 0x8000) {
backlok();
return 0;
}
}
}
//初始化移动光标得到第一个坐标
char onlymove_tab() {
while (true) {
if (GetAsyncKeyState('W') & 0x8000) {
move_tab_1('w');
backlok();
Sleep(150);
return 'w';
} else if (GetAsyncKeyState('S') & 0x8000) {
move_tab_1('s');
backlok();
Sleep(150);
return 's';
} else if (GetAsyncKeyState('A') & 0x8000) {
move_tab_1('a');
backlok();
Sleep(150);
return 'a';
} else if (GetAsyncKeyState('D') & 0x8000) {
move_tab_1('d');
backlok();
Sleep(150);
return 'd';
} else if (GetAsyncKeyState('J') & 0x8000) {
Sleep(150);
backlok();
return 'j';
} else if (GetAsyncKeyState('K') & 0x8000) {
backlok();
Sleep(150);
return 'k';
} else if (GetAsyncKeyState('0') & 0x8000) {
backlok();
return '0';
}
}
//用退格键抵消多余的输入
INPUT input;
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_BACK; // 退格键的虚拟键码
input.ki.dwFlags = 0; // 指定按键按下事件
SendInput(1, &input, sizeof(input)); // 模拟按下退格键
}
//在光标位置初始化
void origin_set(int num) {
setbomb(tab_line, tab_list, num);
setnum();
click(tab_line, tab_list);
}
//检查局势,0为正常,1为赢,-1为输
int condition() {
for (int i = 1; i < positions.size() - 1; i++) {
for (int j = 1; j < positions[i].size() - 1; j++) {
if (positions[i][j].ifbomb && positions[i][j].ifclicked) {
return -1;
}
}
}
for (int i = 1; i < positions.size() - 1; i++) {
for (int j = 1; j < positions[i].size() - 1; j++) {
if (!positions[i][j].ifbomb && !positions[i][j].ifclicked) {
return 0;
}
}
}
return 1;
}
//复活
void relife() {
for (int i = 1; i < positions.size() - 1; i++) {
for (int j = 1; j < positions[i].size() - 1; j++) {
if (positions[i][j].ifbomb && positions[i][j].ifclicked) {
positions[i][j].ifclicked = 0;
return;
}
}
}
}
//返回奖励值
unsigned int get_reward() {
return reward;
}
//结束时的展示
void showground_clean() {
cout << "0 ";
for (int t = 0; t < positions[0].size(); t++) {
cout << t % 10 << ' ';
}
cout << '\n';
for (int i = 0; i < positions.size(); i++) {
cout << i % 10 << ' ';
for (int j = 0; j < positions[i].size(); j++) {
//判断输出金钩
if (positions[i][j].ifbomb && positions[i][j].sign_cdt && !positions[i][j].ifclicked) {
cout << "\033[93m√\033[0m ";
} else if (positions[i][j].ifbomb && !positions[i][j].ifclicked) {
cout << "\033[91m*\033[0m ";
} else {
positions[i][j].showposition_clean();
}
}
cout << '\n';
}
}
friend void startgame(Ground g);
private:
unsigned int Long, Wide, tab_line, tab_list, Num, reward;
vector <vector<Position >> positions;
};
void colorshow(unsigned int num) {
if (num == 0)
cout << " \033[0m ";
if (num == 1)
cout << "\033[34m1\033[0m ";
if (num == 2)
cout << "\033[33m2\033[0m ";
if (num == 3)
cout << "\033[31m3\033[0m ";
if (num == 4)
cout << "\033[94m4\033[0m ";
if (num == 5)
cout << "\033[36m5\033[0m ";
if (num == 6)
cout << "\033[95m6\033[0m ";
if (num == 7)
cout << "\033[32m7\033[0m ";
if (num == 8)
cout << "\033[35m8\033[0m ";
if (num == 9)
cout << "\033[91m9\033[0m ";
}
//读取存档更新数据
void readgame() {
ifstream ifs;
ifs.open("savegame.txt", ios::in);
ifs >> goldcoin;
ifs >> tool_num;
ifs.close();
}
//更新存档
void savegame(int re_goldcoin, unsigned int re_tool_num) {
ofstream ofs;
ofs.open("savegame.txt", ios::out);
ofs << re_goldcoin << '\n';
ofs << re_tool_num;
ofs.close();
}
//改金币
bool change_goldcoin(int change) {
readgame();
if (goldcoin + change >= 0) {
savegame(goldcoin + change, tool_num);
return 1;
} else {
return 0;
}
}
//改复活币
bool change_tool_num(int change) {
readgame();
if (tool_num + change >= 0) {
savegame(goldcoin, tool_num + change);
return 1;
} else {
return 0;
}
}
//用退格键抵消多余的输入
void backlok() {
//用退格键抵消多余的输入
INPUT input;
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_BACK; // 退格键的虚拟键码
input.ki.dwFlags = 0; // 指定按键按下事件
SendInput(1, &input, sizeof(input)); // 模拟按下退格键
}
// 模拟按下回车键
void returnback() {
// 模拟按下回车键
INPUT input;
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_RETURN; // 回车键的虚拟键码
input.ki.dwFlags = 0; // 指定按键按下事件
SendInput(1, &input, sizeof(input)); // 模拟按下回车键
}
//主要游戏
void menu() {
cout << "*****************************\n"
<< "* 按键控制光标位置:WSAD *\n"
<< "* 按J:当前位置探雷 *\n"
<< "* 按K:当前位置标记/解除 *\n"
<< "* 按0: 返回主菜单 *\n"
<< "*****************************\n\n\n";
}
void show_game(Ground g) {
system("cls");
menu();
g.showground();
}
void endmenu() {
cout << "*****************************\n"
<< "* *\n"
<< "* 游戏 *\n"
<< "* 结束 *\n"
<< "* *\n"
<< "*****************************\n\n\n";
}
void startgame(Ground g, unsigned int Long, unsigned int Wide, unsigned int num) {
while (true) {
system("cls");
cout << "*****************************\n"
<< "* 按键控制光标位置:WSAD *\n"
<< "* 按J:当前位置探雷 *\n"
<< "*按K:当前位置标记(首次除外)*\n"
<< "* 按0: 返回主菜单 *\n"
<< "*****************************\n\n\n";
g.showground();
char ch = g.onlymove_tab();
if (ch == 'j' || ch == 'k')
break;
else if (ch == '0') {
returnback();
return;
}
backlok();
}
g.origin_set(num);
int result = 0;
//初始化完成,正式开始
while (result == 0) {
show_game(g);
if (g.move_tab()) {
result = g.condition();
}
//返回主菜单
else {
returnback();
result = 3;
}
backlok();
//选择复活
if (result == -1) {
readgame();
if (tool_num > 0) {
show_game(g);
cout << "\n \033[91m\033[5mDuang!!!\033[0m\n";
cout << "\033[93m你炸了,但是你有" << tool_num <<
"个复活币哦,是否选择复活呢?\033[0m\n输入1:\033[93m我复活啦!\033[0m\n输入2:哎~我有就是不用\n\n你的选择是:";
int ifrelife;
cin >> ifrelife;
while (cin.fail() || (ifrelife != 1 && ifrelife != 2)) {
cin.clear();
cin.ignore();
show_game(g);
cout << "\n \033[91m\033[5mDuang!!!\033[0m\n";
cout << "是否选择复活呢?\n输入1:复活\n输入2:不复活\n\n你的选择是:";
cin >> ifrelife;
}
if (ifrelife == 1) {
g.relife();
change_tool_num(-1);
result = 0;
} else {
result = 2;
}
} else {
result = 2;
}
}
}
//赢
if (result == 1) {
system("cls");
endmenu();
g.showground_clean();
cout << "\n \033[93m\033[5m恭喜!你赢啦!!!\033[0m\n\n";
cout << "\033[93m你获得了金币:" << g.get_reward() << "\033[0m";
cout << "\n\n输入0回到主菜单:";
char ch(0);
change_goldcoin(g.get_reward());
cin >> ch;
while (ch != '0') {
cin.clear();
cin.ignore();
system("cls");
menu();
g.showground_clean();
cout << "\n \033[93m\033[5m恭喜!你赢啦!!!\033[0m\n\n";
cout << "\033[93m你获得了金币:" << g.get_reward() << "\033[0m";
cout << "\n\n输入0回到主菜单:";
cin >> ch;
}
cin.sync();
return;
}
//输
else if (result == 2) {
system("cls");
endmenu();
g.showground_clean();
cout << "\n \033[91m\033[5mDuang!!!\033[0m";
cout << "\n\n输入0回到主菜单:";
char ch(0);
cin >> ch;
while (ch != '0') {
cin.clear();
cin.ignore();
system("cls");
menu();
g.showground_clean();
cout << "\n \033[91m\033[5mDuang!!!\033[0m";
cout << "\n\n输入0回到主菜单:";
cin >> ch;
}
cin.sync();
return;
}
while (getchar() != '\n');
return;
}
//主菜单
void mainmenu_show() {
readgame();
cout << "\033[93m金币数:" << setw(5) << goldcoin << " 复活币:" << setw(4) << tool_num << "\033[0m\n";
cout << "---------------主菜单--------------------\n"
<< "| 难度 | 选择序号 |\n"
<< "-----------------------------------------\n"
<< "| \033[32m简单( 9*9, 5雷)\033[0m | 1 |\n"
<< "-----------------------------------------\n"
<< "| \033[33m中等(10*15,20雷)\033[0m | 2 |\n"
<< "-----------------------------------------\n"
<< "| \033[31m困难(16*30,99雷)\033[0m | 3 |\n"
<< "-----------------------------------------\n"
<< "| \033[35m自定义( max60*60)\033[0m | 4 |\n"
<< "-----------------------------------------\n"
<< "| \033[93m商店\033[0m | 5 |\n"
<< "-----------------------------------------\n"
<< "| 介绍 | 6 |\n"
<< "-----------------------------------------\n";
cout << "你的选择为:";
}
void mainmenu(int &cdt) {
system("cls");
mainmenu_show();
cin >> cdt;
while (cin.fail() || (cdt != 1 && cdt != 2 && cdt != 3 && cdt != 4 && cdt != 5 && cdt != 6)) {
cin.clear();
cin.ignore(1024, '\n');
mainmenu(cdt);
}
}
//自定义
void user_defined() {
unsigned int Long, Wide, num;
system("cls");
mainmenu_show();
cout << "自定义\n";
cout << "行数:";
cin >> Long;
while (cin.fail() || Long >= 60) {
system("cls");
mainmenu_show();
cout << "自定义\n";
cout << "行数:";
cin >> Long;
}
system("cls");
mainmenu_show();
cout << "自定义\n";
cout << "行数:" << Long << endl;
cout << "列数:";
cin >> Wide;
while (cin.fail() || Wide >= 60) {
system("cls");
mainmenu_show();
cout << "自定义\n";
cout << "行数:" << Long << endl;
cout << "列数:";
cin >> Wide;
}
system("cls");
mainmenu_show();
cout << "自定义\n";
cout << "行数:" << Long << endl;
cout << "列数:" << Wide << endl;
cout << "地雷数:";
cin >> num;
while (cin.fail() || num > Long * Wide - 1) {
system("cls");
mainmenu_show();
cout << "自定义\n";
cout << "行数:" << Long << endl;
cout << "列数:" << Wide << endl;
cout << "地雷数:";
cin >> num;
}
startgame(Ground(Long, Wide), Long, Wide, num);
return;
}
//介绍
void introduce() {
system("cls");
cout << "版本号:3.0\n";
cout << "前言:本扫雷游戏是我第一个练手的游戏,做工粗糙,以后可能会优化awa(就比如现在有乱码的bug啊啊啊)(已修复)\n"
<< " 还有,如果在玩的时候敲了回车会在结束时直接跳过结算回主界面,就当做特性吧(不是)(已修复)\n\n"
<< "规则:基本的扫雷,不用多说\n"
<< "操作:在闪烁的就是你的光标,用wsad来操作\n"
<< " 创建后,先随便探一个地点来初始化游戏(主要是防止第一就次踩雷)\n"
<< " 按下J:探雷\n"
<< " 按下K:标记雷(或解除标记)\n"
<< " 按下0:返回主菜单\n"
<< "获胜条件:吧没有雷的地方全部探完(不是全部标记)\n\n"
<< "如果你觉得做的很烂,赶快去鞭策作者hhhhhh\n"
<< "如果你也有做游戏的梦想就来找也可以来找我聊(企鹅:2431526739)\n虽然我还什么都不会(卑微)\n"
<< "有C++方面的问题也可以来找我啦(虽然我也大概率答不上来)\n\n";
cout << "\n输入任意内容回到主菜单:";
char ch(0);
cin >> ch;
cin.clear();
cin.ignore(10000, '\n');
return;
};
//商店
int store_cdt = 0;
void show_store() {
system("cls");
readgame();
cout << "\033[93m金币数:" << setw(5) << goldcoin << " 复活币:" << setw(4) << tool_num << "\n";
cout << " 奸商:\n"
<< "为了助力你在雷区所向披靡,本店隆重推新:复活币\n"
<< "10金币一枚,价格实惠,童嫂无期,还在等什么?\033[0m\n\n\n";
}
void store() {
show_store();
cout << "输入1:你说得对,但是把我放回主菜单\n"
<< "输入2:好好好,买一个\n";
store_cdt = 0;
cin >> store_cdt;
while (cin.fail() || (store_cdt != 1 && store_cdt != 2)) {
cin.clear();
cin.ignore(1024, '\n');
store();
}
switch (store_cdt) {
case 1:
return;
break;
case 2:
if (change_goldcoin(-10)) {
change_tool_num(1);
cout << "\033[93m老板大气!\033[0m";
Sleep(200);
} else {
cout << "\033[93m你的金币呢?\033[0m";
Sleep(500);
}
store();
break;
}
}
int main() {
//取消输入输出流独立性,在DEV环境会格式混乱,在vs就不会
// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
while (1) {
cdt = 0;
mainmenu(cdt);
switch (cdt) {
case 1:
startgame(Ground(9, 9), 9, 9, 5);
break;
case 2:
startgame(Ground(10, 15), 10, 15, 20);
break;
case 3:
startgame(Ground(16, 30), 16, 30, 99);
break;
case 4:
user_defined();
break;
case 5:
store();
break;
case 6:
introduce();
break;
}
}
}