跳至主要内容

撲克牌密碼

· 閱讀時間約 10 分鐘

你是一個間諜(代號「蛋餅俠」),正在執行一個機密任務。目標:傳遞一條重要訊息「九點老地方見面,幫我買蛋餅」傳給你的搭檔(代號「豆漿哥」)。

但情況比預想中的更棘手。你身在人潮湧動的酒吧中,到處有形形色色的目光在遊走,任何一點疏忽都可能暴露你的身份。你該如何把訊息傳出去?

  • 寫小紙條?太冒險了,一旦被發現,多年的臥底生涯就毀於一旦。
  • LINE?別鬧了,你以為政府的監控系統是吃素的嗎?

正當你陷入沉思時,眼角瞄到桌上放著一盒撲克牌。你若無其事地走過去,假裝整理桌面,順手把牌拿了出來。

在其他客人眼中,你只是一個無聊在把玩紙牌的上班族,但其實你的雙手正以訓練有素的技巧,重新排列著這 52 張牌。排列完後,你把牌重新收回盒子裡放在桌上,起身離開酒吧,就像什麼都沒發生過一樣。

半小時後,豆漿哥走進店裡,看似隨意地拿起那副牌,看了幾眼之後,他嘴角微微上揚。

晚上九點整,老地方。豆漿哥準時出現,手裡拿著兩個熱騰騰的蛋餅。

這是什麼爛故事?

不重要啦。重點是蛋餅俠是怎麼做到的。

當然不是直接在牌上做暗號(例如寫字或折起來什麼的),那太明顯了。而是直接用撲克牌的「排列方式本身」來儲存訊息!

一副撲克牌的 52 張牌,有超級多種可能的排列順序,精確地說是 52!(52 的階乘),大約 8 ⋅ 1067 種。既然牌的排列順序本身,就包含了這麼多資訊,那我們有沒有可能把祕密訊息編碼成撲克牌的順序,然後拿到牌的人就可以靠這個排列順序,解碼出原本的文字呢?

Lehmer Code

答案當然是可以的!

有個叫做 Lehmer Code 的演算法,可以把任意的排列順序對應成獨一無二的數字。

簡單來說,52 張牌的每一種排法,都可以用 Lehmer Code 轉換成專屬的數值,而這個數值又可以進一步編碼成文字訊息。反過來操作,任何文字也能先轉成數字,再透過 Lehmer Code 對應到特定的排序。

這樣一來,我們就可以將撲克牌的「排列順序」作為訊息載體了。

舉個實例

例如,你想傳送「HELLO」這個訊息給朋友。具體的步驟如下:

  1. 文字轉數字:把「HELLO」用 ASCII 或其他編碼方式,變成一個超級大的數字,例如:310939249775(這只是舉例,實際數字會有 68 位數)。
  2. 數字轉排列:用 Lehmer Code 把這個巨大數字對應到一個 52 張牌的特定排列順序,例如 紅心K,黑桃7,方塊A,梅花Q……
  3. 實際排牌:把這個順序實際用真的牌排出來。
  4. 傳遞訊息:把這副「看似隨機排列」的撲克牌交給朋友。
  5. 解碼:朋友收到牌後,將完整的排列順序用 Lehmer Code 反推回那個巨大數字 310939249775,再將這個數字以約定好的文字編碼方式轉為文字,就得到「HELLO」了!

撲克牌編碼程式

網路上已經有個叫做 Asher Falcon 的人把這個概念實作出來了,你可以讀他的部落格文章了解他是怎麼做的,也可以到這個網址直接使用他的編碼程式。

但 Falcon 的版本有個致命的缺陷:為了讓傳遞的訊息夠長,它只使用 5 個位元來儲存每個字元。也就是它的訊息內容只能使用 .,-\"/abcdefghijklmnopqrstuvwxyz 這 32 個字元的其中之一,連阿拉伯數字都不能用。身為一個國際化的現代間諜,這種限制怎麼能接受?

所以我重弄了一個使用 UTF-16 編碼的版本,每個字元用 16 位元來儲存,可以支援絕大部分的中文字和表情符號,這樣用一副牌還是能夠放進長度 14 字元的訊息1。用我的版本,就算是要傳「🥞早安我ㄉ朋友おはよう🌸」這樣的訊息也沒問題唷!

原始碼放在:https://code.wiwi.blog/wiwi/text-to-cards

玩玩看!

使用方式:

  • 編碼:輸入一個字串(14 個字元以內),程式會輸出 52 張撲克牌的排列。
  • 解碼:輸入 52 張撲克牌的排列(例如:As 3d Th 8c……),程式會輸出訊息字串。

透過這個程式,你就可以把任何文字訊息藏在一副撲克牌裡面了!

試試看解碼我的訊息吧:

As 3s Js 6c 7s 9s Ad 2d 7d Jc 9c 2s Jd
4h 8s Kc 4c 4s Qc Kh 7c 5h 3d 7h 5s Td
9h 5d Ac Qh 6s Kd Th 3h 9d 2c 6h Ts Jh
5c 8d 6d 3c Qs 8h 2h 4d Ks Qd Tc Ah 8c
0 / 14 字元
等待輸入文字...
等待輸入撲克牌...
準備就緒

Footnotes

  1. 52 張撲克牌的排列順序資訊約是 224 位元,每個字元使用 16 位元的話剛好可以放入 14 個字元。