Python 入門指南 5.0

單元 23 - 實作 setcode()

~~學習進度表~~

setcode() 的工作就是建立密碼表,我們需要的密碼表就是一個攪亂順序的英文字母表

setCode()

012345678910111213141516171819202122232425
qzirajsbktcludmvenwfoxgpyh

先來溫習一下用來編碼的數學公式

  
  
  
y = a * x + b
m = y % n
r = m + diff

ab 預定是 09 之間的隨機整數,要取得隨機整數的話,標準程式庫 (standard library) 有程式可用,倒是現在先不用急著一次到位,我們先把 a 設定成 3b 設定成 5 測試看看好了,如此 setcode() 的實作如下

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
    # _code 的 setter
    def set_code(self):
        # 取得 a 、 b 值
        a = 3
        b = 5
        # 利用公式建立密碼表
        self.__code = ""
        c = "a"
        i = 0
        while i < 26:
            x = c
            y = ord(x) * a + b
            m = y % 26
            self.__code += chr(m + 97)
            c = chr(ord(c) + 1)
            i += 1

__code 屬性 (attribute) 的初值設定為空字串 (empty string)

  
        self.__code = ""

下面設定兩個控制變數 (control variable) , c 為記錄目前處理的字母, i 則是記錄迴圈 (loop) 進行的次數

  
  
        c = "a"
        i = 0

因為英文字母表的小寫字母共有 26 個,因此公式用迴圈跑了 26

  
  
  
  
  
  
  
        while i < 26:
            x = c
            y = ord(x) * a + b
            m = y % 26
            self.__code += chr(m + 97)
            c = chr(ord(c) + 1)
            i += 1

這裡把 c 指派給 x 後,因為 c 是字串 (string) ,使得 x 也是字串,由於字串做乘法跟加法為複製字串,所以用內建函數 (function) ord()x 轉換成 Unicode 編碼值,然後才進行計算

  
            y = ord(x) * a + b

取得餘數 m 後,再利用內建函數 chr() 將 Unicode 編碼值轉換為單一字母的字串,這裡 += 會把單一字母的字串附加到 __code 的最後

  
self.__code += chr(m + 97)

咦?不是說字串是不可變的 (immutable) 嗎?不可變的複合物件無法更改裡頭的元素值,那這裡為什麼可以這樣寫呢?原因很簡單,這裡是重新指派,每一次 += 都是把新的字串物件給 __code ,所以沒有涉及到更改內容的問題。

最後,兩個控制變數都要遞增

  
  
            c = chr(ord(c) + 1)
            i += 1

我們把目前的版本放在 encrypt02.py 裡,如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 定義 Encrypt 類別
class Encrypt:
    # 定義建構子
    def __init__(self):
        # 建立密碼表
        self.set_code()

    # _code 的 getter
    @property
    def code(self):
        return self.__code

    # _code 的 setter
    def set_code(self):
        # 取得 a 、 b 值
        a = 3
        b = 5
        # 利用公式建立密碼表
        self.__code = ""
        c = "a"
        i = 0
        while i < 26:
            x = c
            y = ord(x) * a + b
            m = y % 26
            self.__code += chr(m + 97)
            c = chr(ord(c) + 1)
            i += 1

    # 編碼的方法
    def toEncode(self, str):
        pass

    # 解碼的方法
    def toDecode(self, str):
        pass

# 測試部分
if __name__ == '__main__':
    e = Encrypt()
    print()
    print(e.code)
    print()

# 檔名: encrypt02.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

測試部分就是印出密碼表,執行結果如下

$ python encrypt02.py
 
knqtwzcfiloruxadgjmpsvybeh
 
$

結果如預期,一個英文小寫字母恰恰好對應到另外一個英文小寫字母,這樣我們的公式就 ok 了嗎? a 等於 3b 等於 5 是沒問題的,可是我們希望 ab 可以是 09 之間的任意整數,這樣就有 100 種組合說,所以我們接下來要繼續測試,看看是不是每一種組合都 ok 囉!

中英文術語對照
屬性attribute
控制變數control variable
函數function
不可變的immutable
迴圈loop
空字串null string
標準程式庫standard library
字串string
重點整理
1. 實作 setcode() 是先將公式中的 a 設成 3b 設成 5 ,然後用迴圈利用兩個控制變數 ic 逐一計算每個字元。
2. 內建函數 ord() 可將字串轉換成 Unicode 編碼數字,而 chr() 將 Unicode 編碼數字轉換回字串。
問題與討論
1. 為什麼不把建立對換表格直接寫在 __init__() 裡就好了?
2. 為什麼字串變數用 += 可以把字元附加到字串物件的最後?
練習
1. 寫一個程式 exercise2301.py ,利用標準程式庫 randomrandint() 及上一個單元發展的 higher() 在命令列設計模擬擲骰子遊戲, 需要有莊家及玩家,然後印出擲出點數及輸贏。 參考程式碼
2. 承上題,將新程式寫在 exercise2302.py 中,加入判斷平手的機制。 參考程式碼
3. 承上題,將新程式寫在 exercise2303.py 中,設計骰子類別 Dice ,利用 point 屬性記錄骰子點數。 參考程式碼
4. 承上題,將新程式寫在 exercise2304.py 中,設計骰子玩家類別 DiceUser 的初始版本,利用 name 屬性記錄玩家名稱。 參考程式碼
5. 承上題,將新程式寫在 exercise2305.py 中,繼續擴充骰子玩家類別,利用屬性 dice1dice4 記錄最多四顆骰子點數,另外利用屬性 total_points 記錄終點數, dice_state 記錄骰子數量。 參考程式碼
6. 承上題,將新程式寫在 exercise2306.py 中,繼續擴充骰子玩家類別,定義 roll1Dice()roll4Dice() 方法,分別進行擲出一顆到四顆骰子。 參考程式碼
7. 承上題,將新程式寫在 exercise2307.py 中,設計 DiceGame 類別,建構子以 namesnumber 當參數, names 預計接收玩家名稱的字串串列, number 則是骰子數量,另外用迴圈建立 DiceUser 的串列屬性 players參考程式碼
8. 承上題,將新程式寫在 exercise2308.py 中,替 DiceGame 類別繼續設計 playgame() 方法,將遊戲進行方式的程式碼移到這裡。 參考程式碼
9. 承上題,將新程式寫在 exercise2309.py 中,定義命令列執行方式的 dice_game() 函數。 參考程式碼
10. 承上題,將新程式寫在 exercise2310.py 中,簡化 dice_game() 函數,用進行十萬次模擬。 參考程式碼

上一頁 單元 22 - Encrypt 類別
回 Python 入門指南 5.0 首頁
下一頁 單元 24 - 繼續測試
回 Python 教材首頁
回程式語言教材首頁