当随机不够随机:一个在线扑克游戏的教训
今天我要讲一个发生于1999年,一个很流行的在线扑克平台的开发者开发的洗牌软件,带有很微小但很致命的漏洞的故事。虽然这个故事已经15年了,但它给算法开发者带来的教训仍有重要意义。
在随机数产生器或算法中,很容易出现一些微小的漏洞,但这些漏洞可能会导致灾难性的结果。在线扑克和真正的扑克一样,是以洗牌开始的。保证洗牌的随机性尤为重要。
一副正常的牌有52张,并且各不相同,这样就有52!,也就是 8.0658×10^67种不同的洗牌方式。这是一个巨大的数字。
1999年,asf软件公司发布了这个软件,支持那个年代许多流行的在线扑克平台。他们发布了洗牌算法。
算法如下, 看看能否找到不对的地方。
1 procedure TDeck.Shuffle; 2 var 3 ctr: Byte; 4 tmp: Byte; 5 6 random_number: Byte; 7 begin 8 { Fill the deck with unique cards } 9 for ctr := 1 to 52 do 10 Card[ctr] := ctr; 11 12 { Generate a new seed based on the system clock } 13 randomize; 14 15 { Randomly rearrange each card } 16 for ctr := 1 to 52 do begin 17 random_number := random(51)+1; 18 tmp := card[random_number]; 19 card[random_number] := card[ctr]; 20 card[ctr] := tmp; 21 end; 22 23 CurrentCard := 1; 24 JustShuffled := True; 25 end;
错误1: 差一错误
上述算法试图遍历所有牌,将每一张牌跟另外一张随机选择的牌进行交换。但是犯了每个程序员都犯过的错误——差一错误。函数random(n)返回一个0到n-1之间的随机数,而不是程序员所想的1到n之间的。因此,这个算法中第52张牌永远不会和他自己进行交换,也就是说第52张牌永远不会停在第52个位置。这是随机洗牌不够随机的第一个原因。
错误2:洗牌不均匀
上述算法将第i张牌和 另外一张从整副也就是52张牌中随机选择的牌进行交换。而合适的洗牌算法应该只和第i到第n张牌中的一张进行交换。这是因为考虑到每一张牌应该只进行一次随机交换。一副牌有n!种不同的排列,合适的洗牌算法应该只产生每种排列一次。原算法使一些排列出现的概率明显高于另一些排列,是个不好的实现。
错误3:32位种子
如果你的业务或技术依赖于随机数的使用,最好的选择是采用一个硬件随机数产生器。ASF却不是,他用了一个带有伪随机数产生器的确定机。更糟糕的是,他使用的是32位的种子。由于种子100%的决定了伪随机数产生器的输出,只有N^32种可能的种子值就意味着只有N^32种可能的打乱顺序。所以在理论上有8.0658×10^67 种打乱顺序的情况下,他只有4百万可能。
错误4:系统时钟作为种子
上述算法使用Pascal函数Randomize()生成随机数,而这个函数是根据从午夜开始的毫秒数来选择种子的。由于一天之中只有86,400,000毫秒,也就意味着上述算法只能产生86,400,000种可能的乱序。
但更糟糕的是,由于随机数产生器的种子是基于服务器时钟的,黑客们只要将他们的程序与服务器时钟同步就能够将可能出现的乱序减少到只有200,000种。到那个时候一旦黑客知道5张牌,他就可以实时的对200,000种可能的乱序进行快速搜索,找到游戏中的那种。所以一旦黑客知道手中的两张牌和3张公用牌,就可以猜出转牌和河牌时会来什么牌,以及其他玩家的牌。(伯乐在线注:在德州扑克中,倒数第二张公共牌,叫“转牌”,最后一张牌,叫“河牌”。)
以《算法》的作者Robert Sedgewick的一段话作为结束语:
“That’s a pretty tough thing to have happen if you’re implementing online poker. You might want to make sure that if you’re advertising that you’re doing a random shuffle that you go ahead and do so.”—Robert Sedgewick, Professor of Computer Science, Princeton
原文链接: lauradhamilton 翻译: 伯乐在线 - Hibiscus
译文链接: http://blog.jobbole.com/64897/
转载于:https://www.cnblogs.com/flowerH/p/3680791.html
当随机不够随机:一个在线扑克游戏的教训相关推荐
- 比特币base58源码解析_中本聪源码早期版本流出:区块链原名时间链,比特币内置虚拟扑克游戏...
本文来自 Bitcoin.com,原文作者:Jamie Redman Odaily 星球日报译者 | Moni 本周,一个比特币源代码早期版本浮出水面,立刻引起了加密货币社区的热议.根据"中 ...
- 8个免费在线编程游戏网站,让每个人都可以学习编程
我的新书<Android App开发入门与实战>已于2020年8月由人民邮电出版社出版,欢迎购买.点击进入详情 文章目录 CodeMonkey CodinGame Flexbox Frog ...
- Java黑皮书课后题第7章:***7.35(游戏:猜字词游戏)编写一个猜字词游戏,随机产生一个单词,当用户猜测正确后,正确的字母显示出来。当用户猜出一个单词,显示猜错的次数,并询问用户是否继续猜测
***7.35(游戏:猜字词游戏)编写一个猜字词游戏,随机产生一个单词,当用户猜测正确后,正确的字母显示出来.当用户猜出一个单词,显示猜错的次数,并询问用户是否继续猜测 题目 题目描述与运行示例 破题 ...
- ColorCode是一个在线随机取色工具,可以随机获取十六进制、RGB、HSl等颜色。
ColorCode是一个在线随机取色工具,可以随机获取十六进制.RGB.HSl等颜色. ColorCode 彩蛋爆料直击现场 ColorCode是一个在线随机取色工具,可以随机获取十六进制.RGB.H ...
- python 类的简单应用--一个简单的扑克游戏
扑克小游戏 学python刚学到类的时候无意间看到有人说作了一个扑克牌的游戏 然后一时兴起试着写了一个简单的比大小的游戏,顺便找一下多年逢赌必输的真相 o.o 下面贴出来的是在python3.6当中运 ...
- js 随机1-10随机数_寻找随机的错误-一个真实的故事
js 随机1-10随机数 几周前,我完成了RapidFTR开源项目的错误查找 ,这花了我三个晚上. 我认为可能值得分享狩猎的故事. 本文将介绍我的工作. 我将概述我的旅程,以便真正找到正在发生的事情的 ...
- 寻找随机的错误-一个真实的故事
几周前,我完成了RapidFTR开源项目的错误查找 ,这花了我三个晚上. 我认为可能值得分享狩猎的故事. 本文将介绍我的工作. 我将概述我的旅程,以实际找到正在发生的事情的根本原因. 我在本文中的目标 ...
- python随机生成一个日期_Python中随机生成未来一个月内的一个随机的日期时间
该函数可以产生从当前日期时间开始到未来一个月内的一个固定时间 import random import timeit import time import datetime #该函数随机生成未来一个月 ...
- 编写程序,生成一种贯穿10*10字符数组(初始时全为字符'.')的“随机步法”。程序必须随机地从一个元素“走到”另一个元素,每次都向上、向下、向左或向右移动一个元素位置
编写程序,生成一种贯穿10*10字符数组(初始时全为字符'.')的"随机步法".程序必须随机地从一个元素"走到"另一个元素,每次都向上.向下.向左或向右移动一个 ...
最新文章
- Android 5.x Theme 与 ToolBar 实战
- Npm install failed with “cannot run in wd”
- 利用一维数组输出杨辉三角
- Springboot 项目中过滤器的使用
- Could not find acceptable representation
- 代码没写完,哪里有脸睡觉!17 张程序员壁纸推荐
- 计算机专业教师演讲稿,计算机部教师会议发言稿范文
- verilog之按键消抖的理解
- MySQL数据库:参数优化
- vijos1697——平面几何
- 【裴礼文数学分析】例1.2.4
- Mediawiki页面权限设置 禁止游客编辑 禁止注册
- 联想服务器配置 RAID
- 机器阅读理解论文必读论文(二): Teaching Machines to Read and Comprehend
- 微信开发公众号本地调试
- Word图表的中英题注及引用
- CSS实现元素翻转效果
- 利用HTML和javaScript实现简单的加减乘除运算
- VS2010/MFC对话框程序调用Windows Media Player播放器控件
- Python+selenium WebDriver API
热门文章
- Git 提示fatal: remote origin already exists 错误解决办法
- CISP-PTE注册信息安全专业人员渗透测试工程师知识体系大纲
- CentOS7.3的基本配置(建议学习用)
- 如何快速接手一个系统?
- HDU1226 搜索 bfs xingxing在努力
- 如何使用Web.config的authentication节实现Form认证
- cxTreeList交换当前两个节点的的位置
- spring springboot websocket 不能注入( @Autowired ) service bean 报 null 错误
- CentOS查看CPU、内存、版本等系统信息
- [BZOJ1030] [JSOI2007]文本生成器