用Python實現(xiàn)2024年春晚劉謙魔術(shù)
簡介
這是新春的第一篇,今天早上睡到了自然醒,打開手機刷視頻就被劉謙的魔術(shù)所吸引,忍不住用編程去模擬一下這個過程。
首先,聲明的一點,大年初一不學(xué)習(xí),所以這其中涉及的數(shù)學(xué)原理約瑟夫環(huán)大家可以找找其他的教程看看,我這塊只是復(fù)現(xiàn)它魔術(shù)里面的每個步驟。
魔術(shù)的步驟
總而言之,可以分為以下8個步驟:
Step 1: 將四張4張牌撕成兩半,直接將兩堆疊放;
Step 2: 假設(shè)姓名為n個字,重復(fù)n次,將堆在最上的牌放到最下面;
Step 3: 將牌堆最上的3張拿出,不改變順序,并隨機插入牌堆中間;
Step 4: 將牌堆最上方的牌拿走,放在一旁;
Step 5: 按照南/北/不知道是南或者北方地區(qū),判斷自己屬于哪一地區(qū),并分別將牌堆最上的1/2/3,不改變順序,并隨機插入牌堆中間;
Step 6: 按性別男/女,從牌堆最上方拿走1/2張牌,一邊念口訣:“見證奇跡的時刻”,每念一個字,將牌堆最上方的牌放到牌堆最下;
Step 7: 念口訣“好運留下米”時,將牌堆最上的牌放到牌堆最下;念“煩惱扔出去”時,將牌堆最上方的牌移除。重復(fù)這兩句口訣,直到手中只有一張牌;
Step 8: 最后留下的牌和Step 4拿走的牌是一樣的。
過程拆開分來其實就是對列表進(jìn)行一個簡單的操作了
用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. 假設(shè)姓名為n個字,重復(fù)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} 重復(fù)姓名字?jǐn)?shù)次后的牌堆:", split_cards_repeated)
夏天是冰紅茶 重復(fù)姓名字?jǐn)?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. 念口訣“好運留下米”時,將牌堆最上的牌放到牌堆最下;念“煩惱扔出去”時,將牌堆最上方的牌移除。重復(fù)這兩句口訣,直到手中只有一張牌;最后留下的牌和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: 設(shè)你的姓名為n個字,重復(fù)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} 重復(fù)姓名字?jǐn)?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: 念口訣“好運留下米”時,將牌堆最上的牌放到牌堆最下;念“煩惱扔出去”時,將牌堆最上方的牌移除。重復(fù)這兩句口訣,直到手中只有一張牌; 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后男生拿走的牌總是會在對應(yīng)的第5位,女生拿走的牌總是會在對應(yīng)的第3位。
結(jié)語
其實說實話,這種數(shù)學(xué)魔術(shù)在我小時候買的書里就曾經(jīng)看到過許多。雖然現(xiàn)在了解了其中的數(shù)學(xué)原理,但當(dāng)時的驚奇與歡樂感覺依然難以忘懷。劉謙老師在表演中展現(xiàn)了非凡的技藝,不僅僅是數(shù)學(xué)的巧妙運用,更是他善于抓住觀眾的好奇心,創(chuàng)造出讓人難以置信的奇跡。
以上就是用Python實現(xiàn)2024年春晚劉謙魔術(shù)的詳細(xì)內(nèi)容,更多關(guān)于Python春晚劉謙魔術(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實現(xiàn)的簡單文件傳輸服務(wù)器和客戶端
這篇文章主要介紹了Python實現(xiàn)的簡單文件傳輸服務(wù)器和客戶端,本文直接給出Server和Client端的實現(xiàn)代碼,需要的朋友可以參考下2015-04-04如何使用matplotlib讓你的數(shù)據(jù)更加生動
數(shù)據(jù)可視化用于以更直接的表示方式顯示數(shù)據(jù),并且更易于理解,下面這篇文章主要給大家介紹了關(guān)于如何使用matplotlib讓你的數(shù)據(jù)更加生動的相關(guān)資料,需要的朋友可以參考下2021-11-11Python數(shù)學(xué)建模學(xué)習(xí)模擬退火算法旅行商問題示例解析
模擬退火算法不僅可以解決連續(xù)函數(shù)優(yōu)化問題,KIRKPATRICK在1983年成功將其應(yīng)用于求解組合優(yōu)化問題,現(xiàn)已成為求解旅行商問題的常用方法,通常采用反序、移位和交換等操作算子產(chǎn)生新解2021-10-10python 篩選數(shù)據(jù)集中列中value長度大于20的數(shù)據(jù)集方法
今天小編就為大家分享一篇python 篩選數(shù)據(jù)集中列中value長度大于20的數(shù)據(jù)集方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06Python+Flask實現(xiàn)自定義分頁的示例代碼
分頁操作在web開發(fā)中幾乎是必不可少的,而flask不像django自帶封裝好的分頁操作。所以本文將自定義實現(xiàn)分頁效果,需要的可以參考一下2022-09-09python使用ctypes調(diào)用第三方庫時出現(xiàn)undefined?symbol錯誤詳解
python中時間的庫有time和datetime,pandas也有提供相應(yīng)的時間處理函數(shù),下面這篇文章主要給大家介紹了關(guān)于python使用ctypes調(diào)用第三方庫時出現(xiàn)undefined?symbol錯誤的相關(guān)資料,需要的朋友可以參考下2023-02-02macbook如何徹底刪除python的實現(xiàn)方法
本文主要介紹了macbook如何徹底刪除python的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07