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

先來溫習一下用來編碼的數學公式
y = a * x + b
m = y % n
r = m + diff
a 與 b 預定是 0 到 9 之間的隨機整數,要取得隨機整數的話,標準程式庫 (standard library) 有程式可用,倒是現在先不用急著一次到位,我們先把 a 設定成 3 , b 設定成 5 測試看看好了,如此 set_code_array() 的實作如下
| // 設定 code_array 的 setter 成員函數 | |
| void Encrypt::set_code_array() { | |
| // 設定 a 、 b 值 | |
| int a = 3; | |
| int b = 5; | |
| // 利用公式建立密碼表字串 | |
| int x, y, m; | |
| char c = 'a'; | |
| string s; | |
| int i; | |
| for (i = 0; i < 26; i++) { | |
| x = c; | |
| y = x * a + b; | |
| m = y % 26; | |
| s += m + 97; | |
| c++; | |
| } | |
| // 將建立好的密碼表直接設定給成員變數 | |
| code_array = s; | |
| } |
因為英文字母表的小寫字母共有 26 個,因此公式用迴圈 (loop) 跑了 26 次
| for (i = 0; i < 26; i++) { | |
| x = c; | |
| y = x * a + b; | |
| m = y % 26; | |
| s += m + 97; | |
| c++; | |
| } |
我們多用了除了公式外的兩個變數 (variable) c 與 s ,變數 c 為起始字元 (character) ,初值設定成英文字母表的第一個字母 'a' , s 則是宣告為字串 (string) ,這裡並沒有直接拿變數 c 進行計算,而是把變數 c 的值指派給整數型態的 x
| x = c; |
會這樣做的原因很簡單,因為需要一個變數表示目前處理的字元,而字元型態的變數可以如同整數型態進行加減乘除,因此迴圈的最後利用遞增將變數 c 轉移到下一個字元,例如迴圈從 'a' 開始,第二個處理的字元為 'b' ,第三個為 'c' ,以此類推
| c++; |
由於 C++ 的字元型態其實就是範圍較小的整數,因此也可以直接將迴圈的控制變數 i 設定為 97 ,讓 i 依次遞增到 97 + 26 為止。
迴圈跑完,最後就是把 s 設定給 code_array
| // 將建立好的密碼表直接設定給成員變數 | |
| code_array = s; |
建構函數 Encrypt() 就是呼叫 set_code_array() 設定 code_array ,另外 get_code_array() 也就是回傳 code_array ,目前的實作版本如下
| 001 | // 引入 Encrypt 類別的標頭檔 |
| 002 | #include "encrypt01.h" |
| 003 | |
| 004 | // Encrypt 的建構函數 |
| 005 | Encrypt::Encrypt() { |
| 006 | // 呼叫 setter 設定 code_array |
| 007 | set_code_array(); |
| 008 | } |
| 009 | |
| 010 | // 設定 code_array 的 setter 成員函數 |
| 011 | void Encrypt::set_code_array() { |
| 012 | // 設定 a 、 b 值 |
| 013 | int a = 3; |
| 014 | int b = 5; |
| 015 | |
| 016 | // 利用公式建立密碼表字串 |
| 017 | int x, y, m; |
| 018 | char c = 'a'; |
| 019 | string s; |
| 020 | int i; |
| 021 | for (i = 0; i < 26; i++) { |
| 022 | x = c; |
| 023 | y = x * a + b; |
| 024 | m = y % 26; |
| 025 | s += m + 97; |
| 026 | c++; |
| 027 | } |
| 028 | |
| 029 | // 將建立好的密碼表直接設定給成員變數 |
| 030 | code_array = s; |
| 031 | } |
| 032 | |
| 033 | // 回傳密碼表字串的 getter 成員函數 |
| 034 | string Encrypt::get_code_array() { |
| 035 | return code_array; |
| 036 | } |
| 037 | |
| 038 | /* encrypt01.cpp |
| 039 | Kaiching Chang |
| 040 | 2014-5 */ |
我們用另外一個程式來測試目前的版本吧!因為 ToEncode() 跟 ToDecode() 都還沒實作,所以就印出密碼表來看看就好了
| 001 | // 引入標準程式庫中的 iostream |
| 002 | #include <iostream> |
| 003 | // 引入 Encrypt 類別的標頭檔 |
| 004 | #include "encrypt01.h" |
| 005 | |
| 006 | // 使用 std 中的兩個名稱 |
| 007 | using std::cout; // 標準輸出串流的物件 |
| 008 | using std::endl; // 新行符號,等於 '\n' |
| 009 | |
| 010 | // 程式執行的 main() 函數 |
| 011 | int main() { |
| 012 | // 印出空白一行 |
| 013 | cout << endl; |
| 014 | |
| 015 | // 建立 Encrypt 物件 |
| 016 | Encrypt encryptor; |
| 017 | // 印出密碼表字串 |
| 018 | cout << encryptor.get_code_array() |
| 019 | << endl << endl; |
| 020 | |
| 021 | return 0; |
| 022 | } |
| 023 | |
| 024 | /* encrypt_demo01.cpp |
| 025 | Kaiching Chang |
| 026 | 2014-5 */ |
編譯執行,結果如下

結果如預期,一個英文小寫字母恰恰好對應到另外一個英文小寫字母,這樣我們的公式就 ok 了嗎?a 等於 3 跟 b 等於 5 是沒問題的,可是我們希望 a 與 b 可以是 0 到 9 之間的任意整數,這樣就有 100 種組合說,所以我們接下來要繼續測試,看看是不是每一種組合都 ok 囉!
中英文術語對照
| 標準程式庫 | standard library |
| 迴圈 | loop |
| 變數 | variable |
| 字元 | character |
| 字串 | string |
重點整理
- 實作 set_code_array() 是先將公式中的 a 設成 3 , b 設成 5 ,然後用迴圈利用兩個控制變數 i 與 c 逐一計算每個字元。
- 字元型態就是範圍較小的整數,因此可直接進行算術運算。
- 計算完的整數直接與字串進行運算,加號在字串類別重載過,因此可把轉換成字元的整數附加到字串的最後。
問題與討論
- 為什麼不把建立對換表格直接寫在建構函數裡就好了?
- 為什麼字串變數用 += 可以把字元附加到字串物件的最後?
練習
- 承接上一個單元的猜數字遊戲,另寫一個程式 exercise1501.cpp ,接受使用者輸入,加入判斷使用者是否猜對的邏輯及提示訊息。
- 承上題,另寫一個程式 exercise1502.cpp ,將 answer 與使用者輸入都轉換成整數陣列,並將判斷的邏輯改成比較陣列元素。
- 重構是指不改變軟體功能,而將程式碼重新整理成易讀、好整理的概念。試著重構猜數字遊戲的 exercise1502.cpp ,將新程式寫在 exercise1503.cpp 中,把整數拆成陣列的部份改寫到函數 ArrayNumber() 中,小提醒,陣列識別字等同指標,因此可以直接傳遞陣列給函數,初始化陣列元素。
the end
沒有留言:
張貼留言
0.留言請選擇註冊帳號, Google 或 OpenID 均可
1.歡迎留言交流,但不歡迎垃圾留言及廣告留言
2.文章相關問題歡迎提出,請減少情緒性留言
3.非文章相關內容,請到 G+ 社群或 FB 社團提出
4.問作業之留言會被直接刪除
5.莫忘網路禮節
6.可使用部份HTML標記,如 <b> 、 <i> 、 <a>
7.站長保留刪除留言的權力