同化棋


#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<stdio.h>
using namespace std;




int chess[8][8] = { 0 };//0为空,1为白,-1为黑
double weight[8][8] = { { 1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5, },
{ 1.5,1,0.965051,0.849347,0.803681,0.779659,0.789668,1, },
{ 1.5,0.965051,0.87366,0.835621,0.743914,0.715635,0.719026,0.789668, },
{ 1.5,0.849347,0.835621,0.788361,0.701912,0.677423,0.715635,0.779659, },
{ 1.5,0.803681,0.743914,0.701912,0.70752,0.701912,0.743914,0.803681, },
{ 1.5,0.779659,0.715635,0.677423,0.701912,0.788361,0.835621,0.849347, },
{ 1.5,0.789668,0.719026,0.715635,0.743914,0.835621,0.87366,0.965051, },
{ 1.5,1,0.789668,0.779659,0.803681,0.849347,0.965051,1, } };
int Human_color;//1为白,-1为黑
int pastchess[8][8] = { 0 };
int botx1 = 0, boty1 = 0, botx = 0, boty = 0;
int blackscore = 0, whitescore = 0;//黑白色分数
double eva_max;
double alpha, beta = 1000;
int pastflag = 0;//是否可以悔棋
struct move {
int ux;
int uy;
int x;
int y;
int chess[8][8] = { 0 };
}moves[6];


double AI(int generation, int color);




int printboard() {
blackscore = 0, whitescore = 0;
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (chess[i][j] == -1)blackscore++;
else if (chess[i][j] == 1)whitescore++;
}
}
system("cls");
cout << "     欢迎来到人工智障同化棋" << endl;
cout << "      ●黑 :○白 = " << blackscore << " : " << whitescore << endl;
cout << "   1   2   3   4   5   6   7   X" << endl;
cout << " ╔═╦═╦═╦═╦═╦═╦═╗" << endl;
for (int i = 1; i <= 7; i++) {
cout << i << "║";
for (int j = 1; j <= 7; j++) {
switch (chess[j][i]) {
case 0:cout << "  "; break;
case 1:cout << "○"; break;
case -1:cout << "●"; break;
}
cout << "║";
}
if (i <= 6) {
cout << endl << " ╠═╬═╬═╬═╬═╬═╬═╣";
if (i == 2)cout << "    作为一名魔法师,你需要了解以下魔法:";
else if (i == 3)cout << "             存档请输入8";
else if (i == 4 && pastflag != 0)cout << "             悔棋请输入9";
else if (i == 5)cout << "             退出请输入0";
cout << endl;
}
}
cout << endl << " ╚═╩═╩═╩═╩═╩═╩═╝" << endl;
cout << 'Y' << endl << endl;
return 0;
}




int check_move2(int x, int y) {
for (int i = x - 2; i <= x + 2; i++) {
for (int j = y - 2; j <= y + 2; j++) {
if (i == x&&j == y) continue;
if (i < 1 || i>7 || j < 1 || j>7)continue;
if (chess[i][j] == 0)return 1;
}
}
return 0;
}


int change_board(int ux, int uy, int x, int y, int color, int chess[8][8]) {
if (ux - x > 1 || ux - x < -1 || uy - y>1 || uy - y < -1) {
chess[x][y] = 0;
chess[ux][uy] = color;
for (int i = ux - 1; i <= ux + 1; i++) {
for (int j = uy - 1; j <= uy + 1; j++) {
if (i < 1 || i>7 || j < 1 || j>7)continue;
if (chess[i][j] == -1 * color) {
chess[i][j] = color;
}
}
}
}
else {
chess[ux][uy] = color;
if (color == 1)whitescore++;
else blackscore++;
for (int i = ux - 1; i <= ux + 1; i++) {
for (int j = uy - 1; j <= uy + 1; j++) {
if (i < 1 || i > 7 || j < 1 || j > 7)continue;
if (chess[i][j] == -1 * color) {
chess[i][j] = color;
blackscore -= color;
whitescore += color;
}
}
}
}
return 0;
}


int check_player(int color) {
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (chess[i][j] != color)continue;
if (check_move2(i, j))return 1;
}
}
return 0;
}


int writein_save() {
FILE*save;
fopen_s(&save, "Text.txt", "w");
fprintf_s(save, "%d %d %d ", Human_color, blackscore, whitescore);
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
fprintf(save, "%d ", chess[i][j]);
}
}
fclose(save);
return 0;
}


int read_save() {
FILE*save;
fopen_s(&save, "Text.txt", "r");
fscanf_s(save, "%d %d %d ", &Human_color, &blackscore, &whitescore);
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
fscanf_s(save, "%d", &chess[i][j]);
}
}
cout << chess[1][2];
fclose(save);
return 1;
}
//决策部分
//比较数组,相同返回1
int compare(int array1[8][8], int array2[8][8]) {
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (array1[i][j] != array2[i][j])return 0;
}
}
return 1;
}
//将2的值赋给1
int copy(int array1[8][8], int array2[8][8]) {
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
array1[i][j] = array2[i][j];
}
}
return 0;
}
//对于color颜色,评估当前棋局
double evaluation(int array1[8][8], int color) {
double total = 0;
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (array1[i][j] == -1 * color) total-=weight[i][j];
else if (array1[i][j] == color)total+=weight[i][j];
}
}
return total;
}


int bot_go(int color) {
double max = -50;
alpha = -50;
beta = 50;
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (chess[i][j] != color)continue;
for (int k = i - 2; k <= i + 2; k++) {
for (int l = j - 2; l <= j + 2; l++) {
if (k < 1 || k>7 || l < 1 || l>7 ||chess[k][l] != 0)continue;
copy(moves[1].chess, chess);
change_board(k, l, i, j, color, moves[1].chess);
if (compare(moves[1].chess, pastchess))continue;
if (evaluation(moves[1].chess, color) + 14 < max)continue;
double m = AI(1, -1 * color);
if (max< m) {
botx1 = k; boty1 = l; botx = i; boty = j; max= m;
}


}
}
}
}
return 0;
}
double AI(int generation,int color) {
if (generation == 2) {
double max=-50;
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (moves[generation].chess[i][j] != color)continue;
for (int k = i - 2; k <= i + 2; k++) {
for (int l = j - 2; l <= j + 2; l++) {
if (k < 1 || k>7 || l < 1 || l>7|| moves[generation].chess[k][l] != 0)continue;
copy(moves[generation + 1].chess, moves[generation].chess);
change_board(k, l, i, j, color, moves[generation + 1].chess);
double m = evaluation(moves[generation + 1].chess, color);
if (max< m)max = m;
}
}
}
}
return max;
}
else if (generation % 2 == 0) {
double max = -50;
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (moves[generation].chess[i][j] != color)continue;
for (int k = i - 2; k <= i + 2; k++) {
for (int l = j - 2; l <= j + 2; l++) {
if (k < 1 || k>7 || l < 1 || l>7|| moves[generation].chess[k][l] != 0)continue;
copy(moves[generation + 1].chess, moves[generation].chess);
change_board(k, l, i, j, color, moves[generation + 1].chess);
if (evaluation(moves[generation + 1].chess, color) + 7 < max)continue;;
double m = AI(generation + 1, -1 * color);
if (max < m)max = m;
}
}
}
}
return max;
}
else {
double min = 50;
for (int i = 1; i <= 7; i++) {
for (int j = 1; j <= 7; j++) {
if (moves[generation].chess[i][j] != color)continue;
for (int k = i - 2; k <= i + 2; k++) {
for (int l = j - 2; l <= j + 2; l++) {
if (k < 1 || k>7 || l < 1 || l>7|| moves[generation].chess[k][l]!=0)continue;
copy(moves[generation + 1].chess, moves[generation].chess);
change_board(k, l, i, j, color, moves[generation + 1].chess);
if (evaluation(moves[generation + 1].chess, -1 * color) - 7 * (5 - generation) / 2 > min)continue;
double m = AI(generation + 1, -1*color);
if (min> m)min = m;
}
}
}
}
return min;
}
}


int human_go() {
int x, y, x1, y1;
printboard();
if (botx1 != 0) cout << "人工智障上一步从(" << botx << "," << boty << ")移动到了(" << botx1 << "," << boty1 << "),该你了!" << endl << endl;
while (1) {
int regretflag = 0;
while (1) {
cout << "请选择行动的棋子" << endl;
while (1) {
char Choice[200] = { 0 };
cout << "请输入横坐标x:";
cin.getline(Choice, 199);
if (Choice[0] >= '1' && Choice[0] <= '7'&&strlen(Choice) == 1) {
x = Choice[0] - '0';
break;
}
else if (Choice[0] == '8'&&strlen(Choice) == 1) {
writein_save();
cout << endl << "存档成功" << endl;
continue;
}
else if (Choice[0] == '0'&&strlen(Choice) == 1) {
return 1;
}
else if (Choice[0] == '9'&&strlen(Choice) == 1) {
copy(chess, pastchess);
pastflag = 0;
printboard();
continue;
}
cout << "emmm……请输入一个1到7之间的整数~" << endl << endl;
}
pastflag = 0;
while (1) {
char Choice[200] = { 0 };
cout << "请输入纵坐标y:";
cin.getline(Choice, 199);
if (Choice[0] >= '1' && Choice[0] <= '7'&&strlen(Choice) == 1) {
y = Choice[0] - '0';
break;
}
else if (Choice[0] == '8'&&strlen(Choice) == 1) {
writein_save();
cout << endl << "存档成功" << endl;
continue;
}
else if (Choice[0] == '0'&&strlen(Choice) == 1) {
return 1;
}
else if (Choice[0] == '9'&&strlen(Choice) == 1) {
regretflag = 1;
break;
}
cout << "emmm……请输入一个1到7之间的整数" << endl << endl;
}
if (regretflag == 1) {
regretflag = 0;
copy(chess, pastchess);
pastflag = 0;
printboard();
continue;
}
cout << endl;
if (chess[x][y] != Human_color) {
cout << "唉,这里没有你的棋子,请重新选择" << endl << endl;
continue;
}
if (check_move2(x, y) == 1)break;
else cout << "嘿嘿嘿,抱歉,这个棋子不能行动,请重新选择" << endl << endl;
}
cout << "请选择移动到何位置" << endl;
while (1) {
char Choice[200] = { 0 };
cout << "请输入横坐标x:";
cin.getline(Choice, 199);
if (Choice[0] >= '1' && Choice[0] <= '7' && strlen(Choice) == 1) {
x1 = Choice[0] - '0';
break;
}
else if (Choice[0] == '9'&&strlen(Choice) == 1) {
regretflag = 1;
break;
}
cout << "请输入一个1到7之间的整数" << endl;
}
if (regretflag == 1) {
regretflag = 0;
copy(chess, pastchess);
pastflag = 0;
printboard();
continue;
}
while (1) {
char Choice[200] = { 0 };
cout << "请输入纵坐标y:";
cin.getline(Choice, 199);
if (Choice[0] >= '1' && Choice[0] <= '7'&&strlen(Choice) == 1) {
y1 = Choice[0] - '0';
break;
}
else if (Choice[0] == '9'&&strlen(Choice) == 1) {
regretflag = 1;
break;
}
cout << "请输入一个1到7之间的整数" << endl;
}
if (regretflag == 1) {
regretflag = 0;
copy(chess, pastchess);
pastflag = 0;
printboard();
continue;
}
if (x1 - x > 2 || x1 - x < -2 || y1 - y>2 || y1 - y < -2)cout << "请在选定棋子周围5*5的方格内落子" << endl << endl;
else if (chess[x1][y1] != 0)cout << "抱歉,这里已经有棋子了" << endl << endl;
else {
copy(pastchess, chess);
pastflag++;
change_board(x1, y1, x, y, Human_color, chess);
break;
}
}
return 0;
}


int main() {
cout << pastchess;
//初始界面选择部分,忽略空格输入,若输入错误重新输入
while (1) {
pastflag = 0;
int firstgo;
system("cls");
cout << "欢迎来到同化棋!" << endl;
while (1) {
char ChoiceOfStart[100] = { 0 };
int i = 0;
cout << "1.开始新游戏" << endl << "2.读取存档" << endl << "3.退出" << endl;
cin.getline(ChoiceOfStart, 99);
while (ChoiceOfStart[i++] == ' ');
i--;
//若选1
if (ChoiceOfStart[i] == '1') {
memset(chess, 0, sizeof(chess));
chess[1][1] = -1; chess[7][7] = -1;
chess[1][7] = 1; chess[7][1] = 1;
blackscore = 2;
whitescore = 2;
cout << "魔法师,你将与邪恶的人工智障为了人类的存亡进行同化棋对决!别问我为什么要用同化棋就行" << endl << endl << "现在,请选择执棋颜色:" << endl << "●黑色:1          ○白色:2" << endl;
while (1) {
char Choice[100] = { 0 };
cin.getline(Choice, 99);
if (Choice[0] == '1'&&strlen(Choice) == 1) {
Human_color = -1;
firstgo = 1;
break;
}
else if (Choice[0] == '2'&&strlen(Choice) == 1) {
Human_color = 1;
firstgo = 0;
break;
}
cout << "请输入1或2" << endl;
}
break;
}


//若选2
else if (ChoiceOfStart[i] == '2') {
read_save();
pastflag = 0;
botx1 = 0;
printboard();
firstgo = 1;
break;
}


//若选3
else if (ChoiceOfStart[i] == '3') {
cout << "谢谢游玩~" << endl;
system("pause");
return 0;
}
cout << "请输入1,2,3中的一个数" << endl;
}


if (firstgo) {
int a, b;
while (1) {
a = check_player(Human_color);
b = check_player(-1 * Human_color);
if (a == 0 && b == 0) {
printboard();
if (blackscore > whitescore)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else if (blackscore < whitescore)cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else if (a == 0) {
printboard();
if (blackscore>24)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else if (b == 0) {
printboard();
if (whitescore<25)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else {
if (human_go())break;
}
a = check_player(Human_color);
b = check_player(-1 * Human_color);
if (a == 0 && b == 0) {
printboard();
if (blackscore > whitescore)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else if (blackscore < whitescore)cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else if (a == 0) {
printboard();
if (blackscore>24)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else if (b == 0) {
printboard();
if (whitescore<25)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else{
bot_go(-1*Human_color);
change_board(botx1, boty1, botx, boty, -1 * Human_color, chess);
}
}
}
else {
int a, b;
while (1) {
a = check_player(Human_color);
b = check_player(-1 * Human_color);
if (a == 0 && b == 0) {
printboard();
if (blackscore < whitescore)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else if (a == 0) {
printboard();
if (whitescore>24)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}


else if (b == 0) {
printboard();
if (blackscore<25)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}


else {
bot_go(-1*Human_color);
change_board(botx1, boty1, botx, boty, -1 * Human_color, chess);
}
a = check_player(Human_color);
b = check_player(-1 * Human_color);
if (a == 0 && b == 0) {
printboard();
if (blackscore < whitescore)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else if (a == 0) {
printboard();
if (whitescore>24)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}


else if (b == 0) {
printboard();
if (blackscore<25)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;
else cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;
break;
}
else{
if (human_go())break;
}
}
}
while (1) {
cout << "重新开始游戏请按1,退出请按0" << endl;
char Choice[200] = { 0 };
cin.getline(Choice, 199);
if (Choice[0] == '1'&&strlen(Choice) == 1)break;
else if (Choice[0] == '0'&&strlen(Choice) == 1) {
cout << "谢谢游玩~" << endl;
system("pause");
return 0;
}
else cout << "请输入0或1" << endl;
}


}
}


同化棋实验报告

信息科学技术学院

赵旭峰

 

功能要求:

1, 能呈现可视化的棋盘;能够判断棋路是否合法,能够正确的判断胜负,具备悔棋,存档,读档等功能。

2, 能够根据用户行棋做出决策,并作出回应

3, 界面易于理解,操作容错率高

 

实现思路

基本界面

本程序中,我选择控制台应用程序,用字符画完成棋盘和棋子,利用printboard这一函数实现,由于控制台应用的反色效果,棋盘中加入了坐标轴和棋子的图例,方便用户识别。特别之处在于,悔棋选项会根据当前能否悔棋而出现/消失,这样既避免了悔棋失败的返回值问题,又便于理解。打印棋盘还使用了system(“cls”),可以避免窗体中内容过长。

 

代码如下:

intprintboard() {

blackscore = 0, whitescore = 0;

for (int i = 1; i <= 7; i++) {

        for (int j = 1; j <= 7; j++) {

               if (chess[i][j] ==-1)blackscore++;

               else if (chess[i][j] ==1)whitescore++;

        }

}

system("cls");

cout << "     欢迎来到人工智障同化棋"<< endl;

cout << "      ●黑 :○白 = " << blackscore << " : " <<whitescore << endl;

cout << "   1  2   3   4   5   6  7   X" << endl;

cout << " ╔═╦═╦═╦═╦═╦═╦═╗"<< endl;

for (int i = 1; i <= 7; i++) {

        cout << i << "║";

        for (int j = 1; j <= 7; j++) {

               switch (chess[j][i]) {

               case 0:cout << "  "; break;

               case 1:cout <<"○"; break;

               case -1:cout <<"●"; break;

               }

               cout<< "║";

        }

        if (i <= 6) {

               cout << endl <<" ╠═╬═╬═╬═╬═╬═╬═╣";

               if (i == 2)cout <<"    作为一名魔法师,你需要了解以下魔法:";

               else if (i == 3)cout <<"             存档请输入8";

               else if (i == 4 &&pastflag != 0)cout << "            悔棋请输入9";

               else if (i == 5)cout <<"             退出请输入0";

               cout << endl;

        }

}

cout << endl << "╚═╩═╩═╩═╩═╩═╩═╝" << endl;

cout << 'Y' << endl << endl;

return 0;

}

 

结果如图所示:

(若可以悔棋,会出现悔棋选项)

 

总体而言,这样打印出来的棋盘易于辨认,基本能满足功能要求。

 

 

用户交互

由于需要用户输入信息,错误输入很可能导致程序卡死或者输出非预期结果,为此,我使用了一个while结构,若输入符合要求则退出循环,否则一直返回提示信息。特别的,对于每一个输入信息,我均将其视为字符串读取,这样可以防止玩家错误地输入一个字母时,界面多次重复刷新的问题,同时,也不会因为输入多个数时提前完成了后面的输入项的问题。

 

(输入应具备一定的容错性)

存盘/读盘

为实现存盘读盘功能,我选择了fscanf,fprintf等功能,这两个函数可以从一个file类型中读取或输入信息,因此,我创建了一个Text.txt文件,用来记录存档的状态,由于这两个函数只能顺次读取数据,需要特别注意数据存放和读出的顺序。同样的,存盘读盘功能也用函数来完成。

//存入状态,依次存入玩家颜色,黑白分数,棋盘状态

int writein_save() {

       FILE*save;

       fopen_s(&save,"Text.txt", "w");

       fprintf_s(save,"%d %d %d ", Human_color, blackscore, whitescore);

       for(int i = 1; i <= 7; i++) {

              for(int j = 1; j <= 7; j++) {

                     fprintf(save,"%d ", chess[i][j]);

              }

       }

       fclose(save);

       return0;

}

//读取状态

int read_save() {

       FILE*save;

       fopen_s(&save,"Text.txt", "r");

       fscanf_s(save,"%d %d %d ", &Human_color, &blackscore, &whitescore);

       for(int i = 1; i <= 7; i++) {

              for(int j = 1; j <= 7; j++) {

                     fscanf_s(save,"%d", &chess[i][j]);

              }

       }

       cout<< chess[1][2];

       fclose(save);

       return1;

}

 

悔棋功能

在每次玩家发出指令后,棋盘数据修改之前,我将棋盘信息复制到pastchess数组中,需要悔棋时,只需将pastchess数组再复制给棋盘即可。在完成这部分过程中我遇到的一个问题是,曾经出现过悔棋后退回的结果在棋局中从来没有出现过,经检查后发现是因为另一个数组越界,但是,修改越界数组后仍然出现过错误,而且每次悔棋错误的棋局是一样的,这个问题随着bot_try函数的返回层数减小而消失,可能与别的变量的地址有关。

 

 

胜负判定

考虑到以下事实:

1.    当一方无棋可走时,这个颜色的棋子必定不与空格相邻,或者说,此时如果有空格,必定仅与另一种颜色相邻或其他空格。

2.    因此,另一种颜色可以用复制的走法填满所有空格,由于复制不会产生新的空格,一方无棋可走时另一方必定有方法使对手一直无棋可走直到自己填满整个棋盘。

 

因此,如果假设两对手都是为了取胜,当一方无棋可走时已经足够判定胜负:只需把无棋可走方的现有棋子数当作其分数,49-现有棋子数当作对方分数,比较大小即可。基于这样的思路,胜负判定就得到了简化:

 

while (1) {

                            a= check_player(Human_color);

                            b= check_player(-1 * Human_color);

                            if(a == 0 && b == 0) {

                                   printboard();

                                   if(blackscore > whitescore)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;

                                   elseif (blackscore < whitescore)cout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;

                                   break;

                            }

                            elseif (a == 0) {

                                   printboard();

                                   if(blackscore>24)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;

                                   elsecout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;

                                   break;

                            }

                            elseif (b == 0) {

                                   printboard();

                                   if(whitescore<25)cout << "恭喜你!勇士!祝贺你成为了新一代人工智障!" << endl;

                                   elsecout << "很遗憾,你输了,不过没关系,它只是下同化棋比较厉害而已……吗?" << endl;

                                   break;

                            }

 

 

BOT的决策

作为核心部分,我在决策部分中使用到了极大极小搜索和alpha-beta剪枝。基本思路是,从一个棋盘状态出发,遍历其每一个可能走法,从这些走法中选择评估函数估计最优局面。其中,在模拟对手的下一步时,由于不清楚对方的棋力,我选择假设对方也至少能选择我方的最优策略,只需要调用同一个函数,。

 

在这个部分我想到,可以利用历史数据优化评估函数。我下载了botzone上一年三个月的历史记录,用最简单的读取字符串的方法统计一局比赛中,不同位置的棋子被翻动的频率。按照估计,被反转字数最多的位置就是价值最低的位置,反之越稳定,价值也越高。进行归一化处理后我把这组数据作为权值加入到评估函数当中,使得ai更倾向于占据边角的稳定点。

 

某个月的历史记录如下:对应数字为此位置累计反转次数

2016.6

593 2212 2937 2336 1252 386 2

1339 1686 1944 1686 1362 720 296

1251 1247 1291 1187 1145 720 346

916 896 974 827 823 504 245

507 1004 1198 1019 382 151 138

262 683 921 734 244 80 12

1 365 489 389 222 29 0

 

但是注意到首行首列与其他位置的数据明显不符合预期的结果(即角<边<中心),这一点在关于对角线取平均后变得更加明显。这可能与我处理字符串的时候无法准确的识别行动路径和某些操作指令的区别导致,为此我放弃了首行首列数据并进行对角取平均,最终得到权值表。

 

doubleweight[8][8] = { { 1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5, },

{1.5,1,0.965051,0.849347,0.803681,0.779659,0.789668,1, },

{1.5,0.965051,0.87366,0.835621,0.743914,0.715635,0.719026,0.789668, },

{ 1.5,0.849347,0.835621,0.788361,0.701912,0.677423,0.715635,0.779659,},

{1.5,0.803681,0.743914,0.701912,0.70752,0.701912,0.743914,0.803681, },

{1.5,0.779659,0.715635,0.677423,0.701912,0.788361,0.835621,0.849347, },

{ 1.5,0.789668,0.719026,0.715635,0.743914,0.835621,0.87366,0.965051,},

{1.5,1,0.789668,0.779659,0.803681,0.849347,0.965051,1, } };

 

 

 

总结

经过编写同化棋程序,我学习了打开/读取文件,最大最小搜索,认识到了较大规模程序的可读性与可维护性的重要,在这个过程中,虽然前人的结论已经超出了我的实现能力,这一点很大地削减了我设计程序的成就感,但这也让我认识到差距所在。希望在未来的学习中我能够保持探索和寻求解决方案的状态,取得进步。


  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值