象棋人工智能算法的C++实现(二)

前言:在看完上一期《象棋人工智能算法的C++实现(一)》后,是不是对这个项目感到有点小兴奋呢?但是我首先要声明的是,这并不是最前沿的人工智能,所用的算法或许不是最快速的,只是闲的没事做着玩的一个小项目。欢迎各位攻城狮、各位行业大牛的讨论、批评与指正。

创一个小群,供大家学习交流聊天

如果有对学C++方面有什么疑惑问题的,或者有什么想说的想聊的大家可以一起交流学习一起进步呀。

也希望大家对学C++能够持之以恒

C++爱好群,

如果你想要学好C++最好加入一个组织,这样大家学习的话就比较方便,还能够共同交流和分享资料,给你推荐一个学习的组织:快乐学习C++组织 可以点击组织二字,可以直达


有了上一期的铺垫,本期就可以实现诸如马走日、象走田等各种棋子的走棋算法了。为了方便后期人工智能算法的实现,我们写一个总的canMove函数,在这个总的canMove函数里调用各种类型棋子的canMove函数来判断各种棋子选择的路径能不能走得通。

总的canMove函数的源代码:

bool Board::canMove(int moveid, int killid, int row, int col)

{

if(killid==-1||!sameColor(moveid,killid))

{

switch(_s[moveid]._type)

{

case Stone::JIANG:

return canMoveJIANG(moveid,row,col,killid);

break;

case Stone::SHI:

return canMoveSHI(moveid,row,col,killid);

break;

case Stone::XIANG:

return canMoveXIANG(moveid,row,col,killid);

break;

case Stone::CHE:

return canMoveCHE(moveid,row,col,killid);

break;

case Stone::MA:

return canMoveMA(moveid,row,col,killid);

break;

case Stone::PAO:

return canMovePAO(moveid,row,col,killid);

break;

case Stone::BING:

return canMoveBING(moveid,row,col,killid);

break;

default: break;

}

}

//move的棋子和kill的棋子是相同颜色的

if(sameColor(moveid,killid))

{

/*换选择*/

_selectid=killid;

update();

return false;

}

return true;

}

本期博客主要介绍相对简单的士、兵、相、马的走棋算法。

1.士的走棋算法

士的走棋规则:只能在米字格(大本营)内行走,且一次只能沿着对角线斜着走一步。

上canMoveSHI函数的源代码:

bool Board::canMoveSHI(int moveid,int row,int col,int killid)

{

if(_s[moveid]._red)

{

//判断红方士的纵向行走是否超出米字格范围

if(row>2) return false;

}

else

{

//判断黑方士的纵向行走是否超出米字格范围

if(row<7) return false;

}

//判断红黑双方方士的横向行走是否超出米字格范围

if(col<3) return false;

if(col>5) return false;

//判断是否为沿着对角线斜着行走

int dr=_s[moveid]._row-row;

int dc=_s[moveid]._col-col;

if(abs(dr)==1&&abs(dc)==1)

return true;

return false;

}

算法解析:红方和黑方的米字格范围不同,红方米字格的范围:row:0~2,col:3~5;黑方米字格的范围:row:7~9,col:3~5。要想让士沿着对角线斜着走,就是想让移动前后的横坐标差的绝对值和纵坐标差的绝对值都为1,横纵各移动一个单位长度。

士的行走图示:

2.兵的走棋算法

兵的走棋规则:无论过没过河,纵向上都不能走回头路。没过河的时候只能纵向走,过了河才可以横向走。

上canMoveBING函数的源代码:

bool Board::canMoveBING(int moveid,int row,int col,int killid)

{

/*兵的走棋规则*/

int dr=_s[moveid]._row-row;

int dc=_s[moveid]._col-col;

//红棋

if(_s[moveid]._red)

{

//过河前

if(_s[moveid]._row>=3&&_s[moveid]._row<=4)

{

//竖着走

if(dr==-1&&dc==0)

return true;

//横着走

else

return false;

}

//过河后

else

{

if(abs(dr)==1&&abs(dc)==0||(abs(dc)==1&&abs(dr)==0))

{

//竖着走

if(dr==1)

//竖着走走了回头路就要返回错误

return false;

//横着走

else

return true;

}

else

return false;

}

}

//黑棋

else

{

//过河前

if(_s[moveid]._row>=5&&_s[moveid]._row<=6)

{

//竖着走

if(dr==1&&dc==0)

return true;

//横着走

else

return false;

}

//过河后

else

{

//竖着走

if(abs(dr)==1&&abs(dc)==0||(abs(dc)==1&&abs(dr)==0))

{

//竖着走走了回头路就要返回错误

if(dr==-1)

return false;

//横着走

else

return true;

}

else

return false;

}

}

return true;

}

算法解析:兵的走棋算法的实现就比士的要难,既要处理每次移动的长度又要区分过河前和过河后的情况。实现不能走回头路的方法是计算行坐标差,以下图所示为例,以上一期博客所述的坐标系为准,红方在上,黑方在下,则红兵不能走回头路的控制条件就是行坐标差(当前位置的行坐标-目标位置的行坐标)必须为-1,黑兵不能走回头路的控制条件就是行坐标差(当前位置的行坐标-目标位置的行坐标)必须为1。实现过河与否的判断则是通过简单的行坐标范围来界定。实现步长为1的控制则更为简单,即行坐标差的绝对值为1且列坐标差的绝对值为0(或行坐标差的绝对值为0且列坐标差的绝对值为1)。

3.相的走棋算法

相的走棋规则:走田字格。若所跨田字格的中心位置有棋子存在,此时为“别象眼”,相便不能完成行走。相不能过河。

上canMoveXIANG函数的源代码:

bool Board::canMoveXIANG(int moveid,int row,int col,int killid)

{

//不能过河

if(_s[moveid]._red)

{

if(row>4) return false;

}

else

{

if(row<5) return false;

}

//走田字格

int dr=_s[moveid]._row-row;

int dc=_s[moveid]._col-col;

int medium_r=(_s[moveid]._row+row)/2;

int medium_c=(_s[moveid]._col+col)/2;

if(abs(dr)==2&&abs(dc)==2)

//别象眼检验

if(!beStone(medium_r,medium_c))

return true;

return false;

}

算法解析:实现走田字格的控制条件即是行坐标差的绝对值为2且列坐标差的绝对值为2(横纵方向上的移动步长都为2)。实现过河与否的判断则是通过简单的行坐标范围来界定。别象眼检验是相的走棋算法的核心部分,此处运用了一点初中数学知识,即中点坐标的求法,田字格对角线上的中点的坐标为((相的当前行坐标+目标位置行坐标)/2,(相的当前位置列坐标+目标位置列坐标)/2)。确定了象眼的行列坐标再调用上期博客介绍的beStone函数即可得知象眼处是否有棋子,若有棋子相则不能完成行走。

相的行走图示:

4.马的走棋算法

马的走棋规则:走日字格(横向移动1格且竖向移动2格or横向移动2格且竖向移动1格)。移动2格的那个方向上距离马当前位置最近的位置上若有棋子存在,则此时为“别马腿”,马便不能完成行走。

上canMoveMA函数的源代码:

bool Board::canMoveMA(int moveid,int row,int col,int killid)

{

int dr=_s[moveid]._row-row;

int dc=_s[moveid]._col-col;

int medium_r=(_s[moveid]._row+row)/2;

int medium_c=(_s[moveid]._col+col)/2;

if(abs(dr)==1&&abs(dc)==2||(abs(dr)==2&&abs(dc)==1))

{

if(abs(dr)==2)

{

//别马腿检验

if(beStone(medium_r,_s[moveid]._col)==false)

return true;

}

else

{

//别马腿检验

if(beStone(_s[moveid]._row,medium_c)==false)

return true;

}

}

return false;

}

算法解析:实现走日字格的方法是控制行坐标差的绝对值为1且列坐标差的绝对值为2(或行坐标差的绝对值为2且列坐标差的绝对值为1)。要想实现别马腿的检验就要先确定马的“绊脚石”的行列坐标,若马的移动步长为2的方向为横向,则该“绊脚石”的坐标为(马的当前位置行坐标,(马的当前位置列坐标+目标位置列坐标)/2);若马的移动步长为2的方向为纵向,则该“绊脚石”的坐标为((马的当前位置行坐标+目标位置行坐标)/2,马的当前位置列坐标)。

马的行走图示:

看到这里可能有人会说,我不会使用Qt开发项目,不用担心,整个项目的算法都可以抽象到控制台应用程序(黑框框)中,大家可以先动脑筋实现一下。如果后期还有人提问在黑框框中如何实现,我会视具体情况在后面的博客中加以介绍。

这个项目我会连载,后期各种算法的实现敬请期待!

- The End -

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容