做了几个场景切换,稍微美化了一下,大体效果如下
问题定义及分析
五子棋问题归结为一个寻找某状态下的棋盘的最佳落子点的问题,所以我们不如使用一个整型二维数组来代表棋盘状态,每个元素这一点的状态,0表示该处无子,1为黑子,2为白子。将下棋时棋落在哪一点的决策标准抽象化为该点的得分@H_502_28@
我们进一步分析两个人在下棋时的想法。落子时,考虑两方面的目的:@H_502_28@
1.进攻,即设法使自己的局势朝向胜利方向转变;@H_502_28@
2.防守,即设法阻止对家胜利(即若对家在改点落子可使对家走向成功,则我方应在此落子以阻碍对方取得胜利)。@H_502_28@
故落子时必须综合考虑到上述两种因素:我们希望找到一点,当任意一方在此落子时,可造成对该方更容易达到五子连环的局面。而我们需要对“更容易达到五子连环的局面”的这一表达进行的界定:一是落子后所能达到的连环子数(这也是最直观的),二是下一个回何时是否能在此基础上继续加棋子(如:当该子下在了棋盘的边缘,则下一次最多只能下在连环的另一端,倘若另一端已有棋子,那么就不能在此继续造成更多的连环了)以及最多能加多少(1,2或0)。@H_502_28@
将上述思想转化程序思想。对于上述“更容易达到五子连环的局面”的这一表达进行的界定,采用计分的形式(如:当放置在此点可造成五子连环,便得到一个最大的分值,若只有四子连环,则得到一个小的分值,等等,再将各分值累加。@H_502_28@
遍历棋盘所有空位(在某一位置,假设放上己方的棋子,计算此时己方得分,(此为进攻得分);假设放上对方棋子,计算此时对方得分(此为防守得分),二者相加即得最终得分。选取分值最大的点,即为要下的位置@H_502_28@
@H_502_28@
下面是我从网上搜集到的计分表@H_502_28@
@H_502_28@
@H_502_28@
参照上表,实现的计分函数score如下:@H_502_28@
int ChessBox::score(int color) //1 black 2 white { char d[16][7] = { "OOOOO","+OOOO+","+OOO++","++OOO+","+OO+O+","+O+OO+","OOOO+","+OOOO","OO+OO","O+OOO","OOO+O","++OO++","++O+O+","+O+O++","+++O++","++O+++" }; int s[16] = { 50000,4320,720,120,20,20 }; int score = 0; int i,j,k,l; /* 检查行 */ for (i = 0; i < 15; i++) for (j = 0; j < 15; j++) for (k = 0; k < 16; k++) if (strlen(d[k]) + j - 1 <= 15) { int flag = 1;//flag==1 初始默认可行 for (l = 0; l < strlen(d[k]); l++) if (((d[k][l] == 'O') && (a[i][j + l] != color)) || ((d[k][l] == '+') && (a[i][j + l] != 0))) { flag = 0;//发现不可行 break; } if (flag) score += s[k]; } /* 检查列 */ for (j = 0; j < 15; j++) for (i = 0; i < 15; i++) for (k = 0; k < 16; k++) if (strlen(d[k]) + i - 1 <= 15) { int flag = 1; for (l = 0; l < strlen(d[k]); l++) if (((d[k][l] == 'O') && (a[i + l][j] != color)) || ((d[k][l] == '+') && (a[i + l][j] != 0))) { flag = 0; break; } if (flag) score += s[k]; } /* 检查斜 */ for (i = 0; i < 15; i++) for (j = 0; j < 15; j++) for (k = 0; k<16; k++) { int ii = i,jj = j; int flag = 1; for (l = 0; l<strlen(d[k]); l++) { if ((ii>15) || (jj>15)) { flag = 0; break; } if (((d[k][l] == 'O') && (a[ii][jj] != color)) || ((d[k][l] == '+') && (a[ii][jj] != 0))) { flag = 0; break; } ii++; jj++; } if (flag) score += s[k]; } /* 检查斜 */ for (i = 0; i < 15; i++) for (j = 0; j < 15; j++) for (k = 0; k < 16; k++) { int ii = i,jj = j; int flag = 1; for (l = 0; l<strlen(d[k]); l++) { if ((ii>15) || (jj < 1)) { flag = 0; break; } if (((d[k][l] == 'O') && (a[ii][jj] != color)) || ((d[k][l] == '+') && (a[ii][jj] != 0))) { flag = 0; break; } ii++; jj--; } if (flag) score += s[k]; } return score; }
进一步提高AI智能——应用博弈树
原先的算法只从电脑落子的角度考虑了一步。我们可以从玩家落子的角度再考虑一步,搜索两步。第一步搜电脑落子在该点的score[i][j],记为s1;第二步搜电脑在(i,j)落完子后,玩家落子所能获得的最大score[x][y],记为s2.取使得(s1-s2)的值最大的(i,j)作为电脑该步的落子点。这样我们综合考虑了两点:1.电脑在该步的下法优秀(s1尽量大);2.玩家在该步的最优下法差(s2尽量小),即(s1-s2)的值尽量大。同理可再向下搜第三步(s3尽量大),第四步(s4尽量小)……使(s1-s2+s3-s4……)尽量大,但是综合考虑时间效率,如果向下搜索太多步,程序运行时间较长,搜索两步时从运行时间和下棋智能两个方面综合考虑效果较好。@H_502_28@
提高AI效率——alpha-Beta剪枝
在博弈树的搜索过程中有些搜索是可以舍弃的,但是博弈树的计分方法必须修改,舍弃(s1-s2+s3-s4……)的计分方式,改为最大/最小的计分方法,只计算底层搜索的分数并且某个父节点的分数等于由它的某个子节点,在这个基础上,我们成功应用了alpha-Beta剪枝,我们通过如下图的启发策略减少了不必要的搜索@H_502_28@
@H_502_28@
@H_502_28@
矩形框节点是电脑走,圆形框节点是玩家走,我们搜索固定的层数n(搜索层数即为要搜的步数,图中的例子n=5),第n层为叶子节点,计算每个叶子节点对应的棋局的score,对于节点E,E是玩家走的节点,因此会在I、J节点中选择score最小的节点(即节点I,score=2),并将I的score作为自己的score。对于节点C,C是电脑走的节点,因此会在E、F节点中选score最大的节点。搜索节点F时,F是玩家走的节点,会在K、L、M中选score最小的节点,发现K的score为1,则F的score小于等于1,而E的score是2,E、F中score较大的点必定是E,F的子节点L、M不用再搜索。对于节点A,A是玩家走的点,会在C、D中取score最小的点。对于节点D,D是电脑走的点,会在G、H取score最大的点,因为G的score为7,所以D的score大于等于7,而C节点score为2,因此A节点取子节点C,D的子节点H不用搜索。@H_502_28@
@H_502_28@
用递归实现的alpha-beta剪枝如下:@H_502_28@
</pre><pre name="code" class="cpp">int ChessBox::nextscore(int currentDepth,int color,int depth){ int highest = 0; int lowest = 0; int rescore = 0; for (int i = 0; i < 15; i++){ for (int j = 0; j < 15; j++){ if (a[i][j] == 0){ if (currentDepth == depth){//搜索到底层,计算分数 a[i][j] = 3 - color; rescore = score(3 - color); a[i][j] = color; rescore += score(color); a[i][j] = 0; } if (currentDepth % 2 == 0){ a[i][j] = color; if (currentDepth<depth)rescore = nextscore(currentDepth + 1,3 - color,depth);//深度优先,进入下一层搜索 a[i][j] = 0; if (rescore>= beta) {//发现大于等于当前层的beta值,余下的不需再探索,发生beta剪枝 return rescore; } if (rescore >= highest){ highest = rescore; if (currentDepth == 1){ recordx = i; recordy = j; } } } if (currentDepth % 2 != 0){ a[i][j] = color; if (currentDepth < depth)rescore = nextscore(currentDepth + 1,depth);///深度优先,进入下一层搜索 a[i][j] = 0; if (currentDepth == 1)rescore = -rescore; if (rescore <= alpha) {//发现小于等于当前层的alpha值,余下的不需再探索,发生alpha剪枝 return rescore; } if (rescore <= lowest){ lowest = rescore; if (currentDepth == 1){ recordx = i; recordy = j; } } } } } } if (currentDepth % 2 == 0){//max层返回最大值给父节点 beta = highest; return beta; } else {//min层返回最小值给父节点 alpha = lowest; return alpha; } }
_____________________________________HelloWorldScene.h_____________________________________________________ #ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include <stack> #include <iostream> #include "cocos2d.h" #include"editor-support\cocostudio\CCSGUIReader.h" #include"ui\CocosGUI.h" using namespace cocos2d; using namespace cocos2d::ui; using namespace cocostudio; using namespace std; //场景Choose class Choose : public cocos2d::Layer{ public: static cocos2d::Scene* createScene(); virtual bool init(); void whiteenter(Ref* pSender); void blackenter(Ref* pSender); CREATE_FUNC(Choose); }; //场景PLAY class Play : public cocos2d::Layer { public: // there's no 'id' in cpp,so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); // Here's a difference. Method 'init' in cocos2d-x returns bool,instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback Layout* layout; Button* restart; Button* back; // implement the "static create()" method manually CREATE_FUNC(Play); }; /************************************************************************/ /* ChessBox类绑定了重要的其他控件,方便我们在回调函数中对这些控件进行操作 (这次为了方便,我没有做好很好的封装,数据和函数都放在public部分,这是我 做的不好的地方,下次有待改进) */ /************************************************************************/ class ChessBox :public cocos2d::Node { public: ChessBox(); ~ChessBox(); void Bindwhite(Sprite* sprite); void Bindblack(Sprite* sprite); void Bindback(Sprite* sprite); void Bindrestart(Sprite* sprite); void Check();//检查游戏是否结束的函数,包含了结束的动画 int score(int color);//计算棋盘分数的函数 int nextscore(int currentDepth,int depth); Sprite* ai();//ai函数,修改抽象化棋盘,返回一个棋子精灵的指针 stack<Sprite*> chessstack;//棋子栈 stack<int*> posstack;//坐标栈 Sprite* back;//将要绑定的悔棋控件 Sprite* blackBox;//将要绑定的黑棋盒控件 Sprite* whiteBox;//将要绑定的白棋盒控件 Sprite* restart;//将要绑定的新局控件 int isai;//人机对战的状态 bool end;//是否结束的状态 int recordx,recordy; int a[15][15];//棋盘的抽象化 int maxmin[10]; int alpha=60000,beta=-60000; int pitch;//下棋的状态,1代表这一步走白子,2走黑子 int aicolor;//ai执棋颜色 CREATE_FUNC(ChessBox); virtual bool init(); }; class Introduction : public Layer{ public: static Scene* createScene(); virtual bool init(); void oneenter(Ref* pSender); void twoenter(Ref* pSender); CREATE_FUNC(Introduction); }; #endif
</pre><pre name="code" class="cpp">__________________________________Introduction.cpp____________________________________________________________________ #include "HelloWorldScene.h" USING_NS_CC; using namespace std; //两个全局变量的初始化 int Aicolor = 0; int playway = 0; Scene* Introduction::createScene(){ auto scene = Scene::create(); auto layer = Introduction::create(); scene->addChild(layer); return scene; } void Introduction::oneenter(Ref* pSender){ playway = 1;//人机对战 Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f,Choose::createScene())); //这里使用了场景切换动画,效果是从中心向四周扩散 } void Introduction::twoenter(Ref* pSender){ playway = 2;//双人对弈 Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f,Play::createScene())); //同样使用了场景切换动画 } bool Introduction::init(){ Size visibleSize = Director::getInstance()->getVisibleSize(); Point origin = Director::getInstance()->getVisibleOrigin(); Layout* InBg = Layout::create(); this->setPosition(Point(visibleSize.width/2,visibleSize.height/2)); this->addChild(InBg); InBg->setBackGroundImage("BG.png"); auto item1 = MenuItemImage::create( "one1.png","one.png",CC_CALLBACK_1(Introduction::oneenter,this)); auto item2 = MenuItemImage::create( "two1.png","two.png",CC_CALLBACK_1(Introduction::twoenter,this)); item2->setPosition(Point(0,-200)); Menu* pMenu = Menu::create(item1,item2,NULL); pMenu->setPosition(Point(0,140)); this->addChild(pMenu,1); return true; }
_____________________________________HelloWorldScene.cpp___________________________________________________ #include "HelloWorldScene.h" USING_NS_CC; using namespace std; extern int Aicolor;//定义的外部全局变量,这里做声明 extern int playway; Scene* Play::createScene()//默认的场景生成函数 { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = Play::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } //场景Play的初始化 bool Play::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } //获取窗体大小以及origin坐标 Size visibleSize = Director::getInstance()->getVisibleSize(); Point origin = Director::getInstance()->getVisibleOrigin(); //Layout的初始化;添加背景图片 layout = Layout::create(); layout->setSize(Size(visibleSize.width,visibleSize.height)); layout->setBackGroundImage("BG.jpg"); layout->setPosition(Point(0,0)); this->addChild(layout); //创建一个精灵代表棋盘 Sprite* broad = Sprite::create("broad.png"); broad->setPosition(Point(65+217,70+222)); broad->setScale(1.19f); layout->addChild(broad); //ChessBox以及棋盘上各按钮,组件的初始化 ChessBox* chessBox = ChessBox::create(); Sprite* blackBox = Sprite::create("BBox.png"); Sprite* whiteBox = Sprite::create("WBox.png"); Sprite* back = Sprite::create("back.png"); Sprite* restart = Sprite::create("restart.png"); //玩家个数,是否人机对战等信息 chessBox->aicolor =Aicolor; chessBox->pitch = 3-Aicolor; chessBox->isai = playway; /************************************************************************/ /*将其他控件绑定到chessBox */ /************************************************************************/ chessBox->Bindblack(blackBox); chessBox->Bindwhite(whiteBox); chessBox->Bindback(back); chessBox->Bindrestart(restart); chessBox->setPosition(Point(600,120));//调整好位置 layout->addChild(chessBox,300); //如果是人机对战,玩家持白字,则ai先落子 if (Aicolor == 1 && playway == 1){ auto aichess = chessBox->ai(); layout->addChild(aichess); } auto chesslistener=EventListenerTouchOneByOne::create(); /************************************************************************/ /* 接下来将开始监听事件 使chesslistener的onTouchBegan指向一个lambda函数,而lambda表达式内部是异步线程 所以,由点击事件触发的一切变化都最好通过事件绑定的精灵对象来操作 Ps:我尝试过直接在[&]形式的lambda表达式里对栈以及其它对象进行操作,发现对cocos 的Node类以及其子类直接利用我截取的引用来调用addChild和removeChild居然不会发生 错误,其他的都报错。这两个方法是否有什么特殊之处? */ /************************************************************************/ chesslistener->onTouchBegan = [&](Touch* touch,Event* event){ auto target = static_cast<ChessBox*>(event->getCurrentTarget()); Point pos = Director::getInstance()->convertToGL(touch->getLocationInView()); //获取棋子的棋盘坐标 int x = (pos.x - (72 + 15+30*3)) / 36 +3; int y = (pos.y - (82 + 15+30*7)) / 32+7; if (x >= 0 && y >= 0 && x <= 14 && y <= 14 && target->end == false) { if (target->pitch== 1 &&target->a[x][y]==0)//pitch 表示下棋的状态,1为黑子下,2为白子下 { target->whiteBox->setScale((1.2f)); target->blackBox->setOpacity(0); target->blackBox->setScale(1.0f); target->whiteBox->setOpacity(255); target->whiteBox->setPosition(Point(70,0)); target->blackBox->setPosition(Point(70,0)); Sprite* newchess = Sprite::create("black.png"); newchess->setPosition(Point(72 + x * 30,82 + y * 30));//放置棋子 layout->addChild(newchess,10); newchess->setScale(0.193f); target->chessstack.push(newchess);//将棋子压入棋子栈 target->a[x][y] = 1;//该位置不能再落子 target->posstack.push(&(target->a[x][y]));//将此坐标压入坐标栈 target->Check();//检查游戏是否结束 if (target->end == false){/*若游戏未结束,则继续*/ if (target->isai == 1){ /*若目前为人机对战模式,则ai落子*/ target->blackBox->setScale((1.2f)); target->whiteBox->setOpacity(0); target->whiteBox->setScale(1.0f); target->blackBox->setOpacity(255); target->whiteBox->setPosition(Point(70,0)); layout->addChild(target->ai(),10); target->Check();//检查游戏是否结束 } else target->pitch = 2; /*若目前为双人对战模式,则改变棋子颜色,等待下一玩家落子*/ } return true; } if (target->pitch == 2 && target->a[x][y] == 0)//下白子的情况,和黑子基本一样 { target->blackBox->setScale((1.2f)); target->whiteBox->setOpacity(0); target->whiteBox->setScale(1.0f); target->blackBox->setOpacity(255); target->whiteBox->setPosition(Point(0,0)); target->whiteBox->setPosition(Point(70,0)); Sprite* newchess = Sprite::create("white.png"); newchess->setPosition(Point(72 + x * 30,82 + y * 30)); layout->addChild(newchess,10); newchess->setScale(0.21f); target->chessstack.push(newchess); target->a[x][y] = 2; target->posstack.push(&(target->a[x][y])); target->Check(); if (target->end == false){ if (target->isai == 1){ target->whiteBox->setScale((1.2f)); target->blackBox->setOpacity(0); target->blackBox->setScale(1.0f); target->whiteBox->setOpacity(255); target->whiteBox->setPosition(Point(70,10); target->Check(); } else target->pitch = 1; } return true; } } return false; }; chesslistener->onTouchEnded = [&](Touch* touch,Event* event){ }; //监听时间的注册 _eventDispatcher->addEventListenerWithSceneGraPHPriority(chesslistener,chessBox); auto restartlistener = EventListenerTouchOneByOne::create(); /* 设置重新开始监听 */ restartlistener->onTouchBegan = [](Touch* touch,Event* event){ auto target = static_cast<ChessBox*>(event->getCurrentTarget()); Point pos = Director::getInstance()->convertToGL(touch->getLocationInView()); if (pos.x<839 && pos.x>651 && pos.y<521 && pos.y>399) { target->restart->setScale(1.25f);//点击开始只在视图层层响应,逻辑层响应在松开鼠标之后 return true; } return false; }; restartlistener->onTouchEnded = [&](Touch * touch,Event* event){ auto target = static_cast<ChessBox*>(event->getCurrentTarget()); target->restart->setScale(1.0f); target->end = false; while (!(target->chessstack.empty())){/*将棋子栈和坐标栈置空,同时重新初始化棋盘*/ layout->removeChild(target->chessstack.top()); target->chessstack.pop(); *(target->posstack.top()) = 0; target->posstack.pop(); } }; //注册第二个监听事件,同样和chessBox绑定 _eventDispatcher->addEventListenerWithSceneGraPHPriority(restartlistener,chessBox); /************************************************************************/ /* 悔棋功能的实现 */ /************************************************************************/ auto backlistener = EventListenerTouchOneByOne::create(); backlistener->onTouchBegan = [&](Touch* touch,Event* event){ auto target = static_cast<ChessBox*>(event->getCurrentTarget()); Point pos = Director::getInstance()->convertToGL(touch->getLocationInView()); if (pos.x<859 && pos.x>661 && pos.y<361 && pos.y>259 && target->end == false) { target->back->setScale(1.25f); if (!target->chessstack.empty()){ layout->removeChild(target->chessstack.top()); target->chessstack.pop(); *(target->posstack.top())=0; target->posstack.pop(); } if (!target->chessstack.empty()){ layout->removeChild(target->chessstack.top()); target->chessstack.pop(); *(target->posstack.top()) = 0; target->posstack.pop(); } return true; } return false; }; backlistener->onTouchEnded = [](Touch * touch,Event* event){ auto target = static_cast<ChessBox*>(event->getCurrentTarget()); target->back->setScale(1.0f); }; _eventDispatcher->addEventListenerWithSceneGraPHPriority(backlistener,chessBox); return true; }
______________________________________Choose.cpp__________________________________________________________ #include "HelloWorldScene.h" extern int Aicolor; extern int playway; Scene* Choose::createScene(){ auto scene = Scene::create(); auto layer = Choose::create(); scene->addChild(layer); return scene; } void Choose::whiteenter(Ref* pSender){ Aicolor = 1;//修改全局变量,表示ai执黑子 Director::getInstance()->replaceScene(TransitionProgressInOut::create(0.5f,Play::createScene())); } void Choose::blackenter(Ref* pSender){ Aicolor = 2;//修改全局变量,表示ai执白子 Director::getInstance()->replaceScene(TransitionProgressInOut::create(0.5f,Play::createScene())); } bool Choose::init(){ Size visibleSize = Director::getInstance()->getVisibleSize(); Point origin = Director::getInstance()->getVisibleOrigin(); Layout* InBg = Layout::create(); this->setPosition(Point(visibleSize.width / 2,visibleSize.height / 2)); this->addChild(InBg); InBg->setBackGroundImage("BG.png"); auto white = MenuItemImage::create( "WC.png","BWC.png",CC_CALLBACK_1(Choose::whiteenter,this)); auto black = MenuItemImage::create( "BC.png","BBC.png",CC_CALLBACK_1(Choose::blackenter,this)); black->setPosition(Point(-200,0)); white->setPosition(Point(200,0)); Menu* pMenu = Menu::create(white,black,0)); this->addChild(pMenu,20); return true; }
_____________________________________________________ChessBox.cpp___________________________________________________________________ #include "HelloWorldScene.h" extern int playway; extern int Aicolor; ChessBox::ChessBox(){ blackBox = NULL; whiteBox = NULL; end = false; for (int i = 0; i < 15; i++){ for (int j = 0; j < 15; j++){ a[i][j] = 0; } } } ChessBox::~ChessBox(){} void ChessBox::Bindblack(Sprite* sprite){ blackBox = sprite; blackBox->setPosition(Point(0,0)); this->addChild(sprite); } void ChessBox::Bindwhite(Sprite* sprite){ whiteBox = sprite; whiteBox->setPosition(Point(130,0)); this->addChild(sprite); } void ChessBox::Bindback(Sprite* sprite){ back = sprite; back->setPosition(Point(50,150)); this->addChild(sprite); } void ChessBox::Bindrestart(Sprite* sprite){ restart = sprite; restart->setPosition(Point(50,300)); this->addChild(sprite); } int ChessBox::score(int color) //1 black 2 white { char d[16][7] = { "OOOOO",jj = j; int flag = 1; for (l = 0; l<strlen(d[k]); l++) { if ((ii>15) || (jj < 1)) { flag = 0; break; } if (((d[k][l] == 'O') && (a[ii][jj] != color)) || ((d[k][l] == '+') && (a[ii][jj] != 0))) { flag = 0; break; } ii++; jj--; } if (flag) score += s[k]; } return score; } int ChessBox::nextscore(int currentDepth,int depth){ int highest = 0; int lowest = 0; int rescore = 0; for (int i = 0; i < 15; i++){ for (int j = 0; j < 15; j++){ if (a[i][j] == 0){ if (currentDepth == depth){//搜索到底层,计算分数 a[i][j] = 3 - color; rescore = score(3 - color); a[i][j] = color; rescore += score(color); a[i][j] = 0; } if (currentDepth % 2 == 0){ a[i][j] = color; if (currentDepth<depth)rescore = nextscore(currentDepth + 1,depth);//深度优先,进入下一层搜索 a[i][j] = 0; if (rescore>= beta) {//发现大于等于当前层的beta值,余下的不需再探索,发生beta剪枝 return rescore; } if (rescore >= highest){ highest = rescore; if (currentDepth == 1){ recordx = i; recordy = j; } } } if (currentDepth % 2 != 0){ a[i][j] = color; if (currentDepth < depth)rescore = nextscore(currentDepth + 1,depth);///深度优先,进入下一层搜索 a[i][j] = 0; if (currentDepth == 1)rescore = -rescore; if (rescore <= alpha) {//发现小于等于当前层的alpha值,余下的不需再探索,发生alpha剪枝 return rescore; } if (rescore <= lowest){ lowest = rescore; if (currentDepth == 1){ recordx = i; recordy = j; } } } } } } if (currentDepth % 2 == 0){//max层返回最大值给父节点 beta = highest; return beta; } else {//min层返回最小值给父节点 alpha = lowest; return alpha; } } Sprite* ChessBox::ai(){ for (int i = 0; i < 10; i++){ maxmin[i] = 0; } alpha = 60000; beta = -60000; recordx = 0; recordy = 0; nextscore(1,pitch,2); if (pitch == 2 && a[recordx][recordy] == 0) { Sprite* aichess = Sprite::create("black.png"); aichess->setPosition(Point(72 + recordx * 30,82 + recordy * 30)); aichess->setScale(0.193f); chessstack.push(aichess); a[recordx][recordy] = 1; posstack.push(&(a[recordx][recordy])); return aichess; } if (pitch == 1 && a[recordx][recordy] == 0) { Sprite* aichess = Sprite::create("white.png"); aichess->setPosition(Point(72 + recordx * 30,82 + recordy * 30)); aichess->setScale(0.21f); chessstack.push(aichess); a[recordx][recordy] = 2; posstack.push(&(a[recordx][recordy])); return aichess; } } void ChessBox::Check(){ MoveBy* ending = MoveBy::create(0.9f,Point(0,-300)); MoveBy* stop = MoveBy::create(0.9f,0)); MoveBy* start = MoveBy::create(0.9f,500)); if (playway == 1){ if (score(aicolor) > 50000){ end = true; Sprite* lose = Sprite::create("lose.png"); lose->setPosition(Point(-300,500)); this->addChild(lose,300); auto re = [&](){ this->removeChild(lose); }; CallFunc* ca = CallFunc::create(re); Action* moves = Sequence::create(ending,stop,start,ca,NULL); lose->runAction(moves); } if (score(3 - aicolor) > 50000){ end = true; Sprite* win = Sprite::create("win.png"); win->setPosition(Point(-300,500)); this->addChild(win,300); auto re = [&](){ this->removeChild(win); }; CallFunc* ca = CallFunc::create(re); Action* moves = Sequence::create(ending,NULL); win->runAction(moves); } } else{ if (score(1) > 50000){ end = true; Sprite* blackwin = Sprite::create("blackwin.png"); blackwin->setPosition(Point(-300,500)); this->addChild(blackwin,300); auto re = [&](){ this->removeChild(blackwin); }; CallFunc* ca = CallFunc::create(re); Action* moves = Sequence::create(ending,NULL); blackwin->runAction(moves); } if (score(2) > 50000){ end = true; Sprite* whitewin = Sprite::create("whitewin.png"); whitewin->setPosition(Point(-300,500)); this->addChild(whitewin,300); auto re = [&](){ this->removeChild(whitewin); }; CallFunc* ca = CallFunc::create(re); Action* moves = Sequence::create(ending,NULL); whitewin->runAction(moves); } } } bool ChessBox::init(){ return true; }