【Python】Magician“专属”神秘的“读心术”
貼吧里有這樣一個題目
下面樓主的補發:
這種魔術看起來是有魔術師有“讀心術”?
實際上不然。
奧秘在于助手的出牌順序,這背后有一套算法,展示后魔術師經過計算已經知道了最后一張牌的值(每張牌有一個編號),對應的可以找到隱藏的牌。
我的思路是這樣的(這是編程設計算法的思路,查閱過一些資料總結的):
首先只有4種花色,抽5張牌,根據鴿巢原理(鴿洞原理),必定有重花色的情況出現。
然后一種花色只有13張牌,圍成一個圈,最遠的距離是6(雙向可達)。
So,我們作如下規約:
- 藏匿的卡牌花色與第一張相同
- 藏匿卡牌的字面值與第一張相距在1~6之間(畢竟不能重復,0是不存在的)
- 1~6 的距離由第2張~第4張展示的牌的大小順序呈現(按照編號而不是字面值)
- (小->中->大)= 1
- (小->大->中)= 2
- (中->小->大)= 3
- (中->大->小)= 4
- (大->小->中)= 5
- (大->中->小)= 6
- 編號順序花色從Club(梅花)->Diamond(方片)->Heart(紅心)->Spade(黑桃)
- 花色內部編號從小到大A->2->3->…->K(與斗地主不同啊)
- 依據先補滿同字面值的花色再往后延伸字面值到K的順序來編號
規約就是這樣,然后就可以搞事情了嘿嘿嘿~~~
下面放出來Python描述的代碼實現:
# 你可以讀心術——隨機抽取五張牌,其中一張隱藏起來,按照特定的順序給四張牌,你就能知道第五張牌是什么!# deck是一個字符串列表,每個字符串是一張卡。名單上卡片的順序很重要!! deck = ['A_C', 'A_D', 'A_H', 'A_S', '2_C', '2_D', '2_H', '2_S','3_C', '3_D', '3_H', '3_S', '4_C', '4_D', '4_H', '4_S','5_C', '5_D', '5_H', '5_S', '6_C', '6_D', '6_H', '6_S','7_C', '7_D', '7_H', '7_S', '8_C', '8_D', '8_H', '8_S','9_C', '9_D', '9_H', '9_S', '10_C', '10_D', '10_H', '10_S','J_C', 'J_D', 'J_H', 'J_S', 'Q_C', 'Q_D', 'Q_H', 'Q_S','K_C', 'K_D', 'K_H', 'K_S']# 給5張牌,助手會藏一張合適的牌,TA仔細挑選了剩下的四張卡片,然后把它們讀出來! def AssistantOrderCards():print('Cards are character strings as shown below.')print('Ordering is:', deck)# 初始化cards, cind, cardsuits, cnumbers = [], [], [], []numsuits = [0, 0, 0, 0]# 將卡片作為用戶/觀眾的輸入# 填寫各種數據結構for i in range(5):print('Please give card', i + 1, end=' ')card = input('in above format: ')cards.append(card)n = deck.index(card)cind.append(n)cardsuits.append(n % 4)cnumbers.append(n // 4)numsuits[n % 4] += 1if numsuits[n % 4] > 1:pairsuit = n % 4# 從5個相同的套裝中找出兩張牌。保證存在cardH = []for i in range(5):if cardsuits[i] == pairsuit:cardH.append(i)# 找出需要隱藏的卡和要編碼的號碼hidden, other, encode = outputFirstCard(cnumbers, cardH, cards)remindices = []for i in range(5):if i != hidden and i != other:remindices.append(cind[i])# 按升序排列這三張牌sortList(remindices)# 給定需要編碼的號碼,對卡片進行適當的排序outputNext3Cards(encode, remindices)return# 這個程序可以根據距離隱藏哪張卡。兩張牌之間有相同的套裝。它返回隱藏卡、第一張暴露卡和距離。 def outputFirstCard(ns, oneTwo, cards):encode = (ns[oneTwo[0]] - ns[oneTwo[1]]) % 13if 0 < encode <= 6:hidden = oneTwo[0]other = oneTwo[1]else:hidden = oneTwo[1]other = oneTwo[0]encode = (ns[oneTwo[1]] - ns[oneTwo[0]]) % 13print('First card is: ', cards[other])return hidden, other, encode# 這個程序根據“編碼”命令三張卡。需要進行編碼。 def outputNext3Cards(code, ind):if code == 1:s, t, f = ind[0], ind[1], ind[2]elif code == 2:s, t, f = ind[0], ind[2], ind[1]elif code == 3:s, t, f = ind[1], ind[0], ind[2]elif code == 4:s, t, f = ind[1], ind[2], ind[0]elif code == 5:s, t, f = ind[2], ind[0], ind[1]else:s, t, f = ind[2], ind[1], ind[0]print('Second card is:', deck[s])print('Third card is:', deck[t])print('Fourth card is:', deck[f])# 升序排列tList的元素 def sortList(tList):for ind in range(0, len(tList)-1):iSm = indfor i in range(ind, len(tList)):if tList[iSm] > tList[i]:iSm = itList[ind], tList[iSm] = tList[iSm], tList[ind]# 這個過程需要正確地編碼四張卡并確定隱藏的卡 def MagicianGuessesCard():print('Cards are character strings are shown as below')print('Ordering is:', deck)cards, cind = [], []for i in range(4):print('Please give card', i+1, end=' ')card = input('in above format:')cards.append(card)n = deck.index(card)cind.append(n)if i == 0:suit = n % 4number = n // 4# 使用最后3張卡的順序來確定與第一張卡的距離if cind[1] < cind[2] and cind[1] < cind[3]:if cind[2] < cind[3]:encode = 1else:encode = 2elif (cind[3] < cind[1] < cind[2]) or (cind[2] < cind[1] < cind[3]):if cind[2] < cind[3]:encode = 3else:encode = 4elif cind[1] > cind[2] and cind[1] > cind[3]:if cind[2] < cind[3]:encode = 5else:encode = 6# 知道號碼和套裝給出卡片索引然后字符串hiddenNumber = (number + encode) % 13index = hiddenNumber * 4 + suitprint('Hidden card is:', deck[index])# 類似于AssistantOrderCards(), 接收大量的卡,然后“隨機”生成五張卡。 def ComputerAssistant():print('Cards are character strings as shown below.')print('Ordering is:', deck)cards, cind, cardsuits, cnumbers = [], [], [], []numsuits = [0, 0, 0, 0]number = 0while number < 99999:number = int(input('Please give random number' +' of at least 6 digits:'))for i in range(5):number = number * (i + 1) // (i + 2)n = number % 52cards.append(deck[n])cind.append(n)cardsuits.append(n % 4)cnumbers.append(n // 4)numsuits[n % 4] += 1if numsuits[n % 4] > 1:pairsuit = n % 4cardH = []for i in range(5):if cardsuits[i] == pairsuit:cardH.append(i)hidden, other, encode = outputFirstCard(cnumbers, cardH, cards)remindices = []for i in range(5):if i != hidden and i != other:remindices.append(cind[i])sortList(remindices)outputNext3Cards(encode, remindices)guess = input('What is the hidden card?')if guess == cards[hidden]:print('You are a Mind Reader Extraordinaire!')else:print('Sorry, not impressed!')returnAssistantOrderCards() MagicianGuessesCard() ComputerAssistant()有三種模式:
AssistantOrderCards()是助手的算法,——助手抽4張牌,可以經過此算法知道何種順序展示哪四張牌(當然了,展示的順序很多種,這是助手跟魔術師約定的“秘鑰”,我們這里只按我們的思路來)。
MagicianGuessesCard()是魔術師的算法——魔術師按照助手展示的順序“讀出”牌的值以及展示順序背后的秘密,算出最后隱藏而他“不知道”的牌。
ComputerAssistant()是沒有助手的魔術師“自行訓練”所用,隨機抽多張卡(輸入大于100000停止),然后猜,看猜得對不對用來檢驗技術達不達標。
OK,終于解決,下面升華一下主題,咳咳~~
這個“讀心術”涉及到了一個 信息編碼 的問題:
這個玩法里有 3! = 6 種排列方式,而一般對于 n! 來說,我們可以通過一個具體排列方式對傳遞的消息進行簡單編碼,普通的監聽者知道有秘密但是他并不能輕易的破解(除非他知道秘鑰,對吧…),而傳遞信息的雙方則可以根據加密解密來傳遞信息,蠻有趣的呢~~
總結
以上是生活随笔為你收集整理的【Python】Magician“专属”神秘的“读心术”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C语言】C语言中一些零碎的基础知识
- 下一篇: 【Java】异常处理的注意事项