ddz AI notes

`C` is all cards.

`p` is the part of playing cards.

`C_1` is all cards after play `p`.

求:

`P_a(C) = P_”activeWin”`

`P_p(C) = P_”passiveWin”`

设:

`P_d(p) = P_”dominate”`

`P_”f”(p) = P_”follow”`

`P_a(C) = max(P_a(p in C))`

`P_p(C) = max(P_p(p in C))`

`P_a(p,C) = P_d(p) * P_a(C_1) + (1-P_d(p)) * P_p(C_1)`

`P_p(p,C) = P_”f”(p) * P_a(p, C)`

为测试而架构

软件架构的目标是什么?为了解耦?解耦的目标是为了什么?为了测试!

所以我意识到软件架构的根本目标是为了测试。如果代码是可测试的,那么这个软件架构就是好的,如果这个软件架构是难以测试的,那么就是垃圾。

定理:软件架构质量=最大测试覆盖率

一个不健壮的难以维护的软件架构,也必然是难以测试的,他所能达到的最大测试覆盖率必然是很低的。

一个测试覆盖率高的软件架构,其模块必然是解耦的,因此也必然是灵活的,必然是一个高质量的软件架构。

常见架构

1
2
3
4
5
6
7
8
9
10

--------------------------
* APP UI, API
-------------------|------
Service | |
Facility - Context |
ORM | |
--------------| |
* 配置 | |
--------------------------

桂糊涂的德州扑克AI

如何编写德州扑克的AI。

德州扑克与其他的棋牌类游戏不同,他不一定存在着最优解,更多的是一种心理竞技。这对于人类来说可能很简单,但对于电脑来说却并不擅长。我的目标就是将人类的思维用代码的方式重现出来。

对德州的分析,首先是概率。一手牌的胜率是多少。在底牌,翻牌,转牌,河牌阶段的算法依次如下:

底牌阶段的算法采用查表法。13不同花色的牌组合共有169种,分为,对子面,同花面,杂花面。这里有个小技巧,13可以用4个bit来表示,两张底牌的组合,正好可以用一个字节来表示。我用高位在前表示同花,低位在前表示杂花。

河牌阶段的胜率算法也比较简单。我采用的是穷举法————去除自己的底牌和公牌后,组合遍历对手可能的底牌,将对手的底牌与自己的底牌比较,胜率=获胜次数/组合数。组合数共有995种。这里的关键是如何高效比较我方牌与对手牌的大小。

转牌阶段的胜率,依然采用穷举法————组合遍历河牌,并计算河牌胜率的平均值。河牌共有46种可能,因此算法复杂度为O(45540)。这一切比较都依赖于快速比较手牌,如果手牌比较速度慢,将无法快速计算出这一胜率。

翻牌阶段胜率,无法再采用转牌阶段胜率的算法,这里有个技巧,翻牌阶段胜率近似=发一张牌后的胜率。

如何快速比较自己和对方的手牌。这里也使用了一个小技巧,就是将每张牌面的大小数值化。德州牌面比较是先比较牌型,再比较牌值。因此,将牌型的值作为最高位,将牌面的值作为后5位,即可形成一个比较值。如红3黑5方A梅5方5,牌值为=3555e3。3代表3条牌型,555e3是牌面值。A一般作为14牌值处理。从高牌,对子,两对,三条,顺子,葫芦,同花,四条,同花顺,依次是0,1,2,3,4,5,6,7,8。牌面值直接用2,3,4,5,6,7,8,9,A,B,C,D,E。以16进制表示依然可以有很好的可读性。

在做牌型检测时,同花,顺子比较特殊,其他的4条,3条,葫芦,两对,对子,高牌,都是相似的。

同花检测,将同样花色的牌放进桶里,一个桶里的牌大于等于5张,则为同花,若这5张还能成顺,则为同花顺。

顺子检测时,A较为特殊,既可以和10,J,Q,K搭配,也可以和2,3,4,5,6搭配。将14位数组,设置1,0,1表示存在该牌,0表示不存在。从大到小遍历计数,连续计数5次则为顺子。之所以从大到小遍历是为了找到最大的顺子而不是最小的顺子。

其他牌型比较,先将牌放进13个桶里,然后将这些桶排序。排序方法是,桶里的牌越多越大,牌一样多比较桶本身的编号。这样我们就得出了[3个3,2个J,2个8,1个K]的桶列表。如果第一个桶是4张,那我们的牌型就是4条。第一个桶是3张就是3条,同时第二个桶是2张就是葫芦,前两个桶是两张就是两对,第一个桶是两张是一对,否则就是杂牌。

但是仅仅知道胜率是远远不够的,这只是人类思维的开始。人类对于胜率的判断很多是基于经验,但这种经验非常高效,综合考虑了很多数学概率中没考虑到的因素:比如,玩家数量,底池大小,对手下注量。人类有恐惧感,也有冒险精神,这都是电脑所不具备的。

有没有可能设计一种AI,只根据标准的概率下注,完全不考虑人类心理因素呢?

德州高手会研究对手。如果一个玩家从来不Bluff(诈赌),并且他的下注量和他的胜率相关。有经验的牌手,可以根据他的下注量反推出他的胜率,再根据他的胜率反推出他的手牌。与一个透明的玩家玩牌,要赢可能要看手气,要输真的很难。

另一方面,一个绝不冒险的玩家,也会被轻易的Bluff掉,从而使对手的实际胜率远大于理论上的胜率。

还有一方面,那就是恐惧。电脑不会恐惧,当对手ALLIN的时候,人类会忌惮,会重新评估对手的牌力。但电脑不会,他认为的大牌,无论多大的注都会跟。

因此,学会冒险与恐惧是编写德州AI的最大难点。

人数概率修正。人数影响概率。
恐惧修正。
安全跟注值计算。
Value控制。
Balnace。
BLUFF。Bluff的时机。

德州扑克策略心得

德州扑克是个概率的游戏,更是心理的游戏。

了解德州的概率只是基础,更重要的是心理战。

数学上的概率是不完整的,必须要结合实际的战斗得出更准确的概率。

比如某个选手比较谨慎,那么他Bet的时候,有大牌的概率明显更大,这是和数学上的概率不同的。

某个选手喜欢Bluff,那么他下大注的时候,有大牌的概率就会相对更小。

场上选手越多,获胜概率越小。有时为了提高胜率会Bet把一些对手挤出局。

出手的先后影响胜负。同样胜率的牌,先下注的人可能吓跑比自己略大的牌。但是最后下注的人,虽然是小牌,也会因为其他选手的Fold而提高胜率,所以最后的玩家会Call。

Allin 不一定是Bluff, 也是博弈策略。在底牌,翻牌阶段,当底池很大时Allin,自己的牌面也很大,可以起到Bluff收底的效果,如果别人跟住,也有很大胜算。

加20%~50%底池量的注,是兼顾攻击性和安全性的下注。太少无关痛痒,太多得不偿失。

Bluff 不一定要Allin, 对手在Call的时候,用Raise策略,让他非常痛苦。

Bluff一定要判断好局势,当对手比较弱的时候Bluff,但永远不要在最后一轮Bluff Allin。

数学与直觉

数学与直觉到底哪个更可靠?

交换门的实验说明直觉不太可靠。还有很多这样的例子。

德州扑克。胜率计算。一副牌的胜率,用数学计算出来的,但是实际上胜率并没有这么高。因为你本来面对的是5个对手,现在其中的4个人已经弃牌了,现在你虽然只有一个对手,但是这个对手是经过多轮淘汰剩下的。根据直觉,我们会判断这个人的牌会很强,但是数学上我们却忽视了这一点。

数学没有错,错的是我们的数学模型。

我们拿到了一手普通牌,胜率是50%。这时,一个玩家加注了,在数学逻辑上,我的胜率是没有改变的。但是在经验上,我的胜率降低了,我开始紧张。如果他加了一个大注,我可能就要弃牌了,因为我觉得赢的希望已经变小。我还是谨慎的跟了注,又发了一张牌,我得到了两对,这是一个不小的牌,我感觉胜率提升了,加注。可是这时对手全押。我感觉我的胜率又降低了,我想要弃牌,可是我又不甘心,我决定相信数学上的概率,我又80%的胜率,我跟了全押。开牌,我输了。我懊悔不已。那么问题来了,我的胜率真的有80%吗?

我们直觉的工作原理:当我抓到两对时,对手全押,我跟全押的胜率是45%,主动全押的情况下胜率是60%。

经验的数学原理。样本统计,相似度参照。似是而非的样本,会干扰我们的判断,形成偏见。女性的胼胝体更发达,能够更好的交换左右脑的信息,这也赋予了女人更强的直觉能力,不过有利有弊,胼胝体强的人可能偏见也会更多,因为他们将很多无关信息综合起来进行了利用。

尽人事 听天命

从十几岁开始,思考人为什么要活着这个问题,很快这个问题的答案显得不那么重要,因为思考的结果直接导致我相信命中注定。因为我是单纯从哲学的角度思考这个问题,而不是因为自身经历而产生的厌世情绪,所以我觉得有必要说一下。注意不是宿命,不是命运,而是命中注定,我觉得这几个词之间是有微妙的差别的,宿命与命运是一个范畴,而命中注定,是对宿命观的一个具体定义。

从微观物理学的角度上来说,一切物理现象都是有规律的,虽然在量子物理的层次上,有诸如测不准、不可知、不连续、等现象,但这都只能说明人类认知的极限,不能否定“一切物理现象都是有规律”的这一定律,爱因斯坦说“上帝不掷骰子”。人类可能以为自己的行为是有主观能动性的,不受规律限制的,但事实上,生物学基于化学,化学基于物理学,我们人类的一切活动都已经由最微观的粒子所决定了。

再从宏观系统论角度来分析。一个微观系统很难对一个宏观系统产生巨大的影响,除非这些微观系统体现出惊人的一致性。比如太阳系的活动很难影响到整个银河系,但反过来则影响很大。而人类社会看起来是一个复杂的系统,但依然是符合这种宏观系统与微观系统的制约规律的。

人类社会目前还是局限于地球这个环境的,而且目前人类也是无法操控气候的,人类社会系统无法过多的影响地球的气候系统,但地球气候系统的细微变化都会对人类社会产生巨大的影响。人类的生死往往只在瞬间。

人类社会由各种政体国家所统治,由几大主流的价值观所统治,人类的经济活动和思维模式都受这些大系统的影响。我们都是被各种经济活动和思潮变迁裹挟着在前进。人类社会的变迁往往只在一个很短的时代内完成。

人类社会资源的分配方式,是由下层聚集到上层,并由上层分配到下层的一个循环。你可以看出这种资源分配方式是多么不合理了吗?你获得的资源,与你付出的努力关系很小,而只与你所处的资源分配层次关系最大。而决定你分配层次的往往只是一两个瞬间:出生、升学、第一份工作、面试的表现。这点 赵劼 举了很多例子。

你的伴侣会陪伴你的一生,影响你很多的决定,而你和你伴侣的相识只在某一个瞬间。

我们的人生由太多的瞬间所决定。而这一瞬,有太多的巧合,这种巧合其实都是命中注定。

如何正确处理命中注定这一观点:

你努力了,不一定会成功(你可以随意定义什么是成功),但是不努力,有很大可能不成功。中国古人是很早认识到天命的,六个字概括的太好:“尽人事,听天命”

游戏赌博设计

暗黑创造了赌博系统。这个概念被暗黑刻意弱化了,赌博概率过低,页游将他发扬光大。
打怪物掉随机掉装备。
打怪掉装备与赌博系统有差别吗?一个投入的是时间,一个投入的是金钱。

暗黑符文系统,宝石系统,插槽系统。个性化。
英雄联盟符文系统,天赋系统。个性化。

神仙道命格系统————赌博+个性化。

抢劫系统与竞技场系统。同为PvP。

天梯、竞技场 与 抢劫是两条不同的线。

天梯是目标。天梯是单向的。
抢劫是手段。抢劫是乱斗。

活动战,仙道会,帮派战。

世界boss与副本。

GameObject properties adapter ———— 游戏数值开发要点

游戏数值是动态的,可叠加的,物品,天赋,被动技能,Buff,光环,都会改变一个GameObject的属性。

游戏数值开发的难点在于抽象。程序员必须将策划的语言抽象出来,否则物品、天赋、技能、Buff、等等会让你的代码千头万绪,错综复杂。

而如果能够很好的抽象出这些东西,将会一目了然,胸有成竹。

鄙人曾在一款塔防游戏中负责数值系统的开发。

数据抽象

  • 静态数据 - 设定 - Settings - S

  • 游戏对象 - 实例 - Instance - I

  • 实例的设定 - 实例的静态数据 - Instance Settings - IS

  • 实例当前的未叠加基本状态 - 实例裸体状态 - Instance Naked Data - IND

  • 状态叠加器们 - Instance Adapters - IA

配置数据

将策划语言转变为可被程序识别的数据,做到技能、物品可配置。

  • 物品 - 技能 - 天赋 - Adapters
    • [选择器] - [Selector] 定义作用对象,比如某天赋影响所有士兵,而另一技能只影响兽人士兵
      • [修改器] - [Modifier]
        • 属性
        • 操作符 + (增加x点) +% (增加x%)= (改变为x)
        • 值 x