---
tags: C/C++
---
[toc]
# Coding Dojo 程式設計道場

## Clean Coder 第6章:練習
- 老闆的職責不包括避免員工的技術落伍以及替員工打造一份好看的履歷。
- 身為專業程式設計師必須用自己的時間來練習,關心自己能做到怎樣的最好結果並且保持自己的技能不落伍。
- 雖然練習是賺不到錢的,但是練習之後,你將會獲得回報。
- 專業人士都要借助專門的訓練來提升自己的技能,音樂家練習音階,醫生練習縫針和動手術,專業人士就會選擇『練習(practice)』
### 轉變
- 在20世紀60年代,可能要等上一兩天才能看到編譯的結果。到了70年代末期,5萬行的程式可能需要45分鐘來編譯。甚至在90年代,仍然經常需要花費大量的時間來完成建置(build)。
- 作者的 FITNESSE 的Java專案,程式碼共有6萬4千行。包含所有單元測試和整合測試的一次完整建置,耗時不到4分鐘。差不多每分鐘可以執行十次的『編譯/測試』。
- 保持這樣的速度不見得是件好事。 更好的做法是慢下來,仔細思考,也有些時候,盡可能快地重複『編譯/測試』的過程,可能帶來很高的生產率。
- 在每分鐘進行許多次『編碼(code) /測試』時,你身上的肌肉記憶了要敲那個鍵,意識中較基礎的部分辨識情況,在百分之一秒的時間內做出合適的反應,大腦則可以放心思考更高層次的問題。
### 程式設計柔道場
- 2005年作者出席在英國謝菲爾德(Sheffield)舉辦的XP2005大會,會上參加了L.B.和E.G主持的『程式設計柔道場(Coding Dojo)』的主題活動。
- 他們要求每個人打開自己的筆記型電腦,跟他們一起用測試驅動開發來編寫Conway’s Game of Life。他們稱其為『kata』
#### Kata(對打)
- 在武術裡,kata是一套設計好的,目標是要逐步把整套招式練習到純熟。

- 程式設計的Kata也是一整套敲擊鍵盤和滑鼠的動作,用來模擬程式設計問題的解決過程。練習者不是在解決真正的問題,因為你已經知道了解決方案。相反地,你是在練習解決這個問題所需要的動作和決策。
- 和習武者一樣,程式設計師應該懂得多種不同的Kata,並定期練習,確保不會淡化或遺忘。
- 它特別有利於潛意識中構築"通用的問題"與"解決方案"的聯繫
#### Wasa(瓦薩)
- Wasa基本上可以說是兩個人的Kata。一個人負責攻,另一個人負責守。
- 一個簡單的問題,一個人寫單元測試,另一個人寫程式使它能夠通過然後交換角色。
- 程式設計師選擇實現一個排序演算法,寫測試的人可以很容易地限制速度和記憶體,給同伴施壓。
#### 自由練習
- 自由練習(Randori)就是不限制形式的搏擊。
- 很多程式設計練習場中,都會玩一種叫做『自由練習』的遊戲。在自由練習中,螢幕被投影到牆上,一個人寫測試,然後坐下來,另一個人寫程式,使得測試能夠通過,再寫下一個測試, 桌子邊的人一個個輪流接下去。
- 從這種練習中可以學到很多東西。你會深入地瞭解人們解決問題的過程,進而掌握更多的方法,提升專業技能。
### 網路上練習 Kata 的題目
https://codingdojo.org/practices/KataCatalogue/
### cyber‑dojo 線上練習 Coding Dojo 環境網頁
https://cyber-dojo.org/creator/home
### OS C++ STUDY GROUP
[Code](https://docs.google.com/spreadsheets/d/1ZO-ck8YKCcR9bRiGfu3-M2xnMcFF6xzEBKFTOJ-PKDI/edit#gid=0)
## 2022/10/26 Coding Dojo 介紹
### 目的
- 了解 Coding Dojo 以及 Kata
- 熟悉使用 TDD 開發

- 練習 refactoring (追求極致的可讀性, 可維護性)
- 觀摩並學習同仁思考邏輯與 Coding 技巧
### 方式
- Prepare Kata : 事先準備好的, 由台上講者來展示某 Kata 的法
- Randori : 選定某一題目, 由台下觀眾根據"輪替"規則, 觀眾輪流上台解題
### Prepare Kata : 題目 FizzBuzz

#### 再加上新增 7 的倍數
* 輸出 Whizz
* 若同時是 3, 5, 7 的公倍數, 則輸出 "FizzBuzzWhizz"
### Randori Kata
#### 台上規則
- 副駕駛(Navigator)與正駕駛(Driver)在台上 Coding 並講解
- 原則上 Navigator 主導邏輯, Driver 敲代碼, 但可以互相討論
- 兩個人要儘量把每個步驟與原因都講出來, 包含討論的內容
- 討論時請大聲,讓觀眾能夠充分瞭解方向與現況
- 過程遵循TDD, 先寫測試程式, 在寫主程式, Baby Step

- 七分鐘換手一次:副駕駛下台,正駕駛轉任副駕駛,一位新的觀眾上台擔任正駕駛

- 台上可視情況舉 "求救牌", 此時不論燈號皆視為綠燈
- 副駕駛下台換手前, git commit -a -m "[Name]" 作紀錄
- 今天的 commit 會放上 gitlab 供大家參考或回去練習
#### 台下規則
- 尚未綠燈前,禁止對正副駕駛提問或給建議,保持安靜
- 綠燈時,歡迎給建議
- 專心看台上討論寫 Code, 嚴禁台下自己偷跑
### 題目 Bowling Game

#### 英文名詞說明
roll : 丟球
pins : 球瓶
frame : 局
strike: 第一球全倒
spare: 第二球才全倒
openframe: 一局內沒有全倒
mark: 指一次全倒或二次全倒時的登記符號
#### 此台 NoteBook 環境限制
* 已設定 CapsLock 等於 Left CTRL
* 有裝 vim extension module, 若要 toogle enable/disable => CapsLock+Alt+V
* 若有自己習慣的 extension module 可以再裝, 但若會影響下一個人, 換手時需要關閉
#### VS Code 快捷鍵輔助
| 說明 | 快捷鍵 |
|---|---|
| toggle vim | CapsLock+Alt+V |
| compile | F7 |
| run | F5 |
| 跳到 compile error line | F8 |
| 切換檔案 | Alt+<數字> |
| find function | Shift + Ctrl + |
| 快速搜尋(列出專案中的其他檔案) | Ctrl +P |
| 註解 / 反註解 | Ctrl +/ |
|快速建立程式碼 | 在剛輸入的程式碼後按Tab |
|上下移動單行程式 | Alt+↑/Alt+↓ |
|導航至前後編輯區塊 | Alt+→/Alt+← |
|以字為單位跳躍游標 | Ctrl +→/Ctrl+← |
|切換最近使用的兩頁籤 | Ctrl+Tab |
|格式化文件 | Shift + Alt + F |
|程式碼縮排操作 |Ctrl+[ Ctrl+] |
|程式碼縮排操作 |Ctrl+Shift+[ Ctrl+Shift+] |
|命令輸入框 | F1 |
|在頁面下方開啟Terminal | Ctrl+` |
|編輯相同文字區塊 |Ctrl+D ... |
|向上下做跨欄選取 |Ctrl+Shift+ Alt+Top / Down |
|游標拖曳做上下跨欄選取 |Alt+Shift+滑鼠左鍵拖曳 |
|游標點選做跨欄選取 | Alt +滑鼠左鍵點選 ... |
|在當前行下方插入一行 | Ctrl + Enter |
|在當前行上方插入一行 | Ctrl + Shift + Enter |
|開啟擴充套件畫面 | Ctrl+Shift+X |
#### VS Code with vim extension 快捷鍵輔助
| 說明 | 快捷鍵 |
|---|---|
| Go To Definition | Ctrl+] |
| Back | Ctrl+O |
| peekReference | Ctrl+] |
#### Retrospective
1. 今天學到了什麼? (語言, 工具, 技巧, 想法, 流程……)
2. 今天的Dojo有沒有什麼地方不理想的?
3. 如果下次還有機會辦Coding Dojo,有 沒有什麼建議?
### The Bowling Game Kata 影片
* https://www.youtube.com/watch?v=Om0co6xNNBI
* https://vimeo.com/18702263
## 2022/11/30 Coding Dojo 介紹
### Prepare Kata : 題目 Tennis
### Randori Kata : 題目 Generating Prime Factors
* Write a class named ==“PrimeFactors”== that has one static method: ==generate()==.
* The generate method takes an integer argument and returns a ==std::vector<int>==. That list contains the prime factors in numerical sequence.
* Uncle Bob’s description that he was able to solve the kata in ==3 lines== of code
#### 邏輯說明: What are the prime factors of 60?
* Our first divisor is 2. 2 goes into 60, leaving 30.
* 2 goes into 30, leaving 15.
* 2 doesn't go cleanly into 15. So let's move on to our next divisor, 3.
* 3 goes cleanly into 15, leaving 5.
* 3 does not go cleanly into 5. The next possible factor is 4.
* 4 does not go cleanly into 5. The next possible factor is 5.
* 5 does go cleanly into 5.
* We're left only with 1, so now, we're done.
* Our successful divisors in that computation represent the list of prime factors of 60: 2, 2, 3, and 5.
You can check this yourself:
```cpp
2 * 2 * 3 * 5
= 4 * 15
= 60
Success!
```
* test case:
```cpp
* 2 => {2}
* 1 => {}
* 3 => {3}
* 4 => {2, 2}
* 6 => {2, 3}
* 8 => {2, 2, 2}
* 9 => {3, 3}
* 12 => {2, 2, 3}
* 30 => {2, 3, 5}
```
* 注意: 每個 test case 都先用最簡單的方式 pass, 例如測試 case 是 2 的時候先讓 2 可以通過 , 不需先去想 3 到時該怎麼過
## 2023/1/4 Randori Kata : 題目 WordWrap
### Description
* You write a class called ==WordWrap==, that has a single member function named ==wrapper== that takes two arguments, a string, and a column number. The function returns the string, but with line breaks inserted at just the right places to make sure that no line is longer than the column number. You try to break lines at word boundaries."
### Practice 1: non-recursive wrapper
### Practice 2: recursive wrapper
### Examples
```cpp=
// group1: no space
wrapper("", 1) => ""
wrapper("w", 1) => "w"
wrapper("word", 4) => "word"
wrapper("word", 10) => "word"
wrapper("word", 2) => "wo\nrd"
wrapper("wordword", 2) => "wo\nrd\nwo\nrd"
wo
rd
wo
rd
// group2: only one space and two words
wrapper("word word", 5) => "word\nword"
wrapper("word word", 6) => "word\nword"
wrapper("word word", 3) => "wor\nd\nwor\nd"
wor
d
wor
d
wrapper("word word", 4) => "word\nword"
wrapper("word word", 2) => "wo\nrd\nwo\nrd"
wo
rd
wo
rd
// group3: more spaces between with words
wrapper("word word word", 2) => "wo\nrd\nwo\nrd\nwo\nrd"
wo
rd
wo
rd
wo
rd
wrapper("word word word", 10) => "word word\nword"
word word
word
wrapper(" word word word", 11) => " word word\nword"
```
### substr()
* string substr (size_t pos, size_t len) const;
```cpp
Parameters:
pos: Position of the first character to be copied.
len: Length of the sub-string.
size_t: It is an unsigned integral type.
Return value:
It returns a string object.
```
* Example:
```cpp
string a="123456789";
cout<<a.substr(2,5)<<endl; //表示呼叫「字串a索引2數起的5個字元」所構成的子字串,顯示34567
cout<<a.substr(2)<<endl; //表示呼叫「字串a索引2數起之後的所有字元」所構成的子字串,顯示3456789
```
### find_last_of()
* size_t find_last_of (const string& str, size_t pos = npos) const noexcept;
```cpp=
size_t find_last_of (const string& str, size_t pos = npos) const noexcept;
Parameters
str − It is a string object.
pos − Position of the first character to be copied.
Return Value
The position of the last character that matches.
If no matches are found, the function returns string::npos.
```
* Example:
```cpp
#include <string>
#include <iostream>
void print_str(const std::string title, const std::string &str, int pos)
{
std::cout << title << " = "<< pos << " " <<
str.substr(0, pos) << " remaining str = " <<
str.substr(pos) << std::endl;
}
int main()
{
#include <string>
#include <iostream>
void print_str(const std::string title, const std::string &str, int pos)
{
std::cout << title << " = "<< pos << " " << str.substr(0, pos) << " remaining str = " << str.substr(pos) << std::endl;
}
int main()
{
const std::string strPath = "E:\\2017\\2018\\2019.txt"; /* 最後一個 \\ , 從0算起, 第12個位置 */
int nPos1 = strPath.find_last_of("\\");
int nPos2 = strPath.find_last_of("\\", nPos1); /* nPos1 是 pos, 找 0 ~ 12 position */
int nPos3 = strPath.find_last_of("\\", nPos1 -1); /* nPos1 是 pos, 找 0 ~ 11 position */
int nPos4 = strPath.substr(0, nPos1+1).find_last_of("\\"); /* 帶入的 nPos1 是 len */
int nPos5 = strPath.substr(0, nPos1).find_last_of("\\"); /* 帶入的 nPos1 是 len */
int nPos6 = strPath.substr(nPos1).find_last_of("\\"); /* 起始位置 nPos1 */
int nPos7 = strPath.substr(nPos1+1).find_last_of("\\"); /* 起始位置 nPos1 + 1 */
print_str("nPos1", strPath, nPos1);
print_str("nPos2", strPath, nPos2);
print_str("nPos3", strPath, nPos3);
print_str("nPos4", strPath, nPos4);
print_str("nPos5", strPath, nPos5);
std::cout << "nPos6 = " << nPos6 << std::endl;
std::cout << "nPos7 = " << nPos7 << std::endl;
return 0;
}
```
輸出
```cpp=
nPos1 = 12 E:\2017\2018 remaining str = \2019.txt
nPos2 = 12 E:\2017\2018 remaining str = \2019.txt
nPos3 = 7 E:\2017 remaining str = \2018\2019.txt
nPos4 = 12 E:\2017\2018 remaining str = \2019.txt
nPos5 = 7 E:\2017 remaining str = \2018\2019.txt
nPos6 = 0
nPos7 = -1
```
https://codingdojo.org/kata/Minesweeper/
https://blog.knatten.org/2011/04/01/the-minesweeper-kata-in-15-lines-of-c/
## 2023/3/7 Randori Kata : 題目 Soundex
### Soundex 演算法示例介紹
- Book : https://www.books.com.tw/products/CN11396496
- 電子書試閱第二章 :
https://www.ituring.com.cn/book/tupubarticle/12090
**Soundex 演算法是一種語音演算法,這個演算法遵循以下 4 種規則:**
- 規則1 : 保留第一個字母,丟掉所有出現的a、e、i、o、u、y、h、w
- 規則2 : 以數字來代替輔音(第一個字母除外):
- b f p v -> 1
- c g j k q s x z -> 2
- d t -> 3
- l -> 4
- m n -> 5
- r -> 6
- 規則3 : 對於相鄰的重複的數字只保留一個,即相鄰的兩個被取代為同一個數字的字母只保留一個; 如果出現兩個編碼相同的字母,且它們被 h 和 w 隔開,也這樣處理;但如果被母音(a,e,i,o,u)隔開,就要編碼兩次。這條規則同樣適用於第一個字母。
- 規則4 : 當得到一個字母和三個數字時,停止處理。如果需要,補零以對齊。
- (補充) 規則5 : 希望第一碼外輸出字母是大寫
- (補充) 規則6 : 除第一碼外, 輸入時都視為小寫來做解碼
### Test Case
```cpp=
//規則4 : 當得到一個字母和三個數字時,停止處理。如果需要,補零以對齊。
ASSERT_EQ("A000", soundex.encode("A"));
// 規則2 : 以數字來代替輔音(第一個字母除外):
ASSERT_EQ("A100", soundex.encode("Ab"));
ASSERT_EQ("A200", soundex.encode("Ac"));
ASSERT_EQ("A000", soundex.encode("A#"));
ASSERT_EQ("A234", soundex.encode("Acdl"));
// 規則4 : 當得到一個字母和三個數字時,停止處理。如果需要,補零以對齊。
ASSERT_EQ("A234", soundex.encode("Acdlb"));
// 規則1 : 保留第一個字母,丟掉所有出現的a、e、i、o、u、y、h、w
ASSERT_EQ("B234", soundex.encode("Baeiouhywcdl"));
// 規則3 : 對於相鄰的重複的數字只保留一個,即相鄰的兩個被取代為同一個數字的字母只保留一個
ASSERT_EQ("A123", soundex.encode("Abfcgdt"));
ASSERT_EQ("B123", soundex.encode("Bbfcgdt"));
// (補充) 規則5 : 希望第一碼輸出字母是大寫
ASSERT_EQ("B123", soundex.encode("bbfcgdt"));
// (補充) 規則6 : 除第一碼外, 輸入時都視為小寫來做解碼
ASSERT_EQ("B123", soundex.encode("bBFCGDT"));
// 規則3 : 但如果被母音(a,e,i,o,u)隔開,就要編碼兩次。這條規則同樣適用於第一個字母。
ASSERT_EQ("J110", soundex.encode("Jbob"));
```
### Before We Start
- kata 除了增進程式技巧外, 編輯技巧熟練度也是重點
- coding 中, 如果答案不如預期, 一時間看不出來, 不要遲疑, 就直接用 F5 設定中斷 debug
- TDD 留下了清晰的測試案例的文檔, 可以讓你回憶起之前所做出的決定
- 整理 code 重點: 檢查是否單一職責原則
- 檢查效率: 是全部轉換完, 再做擷取 4 個字母, 還是可以轉換較少字元就提前結束
#### std::substr()
* string substr (size_t pos, size_t len) const;
```cpp
Parameters:
pos: Position of the first character to be copied.
len: Length of the sub-string.
size_t: It is an unsigned integral type.
Return value:
It returns a string object.
```
* Example:
```cpp
string a="123456789";
cout<<a.substr(2,5)<<endl; //表示呼叫「字串a索引2數起的5個字元」所構成的子字串,顯示34567
cout<<a.substr(2)<<endl; //表示呼叫「字串a索引2數起之後的所有字元」所構成的子字串,顯示3456789
```
#### std::string construct
- std::string initialization
https://cplusplus.com/reference/string/string/string/
- fill constructor
```cpp
// Fills the string with n consecutive copies of character c.
string (size_t n, char c);
std::string str (3, 'x');
=> "xxx"
```
#### std::toupper(unsgined char c)
#### std::tolower(unsgined char c)
#### std::string::front()
```cpp
// accesses the first character
std::string s("Exemplary");
char f1 = s.front();
=> f1 = 'E'
```
#### std::string::back()
```cpp
// accesses the last character
std::string s("Exemplary");
char f1 = s.back();
=> f1 = 'y'
```
#### std::string::find()
- Return value
Position of the first character of the found substring or npos if no such substring is
```cpp
std::string s ("you are a student");
std::string::size_type n = s.find("is");
if (std::string::npos == n)
std::cout << "not found! n == npos\n";
```