上周讲了Cocos2d-x 制作跳棋中棋子各种动作的实现以及跳棋AI思想的分 享,这次跟大家分享跳棋胜负判断和AI具体代码实现。
一、 胜负判断
跳棋中当己方所有棋子都填满到正对方所有棋子位置时才算胜利,这样判断输赢的方 式就是遍历跳棋六个角中十个位置的状态是否为其正对方棋子颜色所代表的的数字(在第二步界 面布局中有讲到六种颜色分别用1、2、3、4、5、6来代表)。实现代码如下:
/**************** 函数名:isWin 参数:无 返回值:无 作用:判断是否产生结果 ****************/ void Game::isWin() { if(flag_win != 0) return; for(int m = 4;m > 0;m--) //循环遍历一个角的所有棋子位置判断是否已被对方填满 for(int n = 0;n < m;n++) { if(lay[17-m][n*2+13-m] != 2) { flag_win = -1; break; } } if(flag_win != -1) { flag_win = 2; return; }else flag_win = 0; for(int m = 4;m > 0;m--) //循环遍历一个角的所有棋子位置判断是否已被对方填满 for(int n = 0;n < m;n++) { if(lay[m-1][n*2+13-m] != 1) //判断相应位置是否有不是对面的棋子 { flag_win = -1; <span style="white-space:pre"> </span>//如果有不是对面的棋子则设置flag_win为0 break; } } if(flag_win != -1) { flag_win = 1; return; }else flag_win = 0; if(chess3.size() > 0) { for(int m = 4;m > 0;m--) //循环遍历一个角的所有棋子位置判断是否已被对方填满 for(int n = 0;n < m;n++) { if(lay[13+n-m][25-m-n] != 3) { flag_win = -1; break; } } if(flag_win != -1) { flag_win = 3; return; }else flag_win = 0; for(int m = 4;m > 0;m--) //循环遍历一个角的所有棋子位置判断是否已被对方填满 for(int n = 0;n < m;n++) { if(lay[n+4][2*m-2-n] != 4) { flag_win = -1; break; } } if(flag_win != -1) { flag_win = 4; return; }else flag_win = 0; for(int m = 4;m > 0;m--) //循环遍历一个角的所有棋子位置判断是否已被对方填满 for(int n = 0;n < m;n++) { if(lay[n+4][26-2*m+n] != 5) { flag_win = -1; break; } } if(flag_win != -1) { flag_win = 5; return; }else flag_win = 0; for(int m = 4;m > 0;m--) //循环遍历一个角的所有棋子位置判断是否已被对方填满 for(int n = 0;n < m;n++) { if(lay[13+n-m][m+n-1] != 6) { flag_win = -1; break; } } if(flag_win != -1) { flag_win = 6; return; }else flag_win = 0; } }其中flag_win为全局变量用来判断是哪一方胜利,当flag_win为-1时表示当前角没有出现胜负。 如果flag_win不等于0则表示已经产生结果,我们可以添加计划任务来判断flag_win是否为0进而做出胜 负操作。
二、AI实现
上周讲解了跳棋AI思想,其实就是一种搜索算法加了判断是否为最优路径的方法。下面是自己的 代码实现:
/**************** 函数名:FindStep 参数:x,y,type,n,dir 返回值:无 作用:执行寻找最优路径的算法 ****************/ void Game::FindStep(int x,int y,int type,int n,int dir) { CCLOG("step1:%d",step1); CCLOG("step1:%d",step1); step1_x[step1] = x; //将当前坐标x保存到step1_x数组中 step1_y[step1] = y; //将当前坐标y保存到step1_y数组中 if(step_x[0] == -1 && step_y[0] == -1) //判断数组step_x和step_y是否还未添加数据 { step_x[step1] = step1_x[step1]; //若为添加数据则将数组step1_x和step1_y中数据加入到数组step_x和step_y中 step_y[step1] = step1_y[step1]; } <span style="white-space:pre"> </span>switch(type) { case 1: if(step1_x[step1] >= 0 && step1_x[step1] <= 8 && chess1.at(n)->y > step1_y[step1]) //判断数组step1_x和step1_y中保存的路径数据最后一步是否在相应范围和满足相应要求 { if(-(step_y[step] - step_y[0]) < -(step1_y[step1] - step1_y[0]) && step1 <= 20) /判断数组step1_x和step1_y中路径数据是否比数组step_x和step_y中路径数据更优 { for(int m = 0;m <= step1;m++) //若数组step1_x和step1_y中路径数据更优则将step1_x和step1_y中数据保存到step_x和step_y中 { step_x[m] = step1_x[m]; step_y[m] = step1_y[m]; } step = step1; //将step1赋值为step } } break; case 3: if((3*step1_y[step1]-step1_x[step1]) >= 0 && (3*step1_y[step1]-step1_x[step1]) <= 16 && chess3.at(n)->x < step1_x[step1]) { if((step_x[step] - step_x[0]) < (step1_x[step1] - step1_x[0]) && step1 <= 20) { for(int m = 0;m <= step1;m++) <span style="white-space: pre;"> //若数组step1_x和step1_y中路径数据更优则将step1_x和step1_y中数据保存到step_x和step_y中 { step_x[m] = step1_x[m]; step_y[m] = step1_y[m]; } step = step1; //将step1赋值为step } } break; case 4: if((3*step1_y[step1]-step1_x[step1]) >= 0 && (3*step1_y[step1]-step1_x[step1]) <= 16 && chess4.at(n)->x > step1_x[step1]) { if((step_x[step] - step_x[0]) > (step1_x[step1] - step1_x[0]) && step1 <= 20) { for(int m = 0;m <= step1;m++) //若数组step1_x和step1_y中路径数据更优则将step1_x和step1_y中数据保存到step_x和step_y中 { step_x[m] = step1_x[m]; step_y[m] = step1_y[m]; } step = step1; //将step1赋值为step } } break; case 5: if((3*step1_y[step1]+step1_x[step1]) >= 8 && (3*step1_y[step1]+step1_x[step1]) <= 24 && chess5.at(n)->x < step1_x[step1]) { if((step_x[step] - step_x[0]) < (step1_x[step1] - step1_x[0]) && step1 <= 20) { for(int m = 0;m <= step1;m++) //若数组step1_x和step1_y中路径数据更优则将step1_x和step1_y中数据保存到step_x和step_y中 { step_x[m] = step1_x[m]; step_y[m] = step1_y[m]; } step = step1; //将step1赋值为step } } break; case 6: if((3*step1_y[step1]+step1_x[step1]) >= 8 && (3*step1_y[step1]+step1_x[step1]) <= 24 && chess6.at(n)->x > step1_x[step1]) { if((step_x[step] - step_x[0]) > (step1_x[step1] - step1_x[0]) && step1 <= 20) { for(int m = 0;m <= step1;m++) //若数组step1_x和step1_y中路径数据更优则将step1_x和step1_y中数据保存到step_x和step_y中 { step_x[m] = step1_x[m]; step_y[m] = step1_y[m]; } step = step1; //将step1赋值为step } } break; default: break; } if(x+12 < 25 && lay[y+4][x+12] == 0 && dir != 1 && find(x+4,y)) //判断右边隔一个棋子是否为空 { if(lay[y+4][x+10] > 0) //判断中间是否隔着棋子 { step1++; CCLOG("step1:%d",step1); FindStep(x+4,2); //执行递归 step1--; CCLOG("step1:%d",step1); } } if(x+4 > -1 && lay[y+4][x+4] == 0 && dir != 2 && find(x-4,y)) //判断左边隔一个棋子是否为空 { if(lay[y+4][x+6] > 0) { step1++; CCLOG("step1:%d",step1); FindStep(x-4,1); step1--; CCLOG("step1:%d",step1); } } if(x+10 < 25 && y+6 < 17 && lay[y+6][x+10] == 0 && dir != 3 && find(x+2,y+2)) //判断右上边隔一个棋子是否为空 { if(lay[y+5][x+9] > 0) { step1++; CCLOG("step1:%d",step1); FindStep(x+2,y+2,6); step1--; CCLOG("step1:%d",step1); } } if(x+10 < 25 && y+2 > -1 && lay[y+2][x+10] == 0 && dir != 4 && find(x+2,y-2)) //判断右下隔一个棋子是否为空 { if(lay[y+3][x+9] > 0) { step1++; CCLOG("step1:%d",y-2,5); step1--; CCLOG("step1:%d",step1); } } if(x+6 > -1 && y+6 < 17 && lay[y+6][x+6] == 0 && dir != 5 && find(x-2,y+2)) //判断左上边隔一个棋子是否为空 { if(lay[y+5][x+7] > 0) { step1++; CCLOG("step1:%d",step1); FindStep(x-2,4); step1--; CCLOG("step1:%d",step1); } } if(x+6 > -1 && y+2 > -1 && lay[y+2][x+6] == 0 && dir != 6 && find(x-2,y-2)) //判断左下边隔一个棋子是否为空 { if(lay[y+3][x+7] > 0) { step1++; CCLOG("step1:%d",3); step1--; CCLOG("step1:%d",step1); } } }其中绿色部分就是A*算法中属于自己的部分,它相对于其他搜索算法的优点就在这个方面,因 为它在搜索遍历的过程中加入了详细判断最优路径的思想,A*的效率全在于这个自己的思想。还有 要注意在每次递归回滚后要把自己建立数组的下标还原,要不然会出现数组越界的问题进而影响到 程序中其他变量的数值导致程序出错,同时数组越界是个非常让人头疼的问题,一旦出现会造成很 多不必要的调试而且还不一定能找到。
三、实现特殊组合动作的小技巧
在实现棋子跳跃的动作中我们可能要跳跃很多次,可能是一次、两次、三次甚至更多……,这 样在传统的Sequence实现顺序动作中就很难实现,有些人可能会想到用DelayTime()来实现跳棋跳 跃多次的顺序实现,但是这样很是麻烦而且在后面多人模式中实现不同棋子跳跃不同次数时将是极 其麻烦的事情,博主在实现这样功能是也是苦恼了好久,不过有幸在网上看到一位博主大大分享了 一篇如何实现一系列不同动作的方法中找到了解决这个问题的方法。
这里是那位博主大大的地址:点击打开链接
我来说说博主大大具体思想:
利用容器Vector<Dictionary *>保存Dictionary对象,然后把棋子对象chess和chess要执行 每一步的跳跃动作逐个保存到Dictionary中,最后在保存容器Vector中,构造两个函数 RunMyAction()和GetMyAction(),第一次用来执行容器中的动作,第二个用来获取容器中的动 作。在两个函数中判断容器下标是否超过容器数量,在GetMyAction()中获取动作并将动作封装到 Sequence中并在其中加入回调函数调用RunMyAction(),在RunMyAction()中执行GetMyAction() 获取相应动作并执行,这样就实现了很多不同对象执行很多不同动作的方法还省去了DelayTime() 使用时设置参数的不便。
原文链接:https://www.f2er.com/cocos2dx/342164.html