扫雷部分:

matrix记录地雷和周边信息,用0表示什么都没有,5表示地雷,1,2,3,4,表示周围地雷的数量
    matrix_probe记录这个地方是否被探索过,0表示没有被探索过,1表示探索过,2表示插旗,认为这里有地雷

#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#define MAXSIZE 100   //棋盘的最大尺寸
#define OK 1
#define ERROR 0using namespace std;
//栈的数据结构,用于揭开迷雾
typedef struct stack {int coord[MAXSIZE][2];   //用于记录坐标数据int top,bottom;          //栈底和栈顶
}*st;
//初始化这个栈
void init_stack(st s) {for (int i = 0; i < MAXSIZE; i++) {for (int j = 0; j < 2; j++) {s->coord[i][j] = 0;}}s->top= -1;s->bottom = -1;
}
//判断这个栈是否为空,如果为空返回0,不为空返回1
int empty(st s) {if (s->top == s->bottom)//这是一个空栈return 0;else//这不是一个空栈return 1;
}
//入栈
int push(st s,int x,int y) {s->top++;if (s->top == MAXSIZE) {//栈满,不可以在添加元素了s->top--;cout << "栈已经满了,不可以再将数据入栈";return ERROR;}s->coord[s->top][0] = x;s->coord[s->top][1] = y;return OK;
}
//出栈
int pop(st s,int b[2]) {b[0] = s->coord[s->top][0]; b[1] = s->coord[s->top][1];s->top--;return OK;
}/*matrix记录地雷和周边信息,用0表示什么都没有,5表示地雷,1,2,3,4,表示周围地雷的数量matrix_probe记录这个地方是否被探索过,0表示没有被探索过,1表示探索过,2表示插旗,认为这里有地雷
*/class MineCleaner {int matrix[MAXSIZE][MAXSIZE];    //棋盘int matrix_probe[MAXSIZE][MAXSIZE]; //记录是否被探索过int size;            //用户指定的棋盘大小int density;         //用户指定的地雷的密度int score;           //游戏得分,每走一步如果没有踩到雷的话就加一分
public:MineCleaner();//构造函数MineCleaner(int size, int density);~MineCleaner();//析构函数void print_blank();   //打印空格,就是每行最开始的空格void print_bottom();  //打印每一行的底部void print_col_info();//答应列数void print_main_info(int x,int y);   //打印棋盘内容,也就是主要的信息void print();   //打印棋盘void init_chessboard();  //初始化棋盘,也就是埋雷void add_score();int get_x();            //获取横坐标int get_y();           //获取纵坐标int get_size();int move();         //游戏主界面int move(int x, int y);   //重载的AI移动void game_over_print();    //游戏结束的界面void uncover(int x,int y);      //揭开没有信息的区域int if_win();       //判断是否胜利void win_print();          //胜利界面int get_matrix(int x,int y);int get_matrix_probe(int x, int y);
};
//构造函数
MineCleaner::MineCleaner() {cout << "请问是否指定棋盘大小,如果不指定大小的话,那么棋盘将会是默认大小10*10?[y/n]  ";char a;cin >> a;//输入字符,以回车结束if (a == 'y' || a == 'Y') {//如果回答是yes的话cout << "请输入棋盘的大小:";int size;cin >> size;this->size = size + 2;   //这样子棋盘就是从1开始到size-2结束的区域}else {this->size = 12;  //从1开始到10结束的区域}system("cls");cout << "请问是否指定棋盘的地雷密度,如果不指定的话那么将会是默认地雷密度30%?[y/n]  ";cin >> a;//输入字符,以回车结束if (a == 'y' || a == 'Y') {//如果指定地雷密度的话cout << "请输入0-100(不包括0和100)之间的地雷密度数,这将影响游戏的难度:";int density;cin >> density;while (density >= 100 || density <= 0) {cout << "输入的数据不正确,请重新输入:";cin >> density;}this->density = density;}else {this->density = 30;   //默认的地雷密度为30%}for (int i = 0; i < size; i++) {for (int j = 0; j < size; j++) {this->matrix[i][j] = 0;  //初始化棋盘this->matrix_probe[i][j] = 0;//一开始都是初始化没有被探索过}}for (int j = 0; j < this->size; j++) {//将边框变为可见,为ai做准备this->matrix_probe[0][j] = 1;this->matrix_probe[this->size - 1][j] = 1;this->matrix_probe[j][this->size - 1] = 1;this->matrix_probe[j][0] = 1;}system("cls");this->score = 0;//初始化分数init_chessboard();//初始化棋盘信息
}
MineCleaner::MineCleaner(int size, int density) {this->size = size + 2;this->density = density;for (int i = 0; i < this->size; i++) {for (int j = 0; j < this->size; j++) {this->matrix[i][j] = 0;  //初始化棋盘this->matrix_probe[i][j] = 0;//一开始都是初始化没有被探索过}}for (int j = 0; j < this->size; j++) {//将边框变为可见,为ai做准备this->matrix_probe[0][j] = 1;this->matrix_probe[this->size - 1][j] = 1;this->matrix_probe[j][this->size - 1] = 1;this->matrix_probe[j][0] = 1;}//system("cls");this->score = 0;//初始化分数init_chessboard();//初始化棋盘信息
}
MineCleaner::~MineCleaner(){}
void MineCleaner::add_score() {this->score++;
}
void MineCleaner::print_blank() {cout << "                      ";
}
void MineCleaner::print_bottom() {cout << endl;print_blank();cout << "    ";for (int i = 1; i < this->size - 1; i++) {cout << " ---";}cout << endl;
}
void MineCleaner::print_col_info() {print_blank();cout << "     ";for (int i = 1; i < this->size - 1; i++) {cout <<" "<< i << "  ";}
}
void MineCleaner::print_main_info(int x,int y) {//先查看matrix_probe数组,如果是0表示没有翻开,什么都不显示,如果是1就显示内容//如果是2就插旗子表示有可能有地雷if (this->matrix_probe[x][y] == 0) {//这表示没有翻开格子cout << "   |";}else if (this->matrix_probe[x][y] == 2) {//这表示插旗判断可能有地雷cout << " @ |";}else {//如果翻开了就显示这个格子本来的信息if (this->matrix[x][y] == 5) {cout << " * |";}else if (this->matrix[x][y] == 0) {cout << " 0 |";}else {cout << " " << this->matrix[x][y] << " |";}}
}
//打印棋盘,调试成功
void MineCleaner::print() {cout << endl;cout << endl;cout << endl;print_col_info();print_bottom();for (int i = 1; i < this->size - 1; i++) {//行信息,每一行开始的时候都要空行并且打印行标if (i < 10) {print_blank();cout << i << "   |";}else {print_blank();cout << i << "  |";}for (int j = 1; j < this->size - 1; j++) {//列信息print_main_info(i,j);}cout <<"  "<< i;//结束的时候打印行信息print_bottom();}//最后再打印列信息print_col_info();cout << endl;print_blank();cout << "当前得分是:" <<this->score;cout << endl;
}
int MineCleaner::get_size() {return this->size;
}
//初始化棋盘信息
void MineCleaner::init_chessboard() {int num_of_total = (this->size-2)*(this->size-2);   //这是显示出来的棋盘的总数量float des = (float)this->density / 100;int x, y;int num_of_mine = des * num_of_total;  //这是地雷的总数//埋雷while (num_of_mine != 0) {//如果地雷数量不为0的话就要继续埋雷srand((unsigned)time(NULL));x = rand() % (this->size - 1) + 1;  //范围是从1-(size-1)y = rand() % (this->size - 1) + 1;while (this->matrix[x][y] == 5 || x == this->size-1 || y==this->size-1) {//如果这个地方已经有雷了,就重新找一个地方埋雷x = rand() % (this->size - 1) + 1;  //范围是从1-(size-1)y = rand() % (this->size - 1) + 1;}this->matrix[x][y] = 5;    //埋雷num_of_mine--;}//接下来要循环遍历整个棋盘的每个坐标,写下雷周围的数字for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix[i][j] != 5) {//如果这个坐标不是雷区才进行判断if (this->matrix[i - 1][j] == 5) this->matrix[i][j]++;if (this->matrix[i + 1][j] == 5) this->matrix[i][j]++;if (this->matrix[i][j - 1] == 5) this->matrix[i][j]++;if (this->matrix[i][j + 1] == 5) this->matrix[i][j]++;}}}
}
int MineCleaner::get_x() {print_blank();cout << "请输入要探索的横坐标(行):";int x;cin >> x;while (x < 0 || x > this->size - 1) {print_blank();cout << "输入的坐标超出允许的范围,请重新输入:";cin >> x;}return x;
}
int MineCleaner::get_y() {print_blank();cout << "请输入要探索的纵坐标(列):";int y;cin >> y;while (y < 0 || y > this->size - 1) {print_blank();cout << "输入的坐标超出允许的范围,请重新输入:";cin >> y;}return y;
}
//走棋
int MineCleaner::move() {//先接收要走棋的坐标位置//system("cls");print();int x, y;x = get_x();y = get_y();while (this->matrix_probe[x][y] == 1) {print_blank();cout << "该坐标已被探索过,请重新输入";x = get_x();y = get_y();}if (this->matrix[x][y] == 5) {game_over_print();return 0;}else if (this->matrix[x][y] == 0) {//如果这是个没有信息的区域,则要将一片连续的没有信息的区域都揭开uncover(x,y);if (if_win()) {return 0;}return 1;}else {this->matrix_probe[x][y] = 1; //表示已经探索过了add_score();return 1;}
}
//0是胜利,-1是失败
int MineCleaner::move(int x, int y) {system("cls");print();if (this->matrix[x][y] == 5) {game_over_print();return -1;}else if (this->matrix[x][y] == 0) {//如果这是个没有信息的区域,则要将一片连续的没有信息的区域都揭开uncover(x, y);this->matrix_probe[x][y] = 1;if (if_win()) {return 0;}return 1;}else {this->matrix_probe[x][y] = 1; //表示已经探索过了add_score();if (if_win()) {return 0;}return 1;}}
void MineCleaner::uncover(int x,int y) {st s = (stack *)malloc(sizeof(stack));init_stack(s);int b[2] = { x,y };push(s, x,y);//先将当前坐标入栈//循环效验当前坐标的上下左右坐标while (empty(s)) {//cout << "开始循环效验未探索区域"<<endl;//如果栈不空的话,就弹栈然后循环验证周围是否有为0的坐标pop(s, b);//出栈,这个时候b[0]为xb[1]为y//探索上面的格子if (this->matrix_probe[b[0] - 1][b[1]] == 0 && this->matrix[b[0] - 1][b[1]] == 0) {//cout << "探索上面的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[0] - 1 > 0) {//如果不是边上的坐标的话this->matrix_probe[b[0] - 1][b[1]] = 1;//表示探索过了push(s, b[0] - 1, b[1]);add_score();}}//探索下面的格子if (this->matrix_probe[b[0] + 1][b[1]] == 0 && this->matrix[b[0] + 1][b[1]] == 0) {//cout << "探索下面的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[0] + 1 < this->size-1) {//如果不是边上的坐标的话this->matrix_probe[b[0] + 1][b[1]] = 1;//表示探索过了push(s, b[0] + 1, b[1]);add_score();}}//探索左边的坐标if (this->matrix_probe[b[0]][b[1] - 1] == 0 && this->matrix[b[0]][b[1] - 1] == 0) {//cout << "探索左边的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[1] - 1 > 0) {this->matrix_probe[b[0]][b[1] - 1] = 1;//表示探索过了push(s, b[0], b[1] - 1);add_score();}}//探索右边的坐标if (this->matrix_probe[b[0]][b[1] + 1] == 0 && this->matrix[b[0]][b[1] + 1] == 0) {//cout << "探索右边的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[1] + 1 < this->size-1) {this->matrix_probe[b[0]][b[1] + 1] = 1;//表示探索过了push(s, b[0], b[1] + 1);add_score();}}}//经过循环之后就把连续的没有探索过并且没有坐标的点都探索了
}
void MineCleaner::game_over_print() {for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {this->matrix_probe[i][j] = 1;//全部变成已经探索过了}}system("cls");print();print_blank();cout << "游戏结束,总得分为:" << this->score;cout << endl;print_blank();
}
//判断是否赢了,赢了返回1,没有赢返回0
int MineCleaner::if_win() {//如果所有没有探索过的格子都是地雷的话就赢了for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] == 0) {if (this->matrix[i][j] == 5) {return 1;}}}}return 0;
}
void MineCleaner::win_print() {for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {this->matrix_probe[i][j] = 1;//全部变成已经探索过了}}system("cls");print_blank();cout << "victory!";print();
}
int MineCleaner::get_matrix(int x, int y) {return this->matrix[x][y];
}
int MineCleaner::get_matrix_probe(int x,int y) {return this->matrix_probe[x][y];
}

扫雷的界面:

自动扫雷ai:

概率计算算法描述:
    1.如果扫描到的格子已经是探索过的,就设置概率为0,并且假如周围有的格子没有被探索到,就用格子记录的数去除以还没有探索的格子数然后 加到那个格子是地雷的概率上
    2.如果扫描到的格子没有探索过,那么久跳过这个格子继续扫描别的格子

/*概率计算算法描述:1.如果扫描到的格子已经是探索过的,就设置概率为0,并且假如周围有的格子没有被探索到,就用格子记录的数去除以还没有探索的格子数加到那个格子是地雷的概率上2.如果扫描到的格子没有探索过,那么久跳过这个格子继续扫描别的格子
*/class robot {int matrix[MAXSIZE][MAXSIZE];int matrix_probe[MAXSIZE][MAXSIZE];int matrix_probability[MAXSIZE][MAXSIZE];   //记录每个格子确认为地雷的概率int size;int go[2];    //这是要走的下一个格子int number;   //记录走棋的步数
public:robot();void set_size(int size);  //获取棋盘的大小void set_matrix(int matrix[][MAXSIZE], int matrix_probe[][MAXSIZE]);  //获取棋盘和没有探索过的位置void calculate();  //计算每个区域是地雷的可能性,用浮点数表示void move();       //扫描概率表,将概率最大的格子的坐标返回void first_go();   //第一步随机给出一个坐标点int get_y();       //获取列数int get_x();       //获取行数void add_num();int get_num();void run();        //ai的主函数void print_pro();  //打印概率表void get_matrix();void get_matrix_probe();
};
robot::robot() {//初始化各个矩阵for (int i = 0; i < MAXSIZE; i++) {for (int j = 0; j < MAXSIZE; j++) {this->matrix[i][j] = 0;this->matrix_probe[i][j] = 0;this->matrix_probability[i][j] = 0;}}this->go[0] = 6; //一开始走(5,5)this->go[1] = 6;this->number = 0;
}
void robot::set_size(int size) {this->size = size;
}
void robot::set_matrix(int matrix[][MAXSIZE], int matrix_probe[][MAXSIZE]) {for (int i = 0; i < this->size; i++) {for (int j = 0; j < this->size; j++) {//获取棋盘信息和为探索区域的信息this->matrix[i][j] = matrix[i][j];this->matrix_probe[i][j] = matrix_probe[i][j];}}
}
void robot::calculate() {//先将所有区域的概率变成0for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {this->matrix_probability[i][j] = 0;}}for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] != 0) {//如果是探索过的格子int num=0;//记录四周没有被探索过的格子的数量//扫描四周没有被探索过的格子if (this->matrix_probe[i - 1][j] == 0) num++;if (this->matrix_probe[i + 1][j] == 0) num++;if (this->matrix_probe[i][j - 1] == 0) num++;if (this->matrix_probe[i][j + 1] == 0) num++;if (num != 0) {int pro = this->matrix[i][j] * 100 / num;//这是四周没有探索过的格子要加上的的概率//cout << "num=" << num << " pro=" << pro << endl;if (this->matrix_probe[i - 1][j] == 0) this->matrix_probability[i - 1][j] += pro;if (this->matrix_probe[i + 1][j] == 0) this->matrix_probability[i + 1][j] += pro;if (this->matrix_probe[i][j - 1] == 0) this->matrix_probability[i][j - 1] += pro;if (this->matrix_probe[i][j + 1] == 0) this->matrix_probability[i][j + 1] += pro;}}}}
}
void robot::add_num() {this->number++;
}
int robot::get_num() {return this->number;
}
void robot::move() {//如果存在已经探索并且周围地雷为0的点,那么优先探索它周围的点for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] == 1 && this->matrix[i][j] == 0) {if (this->matrix_probe[i - 1][j] == 0) {this->go[0] = i - 1;this->go[1] = j;return;}if (this->matrix_probe[i + 1][j] == 0) {this->go[0] = i + 1;this->go[1] = j;return;}if (this->matrix_probe[i][j - 1] == 0) {this->go[0] = i;this->go[1] = j - 1;return;}if (this->matrix_probe[i][j + 1] == 0) {this->go[0] = i;this->go[1] = j + 1;return;}}}}int pro=1000000;       //记录最大的概率/*for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] == 0 && this->matrix_probability[i][j] != 0) {pro = this->matrix_probability[i][j];break;}}}*/for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probability[i][j] < pro && this->matrix_probe[i][j] == 0 && this->matrix_probability[i][j]!=0) {//只要概率比较小并且是没有探索过的就更换目标//cout << "进入更换坐标的函数" << endl;this->go[0] = i;this->go[1] = j;pro = this->matrix_probability[i][j];}}}
}
void robot::first_go() {/*srand((unsigned)time(NULL));int x, y;x = rand() % (this->size - 1) + 1;y = rand() % (this->size - 1) + 1;while (x+2 >= this->size - 1 || y+1 >= this->size - 1) {x = rand() % (this->size - 1) + 1;y = rand() % (this->size - 1) + 1;}this->go[0] = x;this->go[1] = y;*/
}
int robot::get_y() {return this->go[1];
}
int robot::get_x() {return this->go[0];
}
void robot::run() {calculate();move();
}
void robot::print_pro() {for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {cout << this->matrix_probability[i][j]<<" ";}cout << endl;}
}
void robot::get_matrix() {cout << "棋盘表:" << endl;for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {cout << this->matrix[i][j];}cout << endl;}
}
void robot::get_matrix_probe() {cout << "未探索表:" << endl;for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {cout << this->matrix_probe[i][j];}cout << endl;}
}void get_matrix(MineCleaner m,int matrix[][MAXSIZE],int matrix_probe[][MAXSIZE]) {for (int i = 0; i < m.get_size(); i++) {for (int j = 0; j < m.get_size(); j++) {matrix[i][j] = m.get_matrix(i, j);matrix_probe[i][j] = m.get_matrix_probe(i, j);}}
}

最后的测试代码段:

int main()
{int num_of_victory=0;         //记录胜利的次数int victory[1000] = {0};    //记录胜利的盘数,胜利用1表示int number = 1000;int a[9] = {0};for (int j = 10; j < 100; j += 10) {num_of_victory = 0;for (int i = 0; i < number; i++) {MineCleaner m(10, j);robot r;int a;int matrix[MAXSIZE][MAXSIZE], matrix_probe[MAXSIZE][MAXSIZE];get_matrix(m, matrix, matrix_probe);r.set_matrix(matrix, matrix_probe);r.set_size(m.get_size());a = m.move(r.get_x(), r.get_y());while (a == 1) {r.add_num();//Sleep(500);//system("pause");get_matrix(m, matrix, matrix_probe);r.set_matrix(matrix, matrix_probe);cout << endl;m.print_blank();cout << "上一步的横纵坐标为:" << r.get_x() << " " << r.get_y() << endl;m.print_blank();cout << "当前步数为:" << r.get_num() << endl;r.run();//system("pause");a = m.move(r.get_x(), r.get_y());}//system("pause");if (a == 0) {num_of_victory++;victory[i]++;}}system("cls");cout << endl;cout << "胜利次数为:" << num_of_victory << endl;a[j / 10 - 1] = num_of_victory;//记录不同地雷密度的胜率}system("cls");for (int i = 0; i < 9 ; i++) {cout << "测试基数为1000,地雷密度为" << (i + 1) * 10 << "%的时候的胜利次数为:" << a[i] << endl;}
}

ai性能测试结果:

测试使用的是10*10的棋盘,除了地雷密度是0%和100%的情况,其他9种情况每一种都进行了1000次试验测试

测试结果数据源:

最后是完整的代码:

#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#define MAXSIZE 100   //棋盘的最大尺寸
#define OK 1
#define ERROR 0using namespace std;
//栈的数据结构,用于揭开迷雾
typedef struct stack {int coord[MAXSIZE][2];   //用于记录坐标数据int top,bottom;          //栈底和栈顶
}*st;
//初始化这个栈
void init_stack(st s) {for (int i = 0; i < MAXSIZE; i++) {for (int j = 0; j < 2; j++) {s->coord[i][j] = 0;}}s->top= -1;s->bottom = -1;
}
//判断这个栈是否为空,如果为空返回0,不为空返回1
int empty(st s) {if (s->top == s->bottom)//这是一个空栈return 0;else//这不是一个空栈return 1;
}
//入栈
int push(st s,int x,int y) {s->top++;if (s->top == MAXSIZE) {//栈满,不可以在添加元素了s->top--;cout << "栈已经满了,不可以再将数据入栈";return ERROR;}s->coord[s->top][0] = x;s->coord[s->top][1] = y;return OK;
}
//出栈
int pop(st s,int b[2]) {b[0] = s->coord[s->top][0]; b[1] = s->coord[s->top][1];s->top--;return OK;
}/*matrix记录地雷和周边信息,用0表示什么都没有,5表示地雷,1,2,3,4,表示周围地雷的数量matrix_probe记录这个地方是否被探索过,0表示没有被探索过,1表示探索过,2表示插旗,认为这里有地雷
*/class MineCleaner {int matrix[MAXSIZE][MAXSIZE];    //棋盘int matrix_probe[MAXSIZE][MAXSIZE]; //记录是否被探索过int size;            //用户指定的棋盘大小int density;         //用户指定的地雷的密度int score;           //游戏得分,每走一步如果没有踩到雷的话就加一分
public:MineCleaner();//构造函数MineCleaner(int size, int density);~MineCleaner();//析构函数void print_blank();   //打印空格,就是每行最开始的空格void print_bottom();  //打印每一行的底部void print_col_info();//答应列数void print_main_info(int x,int y);   //打印棋盘内容,也就是主要的信息void print();   //打印棋盘void init_chessboard();  //初始化棋盘,也就是埋雷void add_score();int get_x();            //获取横坐标int get_y();           //获取纵坐标int get_size();int move();         //游戏主界面int move(int x, int y);   //重载的AI移动void game_over_print();    //游戏结束的界面void uncover(int x,int y);      //揭开没有信息的区域int if_win();       //判断是否胜利void win_print();          //胜利界面int get_matrix(int x,int y);int get_matrix_probe(int x, int y);
};
//构造函数
MineCleaner::MineCleaner() {cout << "请问是否指定棋盘大小,如果不指定大小的话,那么棋盘将会是默认大小10*10?[y/n]  ";char a;cin >> a;//输入字符,以回车结束if (a == 'y' || a == 'Y') {//如果回答是yes的话cout << "请输入棋盘的大小:";int size;cin >> size;this->size = size + 2;   //这样子棋盘就是从1开始到size-2结束的区域}else {this->size = 12;  //从1开始到10结束的区域}system("cls");cout << "请问是否指定棋盘的地雷密度,如果不指定的话那么将会是默认地雷密度30%?[y/n]  ";cin >> a;//输入字符,以回车结束if (a == 'y' || a == 'Y') {//如果指定地雷密度的话cout << "请输入0-100(不包括0和100)之间的地雷密度数,这将影响游戏的难度:";int density;cin >> density;while (density >= 100 || density <= 0) {cout << "输入的数据不正确,请重新输入:";cin >> density;}this->density = density;}else {this->density = 30;   //默认的地雷密度为30%}for (int i = 0; i < size; i++) {for (int j = 0; j < size; j++) {this->matrix[i][j] = 0;  //初始化棋盘this->matrix_probe[i][j] = 0;//一开始都是初始化没有被探索过}}for (int j = 0; j < this->size; j++) {//将边框变为可见,为ai做准备this->matrix_probe[0][j] = 1;this->matrix_probe[this->size - 1][j] = 1;this->matrix_probe[j][this->size - 1] = 1;this->matrix_probe[j][0] = 1;}system("cls");this->score = 0;//初始化分数init_chessboard();//初始化棋盘信息
}
MineCleaner::MineCleaner(int size, int density) {this->size = size + 2;this->density = density;for (int i = 0; i < this->size; i++) {for (int j = 0; j < this->size; j++) {this->matrix[i][j] = 0;  //初始化棋盘this->matrix_probe[i][j] = 0;//一开始都是初始化没有被探索过}}for (int j = 0; j < this->size; j++) {//将边框变为可见,为ai做准备this->matrix_probe[0][j] = 1;this->matrix_probe[this->size - 1][j] = 1;this->matrix_probe[j][this->size - 1] = 1;this->matrix_probe[j][0] = 1;}//system("cls");this->score = 0;//初始化分数init_chessboard();//初始化棋盘信息
}
MineCleaner::~MineCleaner(){}
void MineCleaner::add_score() {this->score++;
}
void MineCleaner::print_blank() {cout << "                      ";
}
void MineCleaner::print_bottom() {cout << endl;print_blank();cout << "    ";for (int i = 1; i < this->size - 1; i++) {cout << " ---";}cout << endl;
}
void MineCleaner::print_col_info() {print_blank();cout << "     ";for (int i = 1; i < this->size - 1; i++) {cout <<" "<< i << "  ";}
}
void MineCleaner::print_main_info(int x,int y) {//先查看matrix_probe数组,如果是0表示没有翻开,什么都不显示,如果是1就显示内容//如果是2就插旗子表示有可能有地雷if (this->matrix_probe[x][y] == 0) {//这表示没有翻开格子cout << "   |";}else if (this->matrix_probe[x][y] == 2) {//这表示插旗判断可能有地雷cout << " @ |";}else {//如果翻开了就显示这个格子本来的信息if (this->matrix[x][y] == 5) {cout << " * |";}else if (this->matrix[x][y] == 0) {cout << " 0 |";}else {cout << " " << this->matrix[x][y] << " |";}}
}
//打印棋盘,调试成功
void MineCleaner::print() {cout << endl;cout << endl;cout << endl;print_col_info();print_bottom();for (int i = 1; i < this->size - 1; i++) {//行信息,每一行开始的时候都要空行并且打印行标if (i < 10) {print_blank();cout << i << "   |";}else {print_blank();cout << i << "  |";}for (int j = 1; j < this->size - 1; j++) {//列信息print_main_info(i,j);}cout <<"  "<< i;//结束的时候打印行信息print_bottom();}//最后再打印列信息print_col_info();cout << endl;print_blank();cout << "当前得分是:" <<this->score;cout << endl;
}
int MineCleaner::get_size() {return this->size;
}
//初始化棋盘信息
void MineCleaner::init_chessboard() {int num_of_total = (this->size-2)*(this->size-2);   //这是显示出来的棋盘的总数量float des = (float)this->density / 100;int x, y;int num_of_mine = des * num_of_total;  //这是地雷的总数//埋雷while (num_of_mine != 0) {//如果地雷数量不为0的话就要继续埋雷srand((unsigned)time(NULL));x = rand() % (this->size - 1) + 1;  //范围是从1-(size-1)y = rand() % (this->size - 1) + 1;while (this->matrix[x][y] == 5 || x == this->size-1 || y==this->size-1) {//如果这个地方已经有雷了,就重新找一个地方埋雷x = rand() % (this->size - 1) + 1;  //范围是从1-(size-1)y = rand() % (this->size - 1) + 1;}this->matrix[x][y] = 5;    //埋雷num_of_mine--;}//接下来要循环遍历整个棋盘的每个坐标,写下雷周围的数字for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix[i][j] != 5) {//如果这个坐标不是雷区才进行判断if (this->matrix[i - 1][j] == 5) this->matrix[i][j]++;if (this->matrix[i + 1][j] == 5) this->matrix[i][j]++;if (this->matrix[i][j - 1] == 5) this->matrix[i][j]++;if (this->matrix[i][j + 1] == 5) this->matrix[i][j]++;}}}
}
int MineCleaner::get_x() {print_blank();cout << "请输入要探索的横坐标(行):";int x;cin >> x;while (x < 0 || x > this->size - 1) {print_blank();cout << "输入的坐标超出允许的范围,请重新输入:";cin >> x;}return x;
}
int MineCleaner::get_y() {print_blank();cout << "请输入要探索的纵坐标(列):";int y;cin >> y;while (y < 0 || y > this->size - 1) {print_blank();cout << "输入的坐标超出允许的范围,请重新输入:";cin >> y;}return y;
}
//走棋
int MineCleaner::move() {//先接收要走棋的坐标位置//system("cls");print();int x, y;x = get_x();y = get_y();while (this->matrix_probe[x][y] == 1) {print_blank();cout << "该坐标已被探索过,请重新输入";x = get_x();y = get_y();}if (this->matrix[x][y] == 5) {game_over_print();return 0;}else if (this->matrix[x][y] == 0) {//如果这是个没有信息的区域,则要将一片连续的没有信息的区域都揭开uncover(x,y);if (if_win()) {return 0;}return 1;}else {this->matrix_probe[x][y] = 1; //表示已经探索过了add_score();return 1;}
}
//0是胜利,-1是失败
int MineCleaner::move(int x, int y) {system("cls");print();if (this->matrix[x][y] == 5) {game_over_print();return -1;}else if (this->matrix[x][y] == 0) {//如果这是个没有信息的区域,则要将一片连续的没有信息的区域都揭开uncover(x, y);this->matrix_probe[x][y] = 1;if (if_win()) {return 0;}return 1;}else {this->matrix_probe[x][y] = 1; //表示已经探索过了add_score();if (if_win()) {return 0;}return 1;}}
void MineCleaner::uncover(int x,int y) {st s = (stack *)malloc(sizeof(stack));init_stack(s);int b[2] = { x,y };push(s, x,y);//先将当前坐标入栈//循环效验当前坐标的上下左右坐标while (empty(s)) {//cout << "开始循环效验未探索区域"<<endl;//如果栈不空的话,就弹栈然后循环验证周围是否有为0的坐标pop(s, b);//出栈,这个时候b[0]为xb[1]为y//探索上面的格子if (this->matrix_probe[b[0] - 1][b[1]] == 0 && this->matrix[b[0] - 1][b[1]] == 0) {//cout << "探索上面的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[0] - 1 > 0) {//如果不是边上的坐标的话this->matrix_probe[b[0] - 1][b[1]] = 1;//表示探索过了push(s, b[0] - 1, b[1]);add_score();}}//探索下面的格子if (this->matrix_probe[b[0] + 1][b[1]] == 0 && this->matrix[b[0] + 1][b[1]] == 0) {//cout << "探索下面的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[0] + 1 < this->size-1) {//如果不是边上的坐标的话this->matrix_probe[b[0] + 1][b[1]] = 1;//表示探索过了push(s, b[0] + 1, b[1]);add_score();}}//探索左边的坐标if (this->matrix_probe[b[0]][b[1] - 1] == 0 && this->matrix[b[0]][b[1] - 1] == 0) {//cout << "探索左边的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[1] - 1 > 0) {this->matrix_probe[b[0]][b[1] - 1] = 1;//表示探索过了push(s, b[0], b[1] - 1);add_score();}}//探索右边的坐标if (this->matrix_probe[b[0]][b[1] + 1] == 0 && this->matrix[b[0]][b[1] + 1] == 0) {//cout << "探索右边的格子,这个格子也是0" << endl;//如果没有探索并且是没有信息的坐标的话if (b[1] + 1 < this->size-1) {this->matrix_probe[b[0]][b[1] + 1] = 1;//表示探索过了push(s, b[0], b[1] + 1);add_score();}}}//经过循环之后就把连续的没有探索过并且没有坐标的点都探索了
}
void MineCleaner::game_over_print() {for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {this->matrix_probe[i][j] = 1;//全部变成已经探索过了}}system("cls");print();print_blank();cout << "游戏结束,总得分为:" << this->score;cout << endl;print_blank();
}
//判断是否赢了,赢了返回1,没有赢返回0
int MineCleaner::if_win() {//如果所有没有探索过的格子都是地雷的话就赢了for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] == 0) {if (this->matrix[i][j] == 5) {return 1;}}}}return 0;
}
void MineCleaner::win_print() {for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {this->matrix_probe[i][j] = 1;//全部变成已经探索过了}}system("cls");print_blank();cout << "victory!";print();
}
int MineCleaner::get_matrix(int x, int y) {return this->matrix[x][y];
}
int MineCleaner::get_matrix_probe(int x,int y) {return this->matrix_probe[x][y];
}/*概率计算算法描述:1.如果扫描到的格子已经是探索过的,就设置概率为0,并且假如周围有的格子没有被探索到,就用格子记录的数去除以还没有探索的格子数加到那个格子是地雷的概率上2.如果扫描到的格子没有探索过,那么久跳过这个格子继续扫描别的格子
*/class robot {int matrix[MAXSIZE][MAXSIZE];int matrix_probe[MAXSIZE][MAXSIZE];int matrix_probability[MAXSIZE][MAXSIZE];   //记录每个格子确认为地雷的概率int size;int go[2];    //这是要走的下一个格子int number;   //记录走棋的步数
public:robot();void set_size(int size);  //获取棋盘的大小void set_matrix(int matrix[][MAXSIZE], int matrix_probe[][MAXSIZE]);  //获取棋盘和没有探索过的位置void calculate();  //计算每个区域是地雷的可能性,用浮点数表示void move();       //扫描概率表,将概率最大的格子的坐标返回void first_go();   //第一步随机给出一个坐标点int get_y();       //获取列数int get_x();       //获取行数void add_num();int get_num();void run();        //ai的主函数void print_pro();  //打印概率表void get_matrix();void get_matrix_probe();
};
robot::robot() {//初始化各个矩阵for (int i = 0; i < MAXSIZE; i++) {for (int j = 0; j < MAXSIZE; j++) {this->matrix[i][j] = 0;this->matrix_probe[i][j] = 0;this->matrix_probability[i][j] = 0;}}this->go[0] = 6; //一开始走(5,5)this->go[1] = 6;this->number = 0;
}
void robot::set_size(int size) {this->size = size;
}
void robot::set_matrix(int matrix[][MAXSIZE], int matrix_probe[][MAXSIZE]) {for (int i = 0; i < this->size; i++) {for (int j = 0; j < this->size; j++) {//获取棋盘信息和为探索区域的信息this->matrix[i][j] = matrix[i][j];this->matrix_probe[i][j] = matrix_probe[i][j];}}
}
void robot::calculate() {//先将所有区域的概率变成0for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {this->matrix_probability[i][j] = 0;}}for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] != 0) {//如果是探索过的格子int num=0;//记录四周没有被探索过的格子的数量//扫描四周没有被探索过的格子if (this->matrix_probe[i - 1][j] == 0) num++;if (this->matrix_probe[i + 1][j] == 0) num++;if (this->matrix_probe[i][j - 1] == 0) num++;if (this->matrix_probe[i][j + 1] == 0) num++;if (num != 0) {int pro = this->matrix[i][j] * 100 / num;//这是四周没有探索过的格子要加上的的概率//cout << "num=" << num << " pro=" << pro << endl;if (this->matrix_probe[i - 1][j] == 0) this->matrix_probability[i - 1][j] += pro;if (this->matrix_probe[i + 1][j] == 0) this->matrix_probability[i + 1][j] += pro;if (this->matrix_probe[i][j - 1] == 0) this->matrix_probability[i][j - 1] += pro;if (this->matrix_probe[i][j + 1] == 0) this->matrix_probability[i][j + 1] += pro;}}}}
}
void robot::add_num() {this->number++;
}
int robot::get_num() {return this->number;
}
void robot::move() {//如果存在已经探索并且周围地雷为0的点,那么优先探索它周围的点for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] == 1 && this->matrix[i][j] == 0) {if (this->matrix_probe[i - 1][j] == 0) {this->go[0] = i - 1;this->go[1] = j;return;}if (this->matrix_probe[i + 1][j] == 0) {this->go[0] = i + 1;this->go[1] = j;return;}if (this->matrix_probe[i][j - 1] == 0) {this->go[0] = i;this->go[1] = j - 1;return;}if (this->matrix_probe[i][j + 1] == 0) {this->go[0] = i;this->go[1] = j + 1;return;}}}}int pro=1000000;       //记录最大的概率/*for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probe[i][j] == 0 && this->matrix_probability[i][j] != 0) {pro = this->matrix_probability[i][j];break;}}}*/for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {if (this->matrix_probability[i][j] < pro && this->matrix_probe[i][j] == 0 && this->matrix_probability[i][j]!=0) {//只要概率比较小并且是没有探索过的就更换目标//cout << "进入更换坐标的函数" << endl;this->go[0] = i;this->go[1] = j;pro = this->matrix_probability[i][j];}}}
}
void robot::first_go() {/*srand((unsigned)time(NULL));int x, y;x = rand() % (this->size - 1) + 1;y = rand() % (this->size - 1) + 1;while (x+2 >= this->size - 1 || y+1 >= this->size - 1) {x = rand() % (this->size - 1) + 1;y = rand() % (this->size - 1) + 1;}this->go[0] = x;this->go[1] = y;*/
}
int robot::get_y() {return this->go[1];
}
int robot::get_x() {return this->go[0];
}
void robot::run() {calculate();move();
}
void robot::print_pro() {for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {cout << this->matrix_probability[i][j]<<" ";}cout << endl;}
}
void robot::get_matrix() {cout << "棋盘表:" << endl;for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {cout << this->matrix[i][j];}cout << endl;}
}
void robot::get_matrix_probe() {cout << "未探索表:" << endl;for (int i = 1; i < this->size - 1; i++) {for (int j = 1; j < this->size - 1; j++) {cout << this->matrix_probe[i][j];}cout << endl;}
}void get_matrix(MineCleaner m,int matrix[][MAXSIZE],int matrix_probe[][MAXSIZE]) {for (int i = 0; i < m.get_size(); i++) {for (int j = 0; j < m.get_size(); j++) {matrix[i][j] = m.get_matrix(i, j);matrix_probe[i][j] = m.get_matrix_probe(i, j);}}
}int main()
{int num_of_victory=0;         //记录胜利的次数int victory[1000] = {0};    //记录胜利的盘数,胜利用1表示int number = 1000;int a[9] = {0};for (int j = 10; j < 100; j += 10) {num_of_victory = 0;for (int i = 0; i < number; i++) {MineCleaner m(10, j);robot r;int a;int matrix[MAXSIZE][MAXSIZE], matrix_probe[MAXSIZE][MAXSIZE];get_matrix(m, matrix, matrix_probe);r.set_matrix(matrix, matrix_probe);r.set_size(m.get_size());a = m.move(r.get_x(), r.get_y());while (a == 1) {r.add_num();//Sleep(500);//system("pause");get_matrix(m, matrix, matrix_probe);r.set_matrix(matrix, matrix_probe);cout << endl;m.print_blank();cout << "上一步的横纵坐标为:" << r.get_x() << " " << r.get_y() << endl;m.print_blank();cout << "当前步数为:" << r.get_num() << endl;r.run();//system("pause");a = m.move(r.get_x(), r.get_y());}//system("pause");if (a == 0) {num_of_victory++;victory[i]++;}}system("cls");cout << endl;cout << "胜利次数为:" << num_of_victory << endl;a[j / 10 - 1] = num_of_victory;//记录不同地雷密度的胜率}system("cls");for (int i = 0; i < 9 ; i++) {cout << "测试基数为1000,地雷密度为" << (i + 1) * 10 << "%的时候的胜利次数为:" << a[i] << endl;}
}

c++扫雷以及自动扫雷ai性能测试相关推荐

  1. python自动扫雷_Python自动扫雷实现方法

    Python自动扫雷实现方法 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  Python自动扫雷实现方法.txt ] (友情提示:右键点上行txt文档名-> ...

  2. python扫雷_自动扫雷 Python语言

    本文主要向大家介绍了自动扫雷 Python语言,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. 自动扫雷一般分为两种,一种是读取内存数据,而另一种是通过分析图片获得数据,并通过模拟 ...

  3. matlab 自动扫雷,MATLAB自动扫雷(2)——排雷插旗

    如果周围8个方块和当中数字判断周围有空白方块 % 点击白块 function click_blank() global map global blocks_x global blocks_y glob ...

  4. Java 实现扫雷与高胜率低耗时自动扫雷 AI (下)

    上一篇博客介绍了本项目总体情况, 这一篇来介绍一下我实现的自动扫雷 AI 算法. 本 AI 胜率比网上最高胜率的 AI 差 0.5% 左右. 不过本 AI 也不是没有优势, 它运算速度很快 (强行有优 ...

  5. 算法实现自动扫雷游戏

    算法实现自动扫雷游戏 1.游戏的构思 2.算法伪代码的实现 3.算法的实现 1.首先需要建立起游戏的整个框架(棋盘的绘制,地雷的生成,基本函数的实现等) 2.构思AI算法的大概样貌(先尝试写伪码) v ...

  6. 破世界纪录了0.74秒!用Python实现自动扫雷!

    来源丨https://zhuanlan.zhihu.com/p/35755039 大家好,我是菜鸟哥~ 用Python+OpenCV实现了自动扫雷,突破世界记录,我们先来看一下效果吧. 中级 - 0. ...

  7. unity应用实例——扫雷游戏(自动扫雷、人工布雷)

    最近用Unity做了一个简单的扫雷小游戏,可以实现电脑自动扫雷.人工布雷等功能,效果图如下. 在游戏的任何时间按下T键后,电脑会自动进行游戏,直到游戏结束.按下B键后可以通过鼠标点击埋雷. 项目一共有 ...

  8. 国庆放假,来40秒!用Python实现自动扫雷,挑战世界纪录!

    来源:zhuanlan.zhihu.com/p/35755039 作者:Artrix 项目:github.com/ArtrixTech/BoomMine 人生苦短,快学Python!今天文末送福利! ...

  9. 破纪录了!用 Python 实现自动扫雷!

    用Python+OpenCV实现了自动扫雷,突破世界记录,我们先来看一下效果吧. 中级 - 0.74秒 3BV/S=60.81 相信许多人很早就知道有扫雷这么一款经典的游(显卡测试)戏(软件),更是有 ...

最新文章

  1. 使用Windows8开发Metro风格应用三
  2. Delphi中Indy 10的安装和老版本的卸载
  3. 怎样把SharePoint中文备份恢复到英文版,修改sharepoint站点语言
  4. 指代消解论文阅读(一): END-TO-END NEURAL COREFERENCE RESOLUTION REVISITED: A SIMPLE YETEFFECTIVE BASELINE
  5. 随机梯度下降(Stochastic gradient descent)和 批量梯度下降(Batch gradient descent )的公式对比、实现对比
  6. 手机PIN锁死让输入PUK解决方案
  7. 生产订单结算KKS1常见错误
  8. windows相关知识点分析
  9. DevOps之持续集成SonarQube代码质量扫描
  10. 【转】医学影像处理相关知识整理(一)
  11. linux文件属性是什么意思,Linux文件属性
  12. sublime 插件安装;sublime的 babel、sublime-jsfmt插件
  13. hadoop中mapreduce参数优化
  14. Unity学习笔记:unity脚本常用API
  15. bootstrp_组件
  16. readelf命令使用
  17. 《Unity3D脚本编程与游戏开发》学习Day one
  18. TOPOLOGY ADAPTIVE GRAPH CONVOLUTIONAL NETWORKS论文笔记(TAGConv)
  19. java 内存很高_Java服务器内存和CPU占用过高的原因
  20. js使用rgb和argb

热门文章

  1. Altium Designer 21 原理图编号、PCB封装名称的添加与管理,原理图编译、检查、输出BOM表及PDF打印。
  2. Another Redis使用手册
  3. 快播 QvodTerminal.exe 应用程序错误排查
  4. 微信红包违反央行规定? 回应称使用财付通支付不违规
  5. vscode设置全英文的方法
  6. 局域网络故障---能ping通网址但不能访问网页
  7. c语言卡拉兹猜想,16岁西班牙少年夺ATP正赛首胜 称纳达尔是其偶像
  8. 吐槽memoQ | 实时预览能不能更强大?
  9. lambda表达式之美
  10. 联合国“全球脉动”计划 《大数据开发:机遇与挑战》