我们在前面讲到过,各牌手的牌力估计就是我们在用蚁群算法构造最优牌型时的启发性知识。启发性知识其实就是我们利用自己的经验对事物做出的判优性评估,或者说就是对事物价值的判断。
原则上,应用蚁群算法需要用到两类启发性的知识:
- 单步择优:用来在单只蚂蚁决定下一步如何走时各选择的加权概率,其决定了优化方向
- 结构评分:单步最优未必全局最优,所以当单只蚂蚁围绕每轮次的优胜解爬出一个新解时,对这个解的质量需做一个总体评价
对于我们的牌型整理问题来说,单步择优是每手牌的牌力大小,结构评分是对所有牌手威力最大化的综合评价。那么,三张2和A23456789这两手牌的牌力该如何估算呢?!如果分不清这两手牌的大小,那么我们就无法判断2到底应该组成哪一手才更好。
嗯,大家都会打斗地主吧?如果不会的话,以学习的名义去找人打几把斗地主吧:) 记得是上海三打一啦:两副牌、四个玩家的斗地主
首先我们得把所有的牌手做一个区分:炸弹和其它。因为其它类型的牌手都只能打同类型的牌手,而炸弹可以炸掉所有比自己小的牌手,包括其它类型的牌手和比自己小的炸弹。
我们做IT的有所谓 三个世界 的说法:
- 真实世界:这个不需要解释,就是我们所感知到的客观现实
- 数字世界:这个也不需要解释,对我们做IT的来说,就是计算机、IT系统中运行的、处理的代码和编码后的信息
- 想象世界:这是只存在于我们IT人的头脑中,是从真实世界跨越数字鸿沟抵达数字世界的桥梁,就是我们如何看待、思考、解决真实世界中的问题,然后如何将其在数字世界中加以实现的
请大家务必牢记:由于真实世界和数字世界的巨大差异,所以当我们看到一个问题时首先就要将其转换一下,不能实际问题怎么样,我们就按实际问题来思考!
这种转换有两个要点:
- 保持实际问题的核心本质,这里是能正确反映实际打牌时的大小关系,但4张3的炸弹和3张3的区别也要能体现出来
- 便于计算机处理,这里是归一化(即蚂蚁进行计算时不管什么牌型都得到一个合理的牌力大小估计)、数值化(真实世界中我们是对各种牌的大小关系有个排序,IT的叫法是存在偏序关系;这里是将其转化为一个具体的数值,大小关系就看数值大小)
这时我们就看到牌力这个真实世界中的概念的问题了:牌力反映了牌手的大小,但反映不出来4张3的炸弹和3张3的本质区别!这个本质区别就是:3张3可以被比3大的其它三张打停,而4张3的炸弹则只能用炸弹才能打停!
`这可不是废话,这就是我们解决牌型整理问题时跨越数字鸿沟的关键!`
我针对这个问题,引入了自己的一个概念:**剩余牌手数**。即这手牌,需要消耗的炸弹数。斗地主的关键就是争夺牌权,剩余牌手数反映的就是这手牌需要消耗掉自己多少炸弹才能得到打出去的机会。
我把剩余牌手数的取值范围定义在:【-1,1】:
- 越靠近1则说明这手牌想顺利的打出去就需要消耗自己多少的炸弹数量
- 越接近-1则表明这手牌如果打出去了,反而会消耗掉对方的多少炸弹来阻止你继续出牌
- 0则表明该手牌容易顺出去,既不会放在手里需要用炸弹来开路,也不会打出来让对方无法大过只好用炸弹停住
这样一来,牌力的大小只要看两手牌谁更小就可以简单比较了,比如三张2我定义的剩余牌手数是-0.95,而A23456789我定义的是0.55(既不好顺也不大),所以如果不考虑其它牌,三个2、A、3-9各一张这些牌最有可能组成的两种牌型分别是:
- 牌型一:一张A、三张2和3456789的小顺子,单A我定义的剩余牌手数是0.2,三张2是-0.95(除了炸弹没有再大的三张了),3456789是0.63,共计-0.12
- 牌型二:对2和A23456789的顺子,对2我定义的剩余牌手数是-0.4(有对大鬼、对小鬼,所以不是太大),A23456789是0.55(顺子除了顶头的A,其它都不会太大,因为顺子对方也容易组成,同时对家放给你恰好长度顺子的可能性也不大,而顺子如果拆出来几个单牌,效果更差),共计0.15,因此要比牌型一差
因此理论上,就给出的牌,2应该组成三张2。
所以,剩余牌手数反映的是初始情况下不考虑任何对家的情况(即在叫完牌,对其它三家是什么样的牌还是零知识的情况下),只看自己手中的牌做出的一个基本估计。
那么,问题来了:三张2我定义的剩余牌手数是-0.95,而A23456789我定义的是0.55,这是否意味着三张2要比A23456789大?!
当然是不!剩余牌手数反映的是想打出本手牌需要消耗的炸弹数(如果需要消耗-1手炸弹则代表消耗的是对家的炸弹哦,我们用正负就完成了消耗谁的炸弹的转换),不同牌型之间的剩余牌手数只表明了本手牌的有利程度而已(价值)。这个就是我们前面所说的转换,要从真实世界各手牌的大小比较,转换到各手牌的有利程度的比较上!即本手牌能贡献多大的牌权
但是,问题又来了:单张大鬼和对大鬼的剩余牌手数都是-0.95,那岂非我们把对大鬼拆为两个单张的大鬼更为有利?!不是的,如果我们手中所有的牌组合完后,留有两张以上的单张,那么两个单张的大鬼确实要比对大鬼有利,但如果我们手中没有单张,对方打了次单张之后判断另外一张大鬼还在我们手中,从此就不出单张了,那所谓的两个单张大鬼的价值就不是很大了(当然对方的牌型要非常整齐)。所以,剩余牌手数的正确用法其实是把本类型所有牌手的剩余牌手数全部累加之后看看还需要消耗多少炸弹! 同类型累加后的剩余牌手数 反映了我们打了一手小牌之后能不能收回来,即不需要额外消耗炸弹而继续保有出牌权。所以我才会把它叫做剩余牌手数。
比如,我有单张3(0.99)、单张4(0.99)、单张小鬼(-0.4)、单张大鬼(-0.95),那么单张的剩余牌手数就是这四手牌各自的剩余牌手数的累加值:0.63。也就是说我们估计:这样的四手牌需要消耗自己0.63手炸弹才能出完。
所以除了炸弹,其它类型的牌手,如果剩余牌手数累计小于某个门限之后,就属于牌力过剩了(只具有阻击的用途,但对家判断该类型你比较强之后就会选择尝试其它攻击路线,这种情况下这些牌力就浪费掉了),我们在计算剩余牌手数时就不能统计在有效的剩余牌手数中了:此即再多的大对,也挡不住对家出三带二的。
最后总结下:
- 我用了剩余牌手数来估计牌手的价值,剩余牌手数最大的用处其实是估计同一类型的牌手是否具有攻防能力
- 解决问题需要我们首先在想象世界中完成问题的转换,这是IT工程师的基础技能,问题转换的好坏直接决定了我们能否解决问题以及解决的成本
- 各牌手的剩余牌手数的大小估计以及剩余牌手的门限等都需要我们自行指定,而这种指定是先验的、固化的常识性知识,这就限制了人工智能的能力:没有这些先验性的知识,人工智能就是一个智障患者,而先验先验,就是人类依靠自己的经验预先设定好的,只靠人工智能自身无法习得!也就是说,我们可以自己设计一种新的玩法(如掼蛋),然后叫上几个人慢慢打就学会了,而人工智能目前还没有这种学习能力,给他一个新玩法,不导入人类已经打过的牌局,人工智能就无从学起
类似剩余牌手数这样的先验性的领域常识、启发性知识很令人头疼,如果不抽出来,则人工智能没有通用性;可抽出来,又存在数量庞大、处理/应用效率极低的毛病。可能,这也正好对我们人类来说是个福音吧,我们暂时还可以不需要太过忧虑被人工智能所取代:)
====================================================================================================
关注我的公众号及时获取推送的最新文章