【青训营】- 如何给扑克洗牌才能更公平?

简介: 平常在日常生活中,我们总会遇到公平性这个话题。比如,几个人分奖品,怎么样才能公平分配?又或者,年会来个抽奖转盘,怎么样才能让它更公平呢?那在下面这篇文章呢,我们将谈论关于洗牌的公平性。一起来了解吧~

30.png📻前言


平常在日常生活中,我们总会遇到公平性这个话题。比如,几个人分奖品,怎么样才能公平分配?又或者,年会来个抽奖转盘,怎么样才能让它更公平呢?

那在下面这篇文章呢,我们将谈论关于洗牌的公平性。一起来了解吧~


一、🎙️需求分析 - 洗牌问题


有时候我们在闲暇之余可能会打打斗地主之类的扑克游戏,但是这扑克要怎么去洗牌,才能不失公平性呢?

31.png

那么接下来,我们由浅入深的来讲解一种实现效果。


二、💿实现版本


1. 版本一:常规思维


先附上代码:

JS 代码:

const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
  return [...cards].sort(() => Math.random() > 0.5 ? -1 : 1);
}
console.log(shuffle(cards)); // [5, 4, 3, 2, 1, 9, 0, 6, 8, 7]
复制代码

如果说要公平,那很多小伙伴刚开始想的应该是随机打乱。但是其实 Math.random() 并不能真正起到真正的随机。

它的随机性跟原来的位置相关,它是随机的去交换原来两个数的位置,而这个位置是否会产生交换的不确定性也很大,所以它并没办法达到真正的公平。


2. 版本二:验证公平性

先附上代码:

JS 代码:

const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
  return [...cards].sort(() => Math.random() > 0.5 ? -1 : 1);
}
const result = Array(10).fill(0);
for(let i = 0; i < 1000000; i++) {
  const c = shuffle(cards);
  for(let j = 0; j < 10; j++) {
    result[j] += c[j];
  }
}
console.log(result);
复制代码

依据版本一的例子,我们来看下它为什么不公平。先看下打印效果:

1.png

大家可以看到,如果这个算法是公平的,那它从第一个数到最后一个数应该都是比较平均的,而在这个算法中,越靠后的数,其数值会越大,所以这个随机性明显是有问题的。一般来说,如果用这个算法的话,排在越后面的同学的中奖概率,会比排在前面的同学的中奖概率要


3. 版本三:交换法则

先附上代码:

JS 代码:

const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
  const c = [...cards];
  for(let i = c.length; i > 0; i--) {
    const pIdx = Math.floor(Math.random() * i);
    [c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
  }
  return c;
} 
//验证是否公平
const result = Array(10).fill(0);
for(let i = 0; i < 10000; i++) {
  const c = shuffle(cards);
  for(let j = 0; j < 10; j++) {
    result[j] += c[j];
  }
}
console.log(shuffle(cards));
console.log(result);
复制代码

基于前面两个版本的瑕疵,我们来实现一种公平的写法。上面的这种算法呢,其复杂度是 O(n) ,它的实现逻辑是,在整个有序数组中,先随机抽取任意一个数,把它放到最后的位置,之后再随机抽取任意一个数,再把它换到最后一个位置进行交换,以此类推。具体思路如下图所示:

2.png

下面来看控制台打印效果:

3.png

大家可以看到,控制台打印出来的数都是相对比较平均的,而不会前后差异特别大。所以,这个算法是公平的。


三、📺在线Online


以上三个版本的在线地址:


四、📹结束语


在上面的文章中,我们首先谈论了平常常用的随机洗牌法的不公平性,之后重新介绍了一种新的交换法则来实现洗牌的公平性。不知道大家对洗牌问题是否有了进一步了解呢?

如果您觉得这篇文章有帮助到您的的话不妨点赞支持一下哟~~😉


相关文章
|
2月前
|
算法 JavaScript C++
如何给扑克洗牌才能更公平
该文章讨论了在线桌游中实现公平洗牌的算法,介绍了几种随机化技术来确保卡牌或游戏元素的排列真正随机,从而保证游戏的公正性和玩家体验。
【每日一道智力题】之 赛马找最快
【每日一道智力题】之 赛马找最快
204 0
|
算法
小玩意 - 抢红包算法(公平版 & 手速版)
小玩意 - 抢红包算法(公平版 & 手速版)
264 0
小玩意 - 抢红包算法(公平版 & 手速版)
|
存储 算法
蛋蛋惨遭数组滑铁卢,面试官建议回村养猪。
蛋蛋惨遭数组滑铁卢,面试官建议回村养猪。
蛋蛋惨遭数组滑铁卢,面试官建议回村养猪。
|
Java
线程的故事:我的3位母亲成就了优秀的我!(1)
线程的故事:我的3位母亲成就了优秀的我!(1)
107 0
|
物联网 区块链
2018 展望 | 区块链:第一个高(泡)峰(沫)后,要迈几道坎?
区块链就像个成长中的孩子:该夸的时候要夸,该喂的时候要喂。但该吃的苦头,该碰的壁,也一样少不了。
1370 0
|
算法
算法学习之路|马踏过河足
A 点有一个过河卒,需要走到目标 B 点。卒行走规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如上图的 C 点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点。例如上图 CC 点上的马可以控制 9 个点(图中的 P1,P2⋯P8和 C)。卒不能通过对方马的控制点。
1678 0
|
算法 程序员 索引
【智力题】数字游戏2
有16枚硬币。双方轮流从中取走1枚、2枚或者4枚硬币,谁取最后一枚硬币就算输。请分析游戏的策略。可以将游戏转化为:轮流说出数字1或2或4并累加,先加到16的人输。从后往前推:我——>15他——>14\13\11我——>12他——>11\10\8我——>9他——>8\7\5我——>6他——>5\4\2我——>3可以找出一些规律。
1134 0