[cs50x] week2 - array | scrabble, readability, caesar/substitution
CS50 Cbasics
這堂課David講解了一些很接近電腦底層的知識,例如因為ASCII編碼的轉換,在C語言裡面,char
的本質其實是int
,透過減去'0'
就可以將char
轉換成他本身int
的模樣,還蠻有趣的!
char c = 'A';
printf("%i\n", c) // 65
他也解釋了如下的4 steps of compiling,過去自學的過程中其實很難觸碰到如此底層的東西,雖然也沒有100%聽懂我們下compile指令之後電腦裡面到底在幹嘛,但概念上大致理解。
- preprocessing
- compiling
- assembling
- linking
lab2/srcabble
lab2 scrabble的任務是從user方取得兩組字,並由指定編碼自算這兩組字分別的加總分數,分數比較大的player即獲勝此回合遊戲。比較簡單的main function就先不提,這邊只附上compute_score()
的function程式碼。
int compute_score(string word)
{
// compute and return score for string
int score = 0;
for (int i = 0, len = strlen(word); i < len; i++)
{
if (islower(word[i]))
{
score += POINTS[word[i] - 'a'];
}
else if (isupper(word[i]))
{
score += POINTS[word[i] - 'A'];
}
else
{
score += 0;
}
}
return score;
}
需要注意的是字的分數不分大小寫,除了alphabetic letters之外的符號都視為零分(或是說不列入計算)。例如以下輸入會得到平手的結果。
$ ./scrabble
Player 1: Question?
Player 2: Question!
Tie!
pset2/readability
readability的任務是透過一組算式計算出user輸入的這組文字適合幾年級的學生閱讀。算式裡面包含:
L
: average number of letters per 100 words in the textS
: average number of sentences per 100 words in the text
這份作業可能會出錯的眉眉角角比較多,submit50
會包含各式各樣可能找到你program bug的範例text來阻止你交作業(?)要把letters, words, sentences, spaces跟punctuations的出現會帶來的結果都想清楚再寫。
pset2/caesar
caesar作業其實就是最初階的寫一個program做凱薩密碼的加密。概念很簡單,就是指定一個數字作為key
,而輸入的plaintext
都會照那個數量base on alphabet往後偏移,轉換為ciphertext
。因為這份作業不像之前都是在program裡面去跟userget_string()
、而是使用command-line argument,因此還要處理如果輸入的argument不是數字必須exit程式並提醒user輸入數字的狀況。
我不確定這樣是不是最有效率的方法,不過取得key
之後我把plaintext
轉換成ciphertext
的步驟有三。轉換過程中還必須考慮英文字母大小寫的問題,寫成兩種狀況討論,不過想清楚之後其實蠻簡單的:)
1. convert ascii to alphabetical index
// 0~26 instead of 65~90 (uppercase) or 97~122 (lowercase)
2. shift by key
3. convert back to ascii
pset2/substitution
subsitution
又是前面caesar
作業的困難版,前面我們只要取得一個key
的數字並將所有字母都按數量偏移,但subsitution
的任務是在command-line argument輸入一組長度26個英文字母的key
(不分大小寫、字母不可重複)用來指定A~Z
分別被替換成哪些字母,而輸入跟輸出的text會呈現大寫換大寫、小寫換小寫、特殊符號不變的情況。
因為command-line argument的輸入有限制,如果user輸入的key
不符合當作key
的資格就必須exit program,所以必須先驗證以下三個問題,全部通過才視為valid的key
。
key
是否全部為英文字母key
是否全部不重複key
的輸入是否過剛好長度為26
拿到key
之後我的做法是計算出alphabetical orderABCDEFGHIJKLMNOPQRSTUVWXYZ
跟key
之間的距離(int
差)當作mapping的依據。要小心製造這個diff
array的時候,因為user有可能輸入的時大小寫混雜的key,取得diff
的時候必須先將所有char
都toupper()
統一變成uppercase(當然全部換成lowercase也可以),之後才有辦法統一處理。
int diff[26] = {};
int base = 65;
for (int i = 0; i < 26; i++)
{
diff[i] = toupper(argv[1][i]) - base;
base++;
}
接下來處理字母轉換,方法跟caesar
大同小異,也是分為大小寫情況處理,以下以大寫情況作為提示,也要注意如果plaintext
裡面有包含非英文字母的符號,就原形輸出不需要做任何事。最後取得ciphertext
之後簡單printf
出來就可以了!
for (int i = 0; i < len; i++)
{
if (isupper(plaintext[i]))
{
int alpha_index = plaintext[i] - 65;
plaintext[i] = (alpha_index + diff[alpha_index]) + 65;
}
【課後心得】
因為不確定自己的程度到底在哪裡、也希望儘可能多練習跟多寫,所以打算把less comfortable跟more comfortable的作業都完成。一方面也由於上週發現先寫完less comfortable再寫more comfortable對於我對邏輯跟語法的掌握度都有幫助,所以就算工作量暴增也要努力寫完!另外,雖然課才跟到week 2,我已經可以深刻地體會為什麼有人說cs50看完影片只能學到10%,剩下90%知識都在作業裡了,真的要自己動手寫才可以感受到所有困難並自己練習解決!然後上個月因為開始準備GRE,寫程式的時間被壓縮了不少(作業寫完之後這篇筆記拖了三週才痛苦不已地生出來…)希望自己可以不要本末倒置,每天都要努力工作努力讀書努力玩耍!