魔术步骤
step1: 准备4张牌,跟随魔术步骤,见证奇迹
step2: 将4张牌平均斯成两份,并叠在一起
step3: 将牌堆顶数量为名字字数的牌移到牌堆底
step4: 将前三张牌放在牌堆中间并取出牌堆顶的一张牌放到屁股下
step5: 南方人、北方人、不确定分别取顶上的1/2/3张牌插入牌堆中间
step6: 男生扔掉牌堆顶1张,女生扔掉牌堆顶2张,沃尔玛塑料袋扔掉牌堆顶1张,不确定的扔掉牌堆顶2张
step7: “见证奇迹的时刻”,每说一个字取出牌堆顶的一张牌放到牌堆底
step8: 从牌堆顶取一张牌放到牌堆底,再扔掉牌堆顶的一张牌,重复以上操作直到只剩下一张牌,检查此牌和屁股底下的牌是否吻合,若吻合,则魔术成功
下面解释下魔术原理
step2: 四张牌斯成两份放在一起就是ABCDABCD
step3: 根据名字将牌放到牌堆底,无论怎么操作,第4张和第8张都是一样的
例如两个字,CDABCDAB
五个字,BCDABCDA
step4: 三张牌放到牌中间,变成AxxxxxxA,牌堆顶A移走,变成
xxxxxxA
step5: 不会改变牌堆顺序
step6: 拿掉一张牌变成xxxxxA,拿掉两张牌变成xxxxA
step7: 把最顶上的牌放最低下,循环7次,变成 xxxxAx和xxAxx
讲解step8之前先引入个约瑟夫环的概念
约瑟夫环(Josephus problem)是一个经典的数学问题,最早由古罗马历史学家弗拉维奥·约瑟夫斯提出,但它的名字是在19世纪由德国数学家约瑟夫·乔瑟夫斯(Josef Stein)命名的。
问题的描述是这样的:假设有n个人(编号从1到n)站成一个圆圈,从第一个人开始报数,报到某个数字(例如m)的人就被杀死,然后从下一个人开始重新报数并继续这个过程,直到只剩下一个人留下来。
那么剩下的这个人的编号可以由下面的递归公式得出。
在我们的这个问题里
男生那边xxxxAx就是一个 N = 6,M = 2 的约瑟夫问题。最后计算出的结果是 5,那么最后第 5 张卡片就会剩下。
女生那边xxAxx就是一个 N = 5,M = 2 的约瑟夫问题。最后计算出的结果是 3,那么最后第 3 张卡片就会剩下。
代码实现
# 导入所需的库
import random
import itertools
import copy
# 定义一个名为CardGame的类
class CardGame:
# 定义初始化函数
def __init__(self):
# 定义四种花色
self.suits = ['红桃', '方块', '梅花', '黑桃']
# 定义十三种牌面
self.ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
# 定义两种大小王
self.jokers = ['小王', '大王']
# 生成一副完整的牌
self.deck_of_cards = list(itertools.product(self.suits, self.ranks)) + self.jokers
# 打乱这副牌
random.shuffle(self