博舍

围棋后德扑也被人工智能攻克了!下个会是麻将吗 国际象棋首个人工智能系统叫什么名字来着

围棋后德扑也被人工智能攻克了!下个会是麻将吗

(原标题:围棋之后,德州扑克也被人工智能攻克了!下一个会是麻将吗?)

你有没有想过,未来某一天,称霸各种竞技、棋牌游戏的都不再是人类,而是AI(人工智能)?

据科技网站TechRepublic报道,虽说位于匹兹堡的河流赌场与“科技突破”有些不搭,但本周二(1月31日),它确实见证了卡耐基梅隆大学的AI系统Libratus将4位德州扑克顶级选手斩落马下。

据凤凰科技报道,Libratus是卡耐基梅隆大学计算机科学教授尚德洪姆与博士生布朗共同打造的,在为期20天的赛程中,它们一共进行了12万手牌的比赛,最终Libratus战胜了四位人类顶尖高手。

“这是AI开辟的新疆界,”尚德洪姆在赛后的新闻发布会上说道。“也是AI在游戏比赛中获得的里程碑式突破。”

▲图片来源:卡耐基梅隆大学

Libratus的成功主要在于不断学习,每结束一天的比赛,它都能学到人类牌手的技巧并有所提升。“每天比赛结束后,Libratus内置的原算法就会分析对手的漏洞和技巧,并将其融入到Libratus未来的牌路之中。”尚德洪姆说道。

而Libratus的方式与此前人机扑克大赛的思路有所不同,此前研究人员主要寻找对手的破绽并针对相应破绽进行各个击破。Libratus则正相反,它寻找破绽的目的是要补漏,防止自己也出现同样的破绽。

1月30日傍晚,完成了3万手比赛的JimmyChou就曾筋疲力尽地告诉媒体,“这太难了。它(Libratus)不仅不留空子给我钻,而且我真的觉得它在钻我空子”。

在现实生活中或许比AlphaGo更有用

Libratus的胜利是AI逐步统治棋牌类游戏的又一里程碑,1997年时IBM的深蓝电脑在国际象棋比赛中击败世界冠军卡斯帕罗夫,去年AlphaGo则成功在围棋比赛中摘冠,而此前这项运动被认为是直觉的游戏。与深蓝电脑纯靠计算能力有所不同的是,AlphaGo拥有强化学习的能力。

Libratus的胜利还象征着AI的另一个巨大突破,因为德州扑克与围棋预设的挑战不同,它信息缺失的特性是此前AI从未触碰过的。

▲图片来源:视觉中国

杜克大学计算机教授科尼特兹也认为AI击败德州扑克顶级选手是个巨大突破。“扑克是一个有关不完美信息的游戏,它与现实世界的战略决策更加息息相关,而这种特性在商业、政治、安全甚至社交生活中都能发挥直观重要的作用。”

新南威尔士大学AI教授瓦尔斯也同意这一观点。“从某些角度来看,德州扑克的难度甚至要超越国际象棋和围棋,因为它的信息缺失非常严重。你不知道对手拿了什么牌或者即将打出什么牌,这就意味着变数的增多。此外,在扑克比赛中,选手们还会动用心理战虚张声势来影响对手的判断。”

值得注意的一点是,虽然Libratus用的依旧是传统的树形搜索、抽象和游戏战略分析等AI技术,但我们现在并未完全了解Libratus的工作方式。

“AI的进步可不止在深度学习上。”瓦尔斯补充道。

同时,瓦尔斯认为我们不能高兴的太早,因为AI并未彻底统治扑克界,眼下的比赛还是一对一,如果有更多选手加入进来,德州扑克的难度将会成倍增加。想在多人比赛中获胜,AI恐怕还得多历练几年。

此外,Libratus与AlphaGo有相同的毛病,那就是它们只专精于一个领域。因此人类不必担心它们的觉醒,因为除了玩扑克和下围棋,它们什么都不会。

围棋和德州扑克之后,人工智能的下一站会是哪个游戏?不少正在家里搓着麻将的中国网友认为,麻将会是AI无法攻破的堡垒,但果真如此吗?

带着AI去打麻将,就能百战百胜?

在许多人看来,麻将只要手气足够好,不需要技术也能赢。大部分人也常常将自己的胜利或失败,归于手气,也就是运气够不够好。

但运气真的是麻将游戏中的一切吗?一局人类看起来必输的牌,让AI来接管,结果会不会有所不同?

▲图片来源:视觉中国

每经小编在此向大家分享一篇深入解读的文章。

诚然,麻将是一种运气成分占比非常高的竞技棋牌项目,技艺再强的高手,也有输给菜鸟的可能性。但同时不可否认的是,麻将中“技艺高低”也是明显存在的。

麻将技艺的高低,不仅仅存在于高手和菜鸟之间。即使是顶尖高手,日本竞技麻将的高手段位中,在经过大量场数的竞技之后,顶尖选手之间的分数差距,同样可以稳定地被拉开,竞技水平被显著地区分开来。所以在麻将领域,研究出一个具有极高竞技水准的AI,是完全有可能的。

麻将AI的策略是怎样的?

相比于棋类这样在大多理论上可遍历(通过计算机模拟出每一种可能的情况)的“完全信息动态博弈”,棋牌类项目,因为很多情况下,你都不能知道对方手上的手牌,也不知道接下来会摸到什么牌,所以更多的情况是属于无法遍历的“非完全信息动态博弈”。

也就是说,相比于棋类AI,力求“将对手逼入必输的岔路口”这个博弈目标不同,麻将AI的策略则更多地增加自己得点的期望值,尽量让自己有更大的可能性和大牌,同时尽量避免对手的大牌点炮。而麻将的打牌策略,显然是有最优解的。每圈弃牌的14个选择里,我们总可以找到我们当前认为最好的选择,而高等的选手,和高级的AI要做的,就是尽量能多思考几回合。

当代的计算机棋手大多采用的是“蒙特卡洛树”搜索算法,策略是选择或迫使对手选择一个分支,这个分支下的所有的结局都是自己胜。AlphaGo就是蒙特卡洛算法和深度学习的结合。

让自己有更大的可能性和大牌,就需要通过手牌和弃牌池里的牌,计算自己进张(摸到有效牌)和鸣牌(吃、碰、杠),使自己手牌有进展的概率,进而计算自己和牌得分的期望值。这对于AI设计来说实际上是很简单的。

让AI避免对手的大牌点炮相对更难,一方面麻将AI需要通过大量的牌谱数据库,来获得通过对方打出的弃牌来分析其牌型的能力。这样可以让AI拥有在几圈之前,就开始弃掉别家需要的关键牌的能力。

百战百胜的麻将AI距离我们有多远?

因为竞技麻将这项运动的小众性,麻将AI目前处于一个相当缺乏发展的阶段。目前还没有可以完全战胜所有人类的麻将AI,但这其中主要的原因是缺乏相关的研究。大多麻将AI都还停留在游戏厂商的AI上,计算强度非常有限,无法与棋类AI动辄就在超级计算机上进行运行相比。

但麻将运动中,可执行的打法数量,实际上是远小于围棋的。因为毕竟手上只有14张手牌,一共也只有136张的总牌数。所以实际上麻将的复杂度,AI运行所需要的计算量,实际上也是比AlphaGO这样的围棋AI要少很多的。

并且麻将有着相对明确的目标,有着相对少的和牌牌面,所以麻将AI实际上完全可以储存大量的牌谱,然后在运算的时候,只要寻找对自己有用的牌即可,这样可以减少很多的计算量。

目前最强的麻将AI,是东京大学开发的日麻AI——“爆打”。“爆打”在日本最大的线上麻将平台,天凤上进行了1.3万多场比赛,最高达到过七段的成绩,这意味着「爆打」比96%以上的麻将玩家都取得了更好的成绩。

▲日麻AI“爆打”对战两位天凤六段选手和一位八段选手,自摸。

除了麻将之外的其他棋牌AI

实际上,除了麻将之外,很多中国民间喜闻乐见的棋牌项目,对于开发AI来寻找最优解的能力,相比棋类AI程序来说,都要简单得多。其面对的问题,同样是因为这些项目中都包含了运气成分,这使验证AI的有效性变成了一个相当难的问题。相反,麻将还是这些项目中相对规范化程度非常高的一个,至少在日本,有着非常完善的ranking(排名)机制与平台。而因为验证AI有效性很麻烦,所以也导致了这类AI开发的相对滞后。

而这样的AI的作用是什么?除了他们可以用来研究算法本身之外,棋牌AI所伴随的棋牌类竞技规范化,也是一个很重要的事情。但同时,我们还可能会看到的是,伴随着棋牌类竞技项目的赌博,可能也会开始依赖于AI催生出一个全新的产业。

斗地主、桥牌、德州扑克……在未来我们都有希望看到这些项目对应的“最强AI”,永远能找到最优解的AI出现。

很多人都想不通,为什么人类要研究一个仅仅是用来下围棋的AI,更不必说“打麻将”这件事,如今在中国完全不被当做一个“正经”竞技项目。但他们很难意识到的是,AI实际上代表了人类对这个世界,孜孜不倦的探求,和挑战自我的精神。用来“打麻将”的AI,我们创造它的动机,当然不是让我们可以利用其功能,在麻将场上百战百胜。而是我们通过麻将AI这件小事,使人类的智慧之光,得以在广袤的世界中延伸,直到洒满每一角落。

这是我们要探究这个世界上一切未知事物的动力,包括却不限于,创造一个永远可以找到最优解的,麻将AI。

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

前言:自AlphaGo战胜世界著名九段围棋手李世石之后,我就对棋类人工智能产生了极大的兴趣,并想要自己实现象棋的人工智能。然而那个时候我还在读高二,没有这么深厚的代码基础,所以那个时候也就只能想想了。但是现在不一样了,通过学习编程,已经可以让我在棋类人工智能这个领域向前探索了。

首先说明一下本系列博客描述的人工智能算法不是基于机器学习、深度学习这么高深的知识,而是一种穷举找最优走法的算法。之所以AlphaGo不能使用这种算法战胜李世石,是因为围棋棋局局势的判断是极为复杂的,想要穷举所有的情况,全世界所有的计算机一起运行一百万年也无法找到最优走法。所以DeepMind团队的大佬就想出了另一种解决方案就是让AlphaGo自己学习高水平棋手间的对局,从而提升AlphaGo的棋力。然而象棋的棋局判断还是比较容易的,杀掉对面的老将就可以获胜,杀掉对面的车马炮等棋子就可以提高自己的胜率/降低对方的胜率。具体的算法在之后的篇章详细讲解。

实现本系列博客中算法的编程工具是Qt5.5.1。

既然实现象棋人工智能的算法的本质是穷举,那么就要找到所有的通路,所谓的通路就是能够走棋的那些“路”们,走不通的那些“路”就要直接被pass掉。

1.先把棋盘抽象出来,象棋棋盘有10行9列,行标设为0~9,列标设为0~8。以左上角的坐标为(0,0),假设初始时上方为红棋,下方为黑棋。则初始时所有棋子的坐标为:

车1(红方):(0,0);车2(红方):(0,8);

马1(红方):(0,1);马2(红方):(0,7);

相1(红方):(0,2);相2(红方):(0,6);

士1(红方):(0,3);士2(红方):(0,5);

将(红方):(0,4);

炮1(红方):(2,1);炮2(红方):(2,7);

兵1(红方):(3,0);兵2(红方):(3,2);兵3(红方):(0,4);兵4(红方):(0,6);兵5(红方):(0,8);

注:红方的棋子行列坐标对应黑方棋子的行列坐标的关系为:红方行号+黑方行号=9;红方列号+黑方列号=8。

车1(黑方):(9,8);车2(黑方):(9,0);

马1(黑方):(9,7);马2(黑方):(9,1);

相1(黑方):(9,6);相2(黑方):(9,2);

士1(黑方):(9,5);士2(黑方):(9,3);

将(黑方):(9,4);

炮1(黑方):(7,7);炮2(黑方):(7,1);

兵1(黑方):(6,8);兵2(黑方):(6,6);兵3(黑方):(6,4);兵4(黑方):(6,2);兵5(黑方):(6,0);

下面给大家看一下棋盘类的源代码,里面是关于棋盘类的一些属性(数据成员)和需要在棋盘上进行的一些操作(函数成员),在这里我只给大家提供一个框架,各种成员函数的具体实现就要靠大家开动脑筋了。如果大家在这期间遇到什么问题,尽量要自己解决,如果实在解决不了,给大家提供一下我的邮箱:freedom11235@126.com。

#ifndefBOARD_H#defineBOARD_H#include#include"Stone.h"#include"Step.h"#include#includeclassBoard:publicQWidget{Q_OBJECTpublic:explicitBoard(QWidget*parent=0);//32颗棋子Stone_s[32];//棋子的像素半径int_r;//选中棋子的idint_selectid;//该不该红棋走bool_bRedTurn;//保存棋子的行走步骤QVector_steps;//输入行列获取棋子的idintgetStoneId(introw,intcol);//计算即将行走的棋子与某一坐标之间有几颗棋子intnum_of_Stone(intmoveid,introw,intcol);//输入行列坐标判断该坐标上有没有棋子boolbeStone(introw,intcol);boolcanSelect(intid);//最基本的能不能走的判断判断boolcanMove(intmoveid,introw,intcol,intkillid);//判断将能不能走boolcanMoveJIANG(intmoveid,introw,intcol,intkillid);//判断士能不能走boolcanMoveSHI(intmoveid,introw,intcol,intkillid);//判断象能不能走boolcanMoveXIANG(intmoveid,introw,intcol,intkillid);//判断车能不能走boolcanMoveCHE(intmoveid,introw,intcol,intkillid);//判断马能不能走boolcanMoveMA(intmoveid,introw,intcol,intkillid);//判断炮能不能走boolcanMovePAO(intmoveid,introw,intcol,intkillid);//判断兵能不能走boolcanMoveBING(intmoveid,introw,intcol,intkillid);//尝试函数voidtrySelectStone(intid);voidtryMoveStone(intkillid,introw,intcol);//判断两个棋子是否是同一方的boolsameColor(intid1,intid2);//走棋函数极其重载voidmoveStone(intmoveid,intkillid,introw,intcol);voidmoveStone(intmoveid,introw,intcol);//杀死棋子的函数voidkillStone(intid);//复活棋子的函数voidreliveStone(intid);voidsaveStep(intmoveid,intkillid,introw,intcol,QVector&steps);//与鼠标点击有关的函数voidmouseReleaseEvent(QMouseEvent*);voidclick(QPointpt);virtualvoidclick(intid,introw,intcol);//获取鼠标点击位置的行列坐标boolgetRowCol(QPointpt,int&row,int&col);//与显示到窗口中有关的函数voiddrawStone(QPainter&painter,intid);voidpaintEvent(QPaintEvent*);//输入行列坐标返回像素坐标QPointcenter(introw,intcol);//输入棋子的id返回像素坐标QPointcenter(intid);signals:publicslots:};#endif//BOARD_H

2.再把棋子抽象出来。每个棋子都有一个id,初始时共有32枚棋子,id从0到31;棋子所具有的属性除了id还有所处的行列位置,棋子的类型(车马炮将士相兵),棋子的颜色(红/黑),棋子是否还存活着。id置为int型;棋子类型置为枚举类型enumTYPE{JIANG,CHE,PAO,MA,BING,SHI,XIANG};棋子的颜色置为bool型_red,红棋为true,黑棋为false;棋子是否还存活置为bool型,活着为true,被吃掉为false。

#ifndefSTONE_H#defineSTONE_H#includeclassStone{public:Stone();//枚举棋子的所有类型enumTYPE{JIANG,CHE,PAO,MA,BING,SHI,XIANG};//棋子所处的行int_row;//棋子所处的列int_col;//棋子的idint_id;//棋子是否已死bool_dead;//棋子是否为红子bool_red;//棋子类型TYPE_type;//初始化棋子voidinit(intid);//获取棋子的类型名QStringgetText();};#endif//STONE_H

3.按照象棋的规则实现每个棋子的走法的前期函数铺垫。这一部分是后期人工智能算法的基础,因为后期要将所有能走的通的“路”保存在一个C++容器(类似于C语言中的数组)里。

(1)确定某个行列位置上是否存在棋子。

这个函数在后面具体棋子的走法算法中应用的非常广泛。例如走马的时候需要判断是否别了马腿,也就是需要判定想要移动的马在要去的方向的正前方的位置是否有别的棋子挡住,即判断该位置上是否存在棋子;再例如如果出现了“对将”的情况,需要判断红将和黑将之间与其在同一直线上的所有位置上是否存在棋子,若所有位置都不存在棋子则两个将可以对吃。

其实现的原理很简单,即输入一个行列坐标后遍历所有存活的棋子的行列坐标看一下有没有棋子与之完全吻合,若存在这样的棋子,则表示该行列坐标上存在棋子。

/*确定某个行列位置上是否有棋子*/boolBoard::beStone(introw,intcol){for(inti=0;i0)for(i=_s[moveid]._col+1;icol;i--){if(beStone(_s[moveid]._row,i)==true)sum++;}returnsum;}elseif(_s[moveid]._col==col){if(row-_s[moveid]._row>0)for(i=_s[moveid]._row+1;irow;i--){if(beStone(i,_s[moveid]._col)==true)sum++;}returnsum;}//两个棋子不在一条直线上return-1;}

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

欢迎大家关注/订阅我的微信公众号CodeArtOnline,我会在我的公众号分享个人见闻,发现生活趣味;这里不仅有0和1,还有是诗和远方↓↓↓

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。

上一篇

下一篇