Main

April 21, 2008

不那么随机的随机数列

曾经看过这样一种赌徒的策略:假设在一场赌大小的赌博游戏中,赔率是 1:1 ,而庄家不会出千,开大和开小的概率均等(皆为 50%)。赌徒一开始压一块钱,如果他压错了,那么下一次就压两块,再错继续加倍。一旦压对,赌徒永远可以保证有一块钱的进帐。并且从 1 块钱重新开始。

看起来,这种策略能保证永远包赚不赔。但实际上为什么没有人用这个方案发财呢?

放到现实中,试图采用这个策略去赌博的人,几乎都会赔的倾家荡产(当然只要是赌博,差不多都是这个结局)。不要怪运气,不要怪庄家出千,因为这个策略从一开始就注定了失败。

November 25, 2007

随机数有多随机?

作为一个常识,每个程序员在做入门学习时,都会被老师谆谆教导:我们用的编程语言中的随机函数,只能产生出伪随机数。它有它的内在规律,只能作为对显示世界的随机事件的近似模拟。接下来,我们通常会被传授随机种子的概念。以及用物理上更随机的量做种子。比如系统时间、两次敲击键盘的时间间隔、多次移动鼠标的偏移、甚至系统出错的出错信息码等等。

作为游戏数值策划,除了加减乘除,用的最多的数学概念恐怕就是随机数了。有经验的数值策划或许从他的前辈那得知计算机中程序产生的随机数并不太可靠;或者他本身就受过程序方面的训练。如果游戏项目更幸运一点,担当数值策划的他是一个数学爱好者,并读过诸如《计算机程序设计艺术》这样的技术书籍,那么事情会好的多。可惜大多数境遇下,策划们从不深究计算机随机数背后的细节,也不太关心所谓“伪”随机数究竟“伪”到什么程度。

最近几天,有测试人员向我抱怨,我们游戏中某些概率设定总感觉有点怪怪的。似乎跟文档上的不同。

这种抱怨并不少见,许多网络游戏玩家都在抱怨系统生成的随机数不太对劲。善良点的玩家会归咎到自己的 RP 上,阴谋论者则指责系统作弊。运营着的游戏背后,数值策划和程序员们有苦说不出。

有必要科普一些数学常识,也作为我周末读书的一些笔记。

September 30, 2007

洗牌

今天从 svn 中取下一个同事的代码,浏览了一下。其中一段是关于洗牌的。感觉实现的很乱,算法也没有选好。自己重新写了一个。

因为国庆的缘故,负责这块代码的同事提前回家了。我只好自己读代码实现。看完后,发现旧的实现是这样的:对于 N 张牌,每次随机抽出一张来,检查这张牌是否抽过。如果被抽取过,就重复抽取过程,直到不重复。然后记录下抽取的牌的位置。重复这个过程,直到得到一个随机序列。最后用这个序列将原始排列打乱。

这个方案给我的第一感觉并不好,因为当 N 较大时,最后需要重复抽取多次才可以成功。我估算了整个的时间复杂度大约是 O(N^2)

当然,洗牌这件事情可以有许多算法来解决。我重新写了一个,采用了最简单实现的方案。

September 21, 2007

泊松分布

周末,同事离去的都很早。我留在办公室,这周想做的事情基本完成,那就随便写点东西。

写写概率论中非常重要的泊松分布(poisson distribution)是我这周中间就有的想法。

具体的起因记的不太准确了,似乎是因为在一个接收新游戏 bug 反馈的 IM 群里跟同事聊天跑题。从游戏的 bug 扯到游戏的数值设定,然后说起概率,再跑题到大学中学到的数学知识;正好前几天睡觉前在翻《一生受用的公式》这本袖珍小册子,看到了泊松分布的公式以及关于它的有趣的插图;然后问起同事对这个东西的了解程度。

结果可想而知,当时没有人可以准确告诉我到底什么是泊松分布,它有什么用,当然更不用提它的公式是怎么推导出来的了。让我有点自鸣得意的是,自己大概还知道个所以然。不管怎么说,若不是当年本科的概率统计考试中的笔误,我就能拿个满分的。上大学时,考试前我很少复习,不感兴趣的课程也基本没去读书。不是说天才到可以以那种状态考试过关,只是那个时候我不太在意挂科而已 :)。相比较而言,没经过理解的东西让我去背公式应付考试这种事情,我是坚决不干的。

可惟独这本概率统计,我是相当喜欢,也就最认真的去学了。

自己明白不是真的明白,一旦想教给别人时就会露馅。当想把我曾经的理解和记忆写出来时,才发现自己写不太清楚。这几天没事翻了翻书,也 google 了一下,理清了点思路。今天记录下来,算是一个总结。

September 06, 2007

玩了一下 ajax

起因是这样的:

几个同事在棋牌群里聊天,说找不到搭档打桥牌。网上也没啥好地方去,大家都比较讨厌下客户端和注册。我说,不如我做一个免客户端免注册的桥牌网站吧。然后就开始了。

直觉告诉我,ajax 技术可以实现这些。但是我没做过 web 方面的开发,仅有的一些知识只在几年前写过一个 php 留言本。一开始觉得 ajax 这些时髦玩意学一下午,然后一通宵就可以把想要的东西做出来。哪知道,结果不务正业干了半周了,中间还熬了两晚上,到今天都没做完。明天要出差,只好放一放了。

December 22, 2006

菜鸟打桥牌

昨天周四,晚上是固定桥牌时间。

我们公司一小撮人闷头自学打桥牌已经大半年了。就是从网上拉了一本精确叫牌法的手册,胡乱翻了几页,自己瞎打到现在。水平勉强算是已入门的菜鸟吧。

或许什么游戏都是在菜鸟阶段最有乐趣,昨天打了一局牌就相当有趣 :D

我的记忆力已经比刚打牌时好多了,睡了一觉后勉强回忆,终于把当时的情况回想起来。大约是这样的:

                          S XX
                          H K 10 XXX
                          D A 10 8 X
                          C 10 X

S QJ 10 XX                                   S XX
H J X X                                          H Q XX
D X X                                             D J 9 XX
C A X X                                         C K XXX

                         S AK72
                         H AX
                         D K53
                         C QJ9X

June 21, 2006

打成了一次大满贯

我的桥牌生涯实在是太短,所以平生第一次大满贯在昨天晚上才出现。不完全是运气,牌不好叫也不好打。联手牌点其实是不够的,叫牌的时候想了许久才下了决心把 6 加到 7。首攻,明手摊开后又想了很久。但最后毕竟打成了。留文纪念之 :D

June 13, 2006

概率游戏

最近一直在打桥牌,每周2到3次。感觉自己水平提高的比较快。暂时用的精确叫牌,不过好多人打自然,决定过段时间多了解一些叫牌体系。当然,桥牌是个逻辑推理性很强的游戏,各个叫牌体系就算有不同,牌理也是相通的,我想都不难吧。我也不会去参加竞技性质的牌局,不用去刻意人工设计叫牌。

打牌另一个好玩的地方就是很多情况都是要计算概率的。昨天睡觉的时候想到一个问题,很常用,但是一直没有仔细计算过。

当庄家与明手确定有 8 张将牌的时候,对手的 5 张将牌分布的概率。

我大略算了一下,

  • 0-5 分布的概率直观上就知道很少。应该是 (21!/8!) / (26!/13!) * 2 = 3.91%
  • 1-4 分布的概率应该是 (21!/9!) / (26!/13!) *5 *2 = 10.87% (如果有一张 K 在外面,想赌这张 K 是一个单牌,概率只有 2.17% )
  • 那么剩下的 2-3 分布的概率即为 85.2%

当庄家和明手确定 9 张将牌的时候,对手 4 张将牌分布的概率为:

  • 0-4 分布是 9.57%
  • 1-3 分布是 15.3%
  • 2-2 分布是 75.13%

接下来讨论另一个问题,如果联手 8 张将牌,少张 Q 。把 Q 憋死的概率就是:1-4 分布中,Q 为单张的概率为 2.17% 。或者 1-4 分布,且 4 张在对我方有利的位置(这个时候飞牌几乎总可以成功,除非庄家将牌 1-7/0-8 分布,这种情况不多,暂时忽略)的概率是 4.35%,2-3 分布时且 Q 在 2 张这边的概率为 48.9 % , 如果落 Q 落在双张这边,我们在第 2 圈将牌时,将 Q 打下来的几率只有其中的一半,(如果没打下来,一般会优先选择飞牌),所以确保把 Q 打下来的概率是 2.17%+ 4.35% + 48.9%/2 = 30.97% 。一般想让将牌不丢,一般就要飞牌。当 3 张带 Q 在合适飞牌的方位时,联手只要有 10,9 或者 J 都可以选择飞牌,而且很容易飞中。联手保证有 A,K 没有 Q 的前提下,有 J 概率是 60% ; 没有 J 但是有 10,9 的概率是 16.7% (同时,J 必须在 3 张这边才可以飞,这种情况是 50%) ,合计 60%+16.7% * 50% = 68.4% , 3 张在对我方有利的位置的概率是 50% 。 所以,有 34.2% 的概率可以飞中。

综上所述,联手 8 张将牌,少张 Q 时:

  • 保证将牌不输墩的概率为 30.97% + 44.6% * 34.2% = 46.2 % 。

这个概率是在叫牌过程估算用的,当打牌的时候,因为已经知道 J,10,9 的分布情况了。概率就可以重新计算:

  • 有 J 的时候,飞中而不输墩的概率是 30.97% + 44.6% * 50% = 53.3% 。
  • 有 10,9 的时候,飞中而不输墩的是 30.97% + 44.6% * 25% = 42.1% 。
  • 不适合飞牌的时候。也可以赌 1-4 分布,在第2圈将牌中飞一下。因为 1-4 分布的概率很小,若飞不中,可能会丢两个输墩。所以一般在计算时不考虑这个赌博的因素,只能计算为 48.9%*50% + 2.17% = 26.6%

以上计算还不完全正确,主要是有 10,9 缺 Q,J 的飞牌的情况比较复杂,不想算了,应该对结果影响比较小。

当然,因为叫牌的过程可以提供额外的信息,实际的概率估算会对以上结果做一个修正。

April 30, 2006

一个不简单的概率问题

我们办公室里放了四盒扑克,以前是在休息时玩一种扑克游戏用的。这种玩法需要 8 个人进行,同时用 4 副牌。玩完后我们洗乱放进了 4 个牌盒里。现在流行打桥牌,桥牌只用一副 52 张就够了,所以我决定清一副出来。清牌的时候,偷懒不想把 4 个牌盒里的牌全倒出来,然后我脑子里就出现了这么一个问题。

假设牌是完全洗乱,均匀随机分布在 4 个牌盒里的,而且每个盒子里都是均等的 54 张。那么需要打开几个牌盒,才能有很大几率(>90%)的保证从中得到一整副牌呢?

当时一个帮忙清牌的牌友说,大概打开 2 盒就够了。我的直觉告诉我,2 盒应该不够,3 盒应该勉强吧。但实际情况是,我们从 3 盒牌里只找到了独立的 53 张。第 54 张牌是从第 4 个盒子里找到的。

March 28, 2006

桥牌

周末跟同事打桥牌,打满了16局。倒数第2局成绩最为显赫。对方有局,叫到 4S 被 double。最后打宕6墩,拿了 1700 分 :D

有机会打打桥牌还是很有意思的,跟下围棋的感觉大不一样。对同伴的信任和自己的牌技同样重要吧。