13.2 洗牌

大多数扑克牌游戏需要提供洗牌功能,即将牌随机地排列。8.7 节介绍了如何生成随机数,但如何用随机数来洗牌并不那么简单。

一种选择是模拟人工洗牌的方式:通常将整副牌分成两半,再交替地从这两半中取牌。因为人工洗牌通常不能洗得很乱,所以需要重复大约 7 次才能让整副牌的排列顺序相当随机。

但计算机程序有个令人讨厌的特征,就是每次洗牌都能洗得很乱,但不是完全随机的。实际上,程序连续洗 8 次后,牌就会恢复到原来的顺序!有关这方面的更详细信息,请参阅 https://en.wikipedia.org/wiki/Faro_shuffle

一种更佳的洗牌算法是遍历整副牌——每次一张,并在每次迭代中交换两张牌的位置。这种算法的工作原理大致如下。为了大致地描绘程序,我们结合使用了 Java 语句和自然语言,这种组合被称为伪代码(pseudocode):

  1. for each index i {
  2. // 在i和length - 1之间随机地选择一个数字
  3. // 将第i张牌和随机选择的那张牌的位置互换
  4. }

伪代码的优点在于,让你能够清楚地知道需要哪些方法。从上述伪代码可知,你需要两个方法:一个方法要在 lowhigh 之间随机地选择一个数字,另一个方法要接受两个索引并交换这两个索引处的扑克牌。这样的方法被称为辅助方法(helper method),因为它们用于帮助实现更复杂的算法。

这种先编写伪代码,再编写所需方法的过程被称为自上而下的开发(top-down development),更详细的信息请参阅 https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design

本章末尾有一个练习,要求你编写辅助方法 randomIntswapCards,并用它们实现 shuffle