用Python實現(xiàn)2024年春晚劉謙魔術(shù)
簡介
這是新春的第一篇,今天早上睡到了自然醒,打開手機刷視頻就被劉謙的魔術(shù)所吸引,忍不住用編程去模擬一下這個過程。
首先,聲明的一點,大年初一不學習,所以這其中涉及的數(shù)學原理約瑟夫環(huán)大家可以找找其他的教程看看,我這塊只是復現(xiàn)它魔術(shù)里面的每個步驟。
魔術(shù)的步驟
總而言之,可以分為以下8個步驟:
Step 1: 將四張4張牌撕成兩半,直接將兩堆疊放;
Step 2: 假設姓名為n個字,重復n次,將堆在最上的牌放到最下面;
Step 3: 將牌堆最上的3張拿出,不改變順序,并隨機插入牌堆中間;
Step 4: 將牌堆最上方的牌拿走,放在一旁;
Step 5: 按照南/北/不知道是南或者北方地區(qū),判斷自己屬于哪一地區(qū),并分別將牌堆最上的1/2/3,不改變順序,并隨機插入牌堆中間;
Step 6: 按性別男/女,從牌堆最上方拿走1/2張牌,一邊念口訣:“見證奇跡的時刻”,每念一個字,將牌堆最上方的牌放到牌堆最下;
Step 7: 念口訣“好運留下米”時,將牌堆最上的牌放到牌堆最下;念“煩惱扔出去”時,將牌堆最上方的牌移除。重復這兩句口訣,直到手中只有一張牌;
Step 8: 最后留下的牌和Step 4拿走的牌是一樣的。
過程拆開分來其實就是對列表進行一個簡單的操作了
用python實現(xiàn)其中的過程
0. 模擬撲克牌打亂并抽取的過程;
import random
import itertools
import copy
# 定義撲克牌
suits = ['紅桃', '方塊', '梅花', '黑桃']
ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
jokers = ['小王', '大王']
deck_of_cards = list(itertools.product(suits, ranks)) + jokers
random.shuffle(deck_of_cards) # 模擬打亂的操作
print(f"隨機生成的{len(deck_of_cards)}撲克牌:", deck_of_cards)
selected_cards = random.sample(deck_of_cards, 4)
print("隨機抽取其中的四張牌:", selected_cards)隨機抽取其中的四張牌: [('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'A'), ('黑桃', 'K')]
1. 將四張4張牌撕成兩半,直接將兩堆疊放;
def split_and_stack(cards):
cards_copy = copy.copy(cards)
merged_cards = cards + cards_copy
return merged_cards
split_cards = split_and_stack(selected_cards)
print("撕成兩半后堆疊:", split_cards)撕成兩半后堆疊: [('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'A'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'A'), ('黑桃', 'K')]
2. 假設姓名為n個字,重復n次,將堆在最上的牌放到最下面;
def repeat_name(cards, name):
name_length = len(name)
for _ in range(name_length):
# 取出堆在最上的牌,放到最下面
top_card = cards.pop(0)
cards.append(top_card)
return cards
split_cards_repeated = repeat_name(split_cards, name)
print(f"{name} 重復姓名字數(shù)次后的牌堆:", split_cards_repeated)夏天是冰紅茶 重復姓名字數(shù)次后的牌堆: [('黑桃', 'A'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'A'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', '8')]
3. 將牌堆最上的3張拿出,不改變順序,并隨機插入牌堆中間;
def take_top_and_insert(cards):
top_three_cards = cards[:3] # 取出最上面的3張牌
remaining_cards = cards[3:] # 剩下的牌
insert_index = random.randint(1, len(remaining_cards))
shuffled_cards = remaining_cards[:insert_index] + top_three_cards + remaining_cards[insert_index:]
return shuffled_cards
shuffled_cards = take_top_and_insert(split_cards_repeated)
print("牌堆最上的3張拿出,隨機插入后的牌堆:", shuffled_cards)牌堆最上的3張拿出,隨機插入后的牌堆: [('黑桃', '8'), ('黑桃', 'A'), ('黑桃', 'A'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', '8')]
4. 將牌堆最上方的牌拿走,放在一旁;
def take_top_card(cards):
top_card = cards.pop(0) # 取出最上方的牌
return top_card
top_card = take_top_card(shuffled_cards)
print("拿走的牌:", top_card)
print("剩余的牌:", shuffled_cards)拿走的牌: ('黑桃', '8')
剩余的牌: [('黑桃', 'A'), ('黑桃', 'A'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', '8')]
5. 按照南/北/不知道是南或者北方地區(qū),判斷自己屬于哪一地區(qū),并分別將牌堆最上的1/2/3,不改變順序,并隨機插入牌堆中間;
def insert_cards_based_on_region(cards, region):
if region == "南":
insert_count = 1
elif region == "北":
insert_count = 2
else:
insert_count = 3
top = cards[:insert_count]
remaining_cards = cards[insert_count:]
insert_index = random.randint(0, len(remaining_cards)-1)
shuffled_cards = remaining_cards[:insert_index] + top + remaining_cards[insert_index:]
return shuffled_cards
shuffled_cards_region = insert_cards_based_on_region(shuffled_cards, region)
print(f"{region}方地區(qū)插入后的牌堆:", shuffled_cards_region)南方地區(qū)插入后的牌堆: [('黑桃', 'A'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'K'), ('黑桃', 'A'), ('紅桃', '9'), ('黑桃', '8')]
6. 按性別男/女,從牌堆最上方拿走1/2張牌,一邊念口訣:“見證奇跡的時刻”,每念一個字,將牌堆最上方的牌放到牌堆最下;
def take_and_chant(cards, gender, chant="見證奇跡的時刻"):
take_count = 0
if gender == "男":
take_count = 1
elif gender == "女":
take_count = 2
else:
print("未知性別")
remaining_cards = cards[take_count:] # 剩下的牌
print(remaining_cards)
# 念口訣過程
for c in chant:
remaining_cards.append(remaining_cards.pop(0)) # 將最上方的牌放到牌堆最下
return remaining_cards
remaining_cards= take_and_chant(shuffled_cards_region, gender, chant)
print(f"剩余的牌堆:", remaining_cards)[('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'K'), ('黑桃', 'A'), ('紅桃', '9'), ('黑桃', '8')]
剩余的牌堆: [('紅桃', '9'), ('黑桃', 'K'), ('黑桃', 'A'), ('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'K')]
7/8. 念口訣“好運留下米”時,將牌堆最上的牌放到牌堆最下;念“煩惱扔出去”時,將牌堆最上方的牌移除。重復這兩句口訣,直到手中只有一張牌;最后留下的牌和Step 4拿走的牌是一樣的。
def chant_and_modify(cards):
iter = 1
while len(cards) > 1:
chant_good_luck = "好運留下米"
chant_throw_away = "煩惱扔出去"
print(f"\n第{iter}輪口訣開始:")
cards.append(cards.pop(0))
print(f"口訣{chant_good_luck}結(jié)束后手上的牌:", cards)
cards.pop(0)
print(f"口訣{chant_throw_away}結(jié)束后手上的牌:", cards)
iter += 1
return cards[0]
final_card = chant_and_modify(remaining_cards)
print(f"\n最終留下的牌:{final_card}, Step 4:{top_card}")第1輪口訣開始:
口訣好運留下米結(jié)束后手上的牌: [('黑桃', 'K'), ('黑桃', 'A'), ('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'K'), ('紅桃', '9')]
口訣煩惱扔出去結(jié)束后手上的牌: [('黑桃', 'A'), ('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'K'), ('紅桃', '9')]
第2輪口訣開始:
口訣好運留下米結(jié)束后手上的牌: [('紅桃', '9'), ('黑桃', '8'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'A')]
口訣煩惱扔出去結(jié)束后手上的牌: [('黑桃', '8'), ('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'A')]
第3輪口訣開始:
口訣好運留下米結(jié)束后手上的牌: [('黑桃', 'K'), ('紅桃', '9'), ('黑桃', 'A'), ('黑桃', '8')]
口訣煩惱扔出去結(jié)束后手上的牌: [('紅桃', '9'), ('黑桃', 'A'), ('黑桃', '8')]
第4輪口訣開始:
口訣好運留下米結(jié)束后手上的牌: [('黑桃', 'A'), ('黑桃', '8'), ('紅桃', '9')]
口訣煩惱扔出去結(jié)束后手上的牌: [('黑桃', '8'), ('紅桃', '9')]
第5輪口訣開始:
口訣好運留下米結(jié)束后手上的牌: [('紅桃', '9'), ('黑桃', '8')]
口訣煩惱扔出去結(jié)束后手上的牌: [('黑桃', '8')]
最終留下的牌:('黑桃', '8'), Step 4:('黑桃', '8')
完整的代碼
import random
import itertools
import copy
# 定義撲克牌
suits = ['紅桃', '方塊', '梅花', '黑桃']
ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
jokers = ['小王', '大王']
deck_of_cards = list(itertools.product(suits, ranks)) + jokers
random.shuffle(deck_of_cards) # 模擬打亂的操作
print(f"隨機生成的{len(deck_of_cards)}撲克牌:", deck_of_cards)
selected_cards = random.sample(deck_of_cards, 4)
print("隨機抽取其中的四張牌:", selected_cards)
# 模擬性別為男的情況
name = "夏天是冰紅茶"
gender = "男"
chant = "見證奇跡的時刻"
region = "南"
# step 1: 將四張4張牌撕成兩半,直接將兩堆疊放;
def split_and_stack(cards):
cards_copy = copy.copy(cards)
merged_cards = cards + cards_copy
return merged_cards
split_cards = split_and_stack(selected_cards)
print("撕成兩半后堆疊:", split_cards)
# Step 2: 設你的姓名為n個字,重復n次,將堆在最上的牌放到最下面;
def repeat_name(cards, name):
name_length = len(name)
for _ in range(name_length):
# 取出堆在最上的牌,放到最下面
top_card = cards.pop(0)
cards.append(top_card)
return cards
split_cards_repeated = repeat_name(split_cards, name)
print(f"{name} 重復姓名字數(shù)次后的牌堆:", split_cards_repeated)
# Step 3: 將牌堆最上的3張拿出,不改變順序,并隨機插入牌堆中間
def take_top_and_insert(cards):
top_three_cards = cards[:3] # 取出最上面的3張牌
remaining_cards = cards[3:] # 剩下的牌
insert_index = random.randint(1, len(remaining_cards))
shuffled_cards = remaining_cards[:insert_index] + top_three_cards + remaining_cards[insert_index:]
return shuffled_cards
shuffled_cards = take_top_and_insert(split_cards_repeated)
print("牌堆最上的3張拿出,隨機插入后的牌堆:", shuffled_cards)
# Step 4: 將牌堆最上方的牌拿走,放在一旁
def take_top_card(cards):
top_card = cards.pop(0) # 取出最上方的牌
return top_card
top_card = take_top_card(shuffled_cards)
print("拿走的牌:", top_card)
print("剩余的牌:", shuffled_cards)
# Step 5: 按照南/北/不知道是南或者北方地區(qū),判斷自己屬于哪一地區(qū),并分別將牌堆最上的1/2/3,不改變順序,并隨機插入牌堆中間
def insert_cards_based_on_region(cards, region):
if region == "南":
insert_count = 1
elif region == "北":
insert_count = 2
else:
insert_count = 3
top = cards[:insert_count]
remaining_cards = cards[insert_count:]
insert_index = random.randint(0, len(remaining_cards)-1)
shuffled_cards = remaining_cards[:insert_index] + top + remaining_cards[insert_index:]
return shuffled_cards
shuffled_cards_region = insert_cards_based_on_region(shuffled_cards, region)
print(f"{region}方地區(qū)插入后的牌堆:", shuffled_cards_region)
# Step 6: 按性別男/女,從牌堆最上方拿走1/2張牌,一邊念口訣:“見證奇跡的時刻”,每念一個字,將牌堆最上方的牌放到牌堆最下。
def take_and_chant(cards, gender, chant="見證奇跡的時刻"):
take_count = 0
if gender == "男":
take_count = 1
elif gender == "女":
take_count = 2
else:
print("未知性別")
remaining_cards = cards[take_count:] # 剩下的牌
print(remaining_cards)
# 念口訣過程
for c in chant:
remaining_cards.append(remaining_cards.pop(0)) # 將最上方的牌放到牌堆最下
return remaining_cards
remaining_cards= take_and_chant(shuffled_cards_region, gender, chant)
print(f"剩余的牌堆:", remaining_cards)
# Step 7: 念口訣“好運留下米”時,將牌堆最上的牌放到牌堆最下;念“煩惱扔出去”時,將牌堆最上方的牌移除。重復這兩句口訣,直到手中只有一張牌;
def chant_and_modify(cards):
iter = 1
while len(cards) > 1:
chant_good_luck = "好運留下米"
chant_throw_away = "煩惱扔出去"
print(f"\n第{iter}輪口訣開始:")
cards.append(cards.pop(0))
print(f"口訣{chant_good_luck}結(jié)束后手上的牌:", cards)
cards.pop(0)
print(f"口訣{chant_throw_away}結(jié)束后手上的牌:", cards)
iter += 1
return cards[0]
# Step 8: 最后留下的牌和Step 4拿走的牌是一樣的。
final_card = chant_and_modify(remaining_cards)
print(f"\n最終留下的牌:{final_card}, Step 4:{top_card}")大家可以自己去試一試,在步驟6后男生拿走的牌總是會在對應的第5位,女生拿走的牌總是會在對應的第3位。
結(jié)語
其實說實話,這種數(shù)學魔術(shù)在我小時候買的書里就曾經(jīng)看到過許多。雖然現(xiàn)在了解了其中的數(shù)學原理,但當時的驚奇與歡樂感覺依然難以忘懷。劉謙老師在表演中展現(xiàn)了非凡的技藝,不僅僅是數(shù)學的巧妙運用,更是他善于抓住觀眾的好奇心,創(chuàng)造出讓人難以置信的奇跡。
以上就是用Python實現(xiàn)2024年春晚劉謙魔術(shù)的詳細內(nèi)容,更多關(guān)于Python春晚劉謙魔術(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何使用matplotlib讓你的數(shù)據(jù)更加生動
數(shù)據(jù)可視化用于以更直接的表示方式顯示數(shù)據(jù),并且更易于理解,下面這篇文章主要給大家介紹了關(guān)于如何使用matplotlib讓你的數(shù)據(jù)更加生動的相關(guān)資料,需要的朋友可以參考下2021-11-11
Python數(shù)學建模學習模擬退火算法旅行商問題示例解析
模擬退火算法不僅可以解決連續(xù)函數(shù)優(yōu)化問題,KIRKPATRICK在1983年成功將其應用于求解組合優(yōu)化問題,現(xiàn)已成為求解旅行商問題的常用方法,通常采用反序、移位和交換等操作算子產(chǎn)生新解2021-10-10
python 篩選數(shù)據(jù)集中列中value長度大于20的數(shù)據(jù)集方法
今天小編就為大家分享一篇python 篩選數(shù)據(jù)集中列中value長度大于20的數(shù)據(jù)集方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06
Python+Flask實現(xiàn)自定義分頁的示例代碼
分頁操作在web開發(fā)中幾乎是必不可少的,而flask不像django自帶封裝好的分頁操作。所以本文將自定義實現(xiàn)分頁效果,需要的可以參考一下2022-09-09
python使用ctypes調(diào)用第三方庫時出現(xiàn)undefined?symbol錯誤詳解
python中時間的庫有time和datetime,pandas也有提供相應的時間處理函數(shù),下面這篇文章主要給大家介紹了關(guān)于python使用ctypes調(diào)用第三方庫時出現(xiàn)undefined?symbol錯誤的相關(guān)資料,需要的朋友可以參考下2023-02-02
macbook如何徹底刪除python的實現(xiàn)方法
本文主要介紹了macbook如何徹底刪除python的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07

