# 2025q1 Homework3 (kxo)
contributed by < `h0w726` >
:::danger
注意細節!
:::
## 鍵盤事件處理
#### 連續觀看多場 「電腦 vs. 電腦」的對弈
> commit [367ac7d](https://github.com/sysprog21/kxo/commit/367ac7d738f3a879dc09d2661c4500a276951720)
執行原來的程式時,第一次按下 Ctrl-Q 可以正常退出。但是想要繼續執行時,棋盤會卡住不動,且按下 Ctrl-P 或 Ctrl-Q 都沒有反應,需要重新掛載模組,於是查看 `/sys/class/kxo/kxo/kxo_state` 發現,剛開始載入模組時,內容為 **1 1 0^@**,對應到 `main.c` 的 `kxo_attr` 結構。
```c
struct kxo_attr {
char display;
char resume;
char end;
rwlock_t lock;
};
```
第一次執行按下 Ctrl-P 及 Ctrl-Q 後, `/sys/class/kxo/kxo/kxo_state` 內容變為 **0 1 1^@**,也就是說 end 的狀態被啟用,需要在 `release` 後將其重置為 0。這時發現再次執行 `sudo ./xo-user` 時連棋盤都沒有顯示,一樣查看 `/sys/class/kxo/kxo/kxo_state` 的內容為 **0 1 0^@** ,原來是 display 的狀態沒有啟用,使用 `sudo dmesg |grep -i kxo` 觀察,發現模組還有在運行。於是在 open 將 display 先設為 1 確保每次執行都可以正常顯示棋盤。
#### 修正按下 Ctrl-Q 顯示的訊息有亂碼的情況
> commit [fcd6c2f](https://github.com/h0w726/kxo/commit/fcd6c2f54e455f2d4d5f0bebe9ec2b9d1a221480)
按下 Ctrl-Q 暫停棋盤後,可以見到顯示的訊息如下
```
O| | |
-------
O| |X|O
-------
X|X|X|
-------
|O| |
-------
B�Stopping the kernel space tic-tac-toe game...
```
有亂碼的原因為在字串最後沒有以 null terminator(`'\0'`)結尾,造成未定義行為。
## 使畫面呈現的部分全部在使用者層級
> commit [161e3a6](https://github.com/h0w726/kxo/commit/161e3a603f63ea39fc4c1d1c13a1d5d74b4089ee)
原來的程式畫出棋盤的步驟如下:
1. 以 Timer 模擬中斷,每次中斷都會下一步棋
2. 核心透過 tasklet 將下棋以及畫棋盤的 work 排入 workqueue
3. AI1 或 AI2 將下棋結果 `'O'` 或 `'X'` 存入 `table`
4. 每下一步棋 `drawboard_work_func` 都會將整個棋盤存入 `kfifo_buffer`
5. 當使用者層級使用 `read` 時 , 對應到核心的 `kxo_read` 將 `kfifo_buffer` 存入 `xo-user.c` 中的 `display_buf`
6. 透過 `printf("%s", display_buf);` 印出棋盤
原本核心是傳遞整個棋盤到使用者層級畫出,我的想法是核心只傳遞 `table` 也就是 `'O'` 或 `'X'` ,將畫出棋盤的工作在使用者層級完成,其實就是將 `draw_board` 搬至使用者層級。
原來的程式是傳遞整個棋盤也就是 `DRAWBUFFER_SIZE` 個 bytes 為 66 個 bytes,改為只傳遞 `table` 只需要 棋盤的大小 4*4 = 16 個 bytes
:::danger
降低傳輸的成本,並提供對應的編碼和數學分析
:::
### 進一步編碼以降低傳輸成本
想法是將棋盤的三種狀態 `'O'` `'X'` `' '` 進行編碼,一個棋格只需要 2 bits 即可表示狀態,由於有16個棋格,運用 [bit field](https://hackmd.io/@sysprog/c-bitfield#C-%E8%AA%9E%E8%A8%80%E7%9A%84-bit-field) 的概念,剛好能以一個 `unsigned int` 表示全部棋格的狀態。
另外觀察 `'O'` `'X'` `' '` 的 ASCII 值
|| `'O'` | `'X'` | `' '` |
|--------| -------- | -------- | -------- |
|十進位| 79 | 88 | 32 |
|二進位| 01001111 | 01011000 | 00100000 |
發現第三第四位剛好可以運用作為編碼,`'O'` 為 00 `'X'` 為 01 `' '` 為 10