上一页 8.void robot() 也是人机对弈五子棋最核心的部分,其中包括了评价机制,估值,搜索部分 搜索空格的八个方向,如: 1 0 2 7 空格 3 6 5 4 最后将权值最大的几个点的位置信息保存于xposition[]与yposition[]数组中,如果极值权重相同,使用随机函数选择其中一点下棋。 void robot(void) { int x, y, X, Y, i, j; int *p, *mp; //用于指向特定数组 long int xposition[38], yposition[38]; //存储相同得权值 long int max; //当前最大权值 //将空格信息填入特定数组,用于bot评分并下子,将 360 度分成 8 个方向 //即同一个空格可能五子相连的八个方向,具体看 readme 文件 for( X = 0; X < 19; X++) //0方向检查 for( Y = 18; Y > 4; Y--) if( map[Y][X].player == blank) for( i = 0, x = X, y = Y; y > Y - 5; i++, y--) map[Y][X].value[0][i] = map[y-1][x].player; for( X = 0; X < 19; X++) //4 方向检查 for( Y = 0; Y < 10; Y++) if( map[Y][X].player == blank) for( i = 0, x = X, y = Y; y < Y + 5; i++, y++) map[Y][X].value[4][i] = map[y+1][x].player; // '/' 检查, 1 方向检查开始 for( i = 4; i < 19; i++) //'/'检查, 1 方向检查,左上部分 for( X = 0, Y = i; Y > 3; X++, Y--) //检查一斜行 if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (y > Y - 5) || (y > 0); j++, x++, y--) map[Y][X].value[1][j] = map[y-1][x+1].player; for( i = 1; i < 11; i++) for( X = i, Y = 18; X < 11; X++, Y--)// 1 方向检查,右下部分 if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (x < X + 5) || (x < 18); j++, x++, y--) map[Y][X].value[1][j] = map[y-1][x+1].player; for( i = 18; i > 3; i--)//'/'检查, 5 方向检查,左上部分 for( X = i, Y = 0; X > 3; X--, Y++) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (x > X - 5) || (x > 0); j++, x--, y++) map[Y][X].value[5][j] = map[y+1][x-1].player; for( i = 1; i < 11; i++)// 5 方向检查,右下部分 for( X = 18, Y = i; Y < 11; X--, Y++) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (y < Y + 5) || (y < 14); j++, x--, y++) map[Y][X].value[5][j] = map[y+1][x-1].player; // '/' 检查结束, 5 方向检查结束 for( Y = 0; Y < 19; Y++)// 2 方向检查,从左到右 for( X = 0; X < 10; X++) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; x < X + 5; j++, x++) map[Y][X].value[2][j] = map[y][x+1].player; for( Y = 0; Y < 19; Y++)//6 方向检查,从右到左 for( X = 18; X > 4; X--) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; x > X - 5; j++, x--) map[Y][X].value[6][j] = map[y][x-1].player; // '\' 检查开始, 3 方向检查开始 for( i = 0; i < 11; i++)// 3 方向检查,右上部分 for( X = i, Y = 0; X < 11; X++, Y++) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (x < X + 5) || (x < 18); j++, x++, y++) map[Y][X].value[3][j] = map[y+1][x+1].player; for( i = 1; i < 11; i++)// 3 方向检查,左下部分 for( X = 0, Y = i; Y < 11; X++, Y++) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (y < Y + 5) || (y < 18); j++, x++, y++) map[Y][X].value[3][j] = map[y+1][x+1].player; for( i = 18; i > 3; i--)// 7 方向检查,右上部分 for( X = 18, Y = i; Y > 3; X--, Y--) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (y > Y - 5) || (y > 0); j++, x--, y--) map[Y][X].value[7][j] = map[y-1][x-1].player; for( i = 17; i > 3; i--)// 7 方向检查,左下部分 for( X = i, Y = 18; X > 3; X--, Y--) if( map[Y][X].player == blank) for( j = 0, x = X, y = Y; (x > X - 5) || (x > 0); j++, x--, y--) map[Y][X].value[7][j] = map[y-1][x-1].player; //'\' 检查结束, 7 方向检查结束, bot 检查棋盘空格结束 //进入bot判断,对棋盘上每一个空格进行评分 for( y = 0; y < 19; y++) for( x = 0; x < 19; x++) if( map[y][x].player == blank) for( i = 0; i < 8; i++) { // for控制对一个空格的8个方向评分 p = &map[y][x].value[i][0];//mp 与 p 刚好组成 空格 的两头 if( i < 4)mp = &map[y][x].value[i+4][0]; else mp = &map[y][x].value[i-4][0]; //b 为bot, m 为man, o 为空格, x为评分点 //己方已经可以赢,或是对方可能有四子相连的评分为 100,000,000 一亿 的情况 if( *p == bot && *(p+1) == bot && *(p+2) == bot && *(p+3) == bot ) map[y][x].score += 100000000; if( *p == man && *(p+1) == man && *(p+2) == man && *(p+3) == man ) map[y][x].score += 100000000; if( *p == bot && *(p+1) == bot && *(p+2) == bot && *mp == bot ) map[y][x].score += 100000000; if( *p == man && *(p+1) == man && *(p+2) == man && *mp == man ) map[y][x].score += 100000000; if( *p == bot && *(p+1) == bot && *mp == bot &&*(mp+1) == bot ) map[y][x].score += 100000000; if( *p == man && *(p+1) == man && *mp == man && *(mp+1) == man ) map[y][x].score += 100000000; //活四评分为 10,000,000 一千万 的情况 if( *p == bot && *(p+1) == bot && *(p+2) == bot && *(p+3) == blank && *mp == blank ) map[y][x].score += 10000000; if( *p == man && *(p+1) == man && *(p+2) == man && *(p+3) == blank ) map[y][x].score += 10000000; if( *p == bot && *(p+1) == bot && *(p+2) == blank && *mp == man && *(mp+1) == blank ) map[y][x].score += 10000000; if( *p == man && *(p+1) == man && *(p+2) == blank && *mp == man && *(mp+1) == blank ) map[y][x].score += 10000000; if( *p == blank && *(p+1) == bot && *(p+2) == bot && *(p+3) == bot && *(p+4) == blank && *mp == blank ) map[y][x].score += 10000000; //冲四评分为 8,000,000 八百万 的情况 if( *p == bot && *(p+1) == bot && *(p+2) == bot && *(p+3) == man && *mp == blank ) map[y][x].score += 8000000; if( *p == bot && *(p+1) == bot && *(p+2) == man && *mp == bot && *(mp+1) == blank ) map[y][x].score += 8000000; if( *p == bot && *(p+1) == man && *mp == bot && *(mp+1) == bot && *(mp+2) == bot && *(mp+3) == blank ) map[y][x].score += 8000000; if( *mp == blank && *p == blank && *(p+1) == bot && *(p+2) == bot && *(p+3) == bot && *(p+4) == man ) map[y][x].score += 8000000; if( *mp == bot && *(mp+1) == blank && *p == blank && *(p+1) == bot && *(p+2) == bot && *(p+3) == man ) map[y][x].score += 8000000; //防对方冲四评分为 6,000,000 的情况 if( *p == man && *(p+1) == man && *(p+2) == man && *(p+3) == bot && *mp == blank ) map[y][x].score += 6000000; if( *p == man && *(p+1) == man && *(p+2) == bot && *mp == man && *(mp+1) == blank ) map[y][x].score += 6000000; //活三评分为 4,000,000 四百万 的情况 if( *p == bot && *(p+1) == bot && *(p+2) == blank && *mp == blank ) map[y][x].score += 4000000; if( *p == man && *(p+1) == man && *(p+2) == blank && *mp == blank ) map[y][x].score += 4000000; if( *p == man && *(p+1) == blank && *(p+2) == man && *(p+3) == blank && *mp == blank ) map[y][x].score += 4000000; if( *p == bot && *(p+1) == blank && *mp == bot && *(mp+1) == blank ) map[y][x].score += 4000000; if( *p == man && *(p+1) == blank && *mp == bot && *(mp+1) == blank ) map[y][x].score += 4000000; //死三评分为 1,500,000 一百五十万 的情况,进攻为主 if( *p == bot && *(p+1) == bot && *(p+2) == man && *mp == blank ) map[y][x].score += 1500000; if( *p == bot && *(p+1) == man && *mp == bot && *(mp+1) == blank ) map[y][x].score += 1500000; if( *mp == man && *p == bot && *(p+1) == bot && *(p+2) == blank ) map[y][x].score += 1500000; if( *mp == blank && *p == blank && *(p+1) == bot && *(p+2) == bot && *(p+3) == man ) map[y][x].score += 1500000; //活二评分为 100,000 十万 的情况 if( *p == bot && *(p+1) == blank && *mp == blank ) map[y][x].score += 100000; if( *p == blank && *(p+1) == bot && *(p+2) == blank && *mp == blank ) map[y][x].score += 100000; //活二评分为 70,000 七万 的情况 if( *p == man && *(p+1) == blank && *mp == blank ) map[y][x].score += 70000; if( *p == blank && *(p+1) == man && *(p+2) == blank && *mp == blank ) map[y][x].score += 70000; //冲二评分为 30,000 三万 的情况 if( *mp == blank && *p == bot && *(p+1) == man ) map[y][x].score += 30000; if( *mp == blank && *p == blank && *(p+1) == bot && *(p+2) == man) map[y][x].score += 30000; //冲二评分为 10,000 一万 的情况,防守为主 if( *mp == blank && *p == man && *(p+1) == bot ) map[y][x].score += 10000; //开局情况,并限定下子范围 if( step == blank){ do{ x = random(19); y = random(19); if( map[y][x].player != blank)x = blank; }while( x - 5 < 0 || x - 10 > 0 || y - 5 < 0 || y - 10 > 0 ); map[y][x].score += 5000; step += 1; } } max = blank; //权值评分机制初始化 for( y = 0; y < 19; y++) //搜寻权值最大点 for( x = 0; x < 19; x++) if( map[y][x].player == blank){ if( map[y][x].score > max) { max = map[y][x].score; for( i = 0; i < 38; i++) { xposition[i] = blank; yposition[i] = blank; } xposition[0] = x; yposition[0] = y; } else if( map[y][x].score == max) { i+=1; xposition[i] = x; xposition[i] = y; } } if( xposition[2] == blank)//选择最大权值点做下子点 { map[ yposition[0] ][ xposition[0] ].player = bot; mark( xposition[0], yposition[0]); } else //在最大权值相等的位置中随机选择下子点*/ { i = random(10); x = xposition[i]; y = yposition[i]; map[y][x].player = bot; mark( x, y); } } 【相关知识】篇幅所限制,活三,冲四等棋型在此就不赘述. 【心得体会】通过本次实践,初步掌握了五子棋“人机博弈”的基本算法,由于开发较为智能的程序,算法复杂度较高,固在此只进行了一层搜索。采用博弈树的算法,搜索最佳位置后,然后剪枝,选择最优。实际上按照王小春的说法,要进行深度为4搜索,计算机可能要思考15秒左右,算法时间性能较差,况且时间较仓促,没有进行更深层次的思考,期间遇到不少挫折,程序规模较以前相比庞大了不少,参照了不少源码(15×15)。 人工智能算法博大精深,日前在网上看到一种所谓“稀疏矩阵”的算法,采用“易语言”编译,时间性能尚可。有机会向作者请教请教。 【参考文献及相关资料】 《PC游戏编程(人机博弈)》 ―――― 王小春 《算法分析与设计技术》 ―――― 马绍汉 CSDN专栏 Programfan.Com论坛 baker 6/28

评论