1. 程式人生 > >使用linux curses開發控制檯的打字遊戲

使用linux curses開發控制檯的打字遊戲

1. 關於linux curses庫,不多說,google下便知道,就像當年的TC下的視窗程式庫一樣

 2.  事情源於在chinaunix上看到了the4king在c/c++論壇上的帖子:

程式碼的編譯命令是:

#  gcc file.c  -lrt -lcurses

我的平臺是Ubuntu10.04

3.  先閱讀原始碼,瞭解其思想。

   該打字遊戲的實現思想大致如下:

   介面如下幾部分組成,topwin(也就是顯示字母下落動畫效果的視窗),numwin(成績框,記錄輸入字元數及命中數)

   其它訊號處理倒是簡單,對應了'1'暫停,'2'退出等功能。

   主執行緒: 

   以字串darwscr代表整個topwin的輸出內容

   do{

     在最上面一行產生若干個字元(數量很少)。然後將新字串重寫回topwin,重新整理顯示

     呼叫changekey(),然後檢查checkkey()在location[]記錄的命中字元,並把當前命中位置置成'@',把上次命中位置置成' '

     將topwin自第二行開始向下移動一行///注意這個地方沒有加鎖,有執行緒同步問題

    }

   checkkey()執行緒:

   do{

        接收鍵盤輸入

         在當前darwscr裡,找出命中位置,並記錄到緩衝區中  //有執行緒同步問題

 }

4. 觀察其程式碼,發現一些不足之處

第一個地方,新增一個basewin,完全覆蓋原始主視窗,因為發現在不同的終端下,預設原始主視窗的背景不一致,現在用basewin來統一一下,這樣做有些移植性的意思哈。

首先,changekey()函式與函式之間用了不必要的訊號量,完全可以用函式呼叫來代替

其次,每交topwin下移一行(產生動畫效果)時,呼叫changekey()函式一次,實際上最多隻能處理一個input字元,效果就是如果某一行的字元數大於topwin的高度LINES,

那麼很悲劇,你無論鍵盤敲得多快,只能眼睜睜看著這一行落地而毫無辦法。而且原始碼裡只用了一個變數去儲存最近的命中字元,如果你輸入很快,後面就會覆蓋前面的。

解決辦法很簡單:

先建立輸入緩衝區,這裡用了一個迴圈佇列,長度為1000,客觀地講應該不會溢位。

接著,就是改動changekey()的stop()時間,把節省下來的時間用於迴圈讀緩衝區,爭取在有限的時間裡多處理幾個命中的字元。

最後,完成上面這些改動之後,編譯執行,緩衝區的效果是有了,可以在一次動畫效果之間命中多個字元,但問題又來了,發現顯示命中效果有問題,個別字元的命中效果產生了偏離,比如明明是第n行的第12個字元命中,卻顯示成了第n-行的第12個字元命中。檢查了下程式碼,發現是多執行緒的問題。原始碼在checkkey()裡檢查命中字元,並把其位置記錄到緩衝區裡,問題是,如果checkkey()恰好發生在一次動畫效果之前,那麼由於隨後發生了動畫效果,剛剛在checkkey()裡記錄的命中位置就不準確了,於是需要在動畫效果的程式碼中檢查緩衝區,並修正已有資料的偏移。同時,應該保證checkkey()修改緩衝區的程式碼與動畫程式碼互斥。同一時刻只能有一個執行, 不然就混亂了!

可以通過增加訊號量控制來改進這個問題

checkkey()執行緒:

  迴圈接收鍵盤輸入

  訊號量P操作,進入臨界區

  在當前darwscr裡,找出命中位置,並記錄到緩衝區中

  訊號量V操作,退出臨界區

主執行緒,對應地改動:

   sem_wait(&sem_location);

            動畫效果區程式碼

    sem_post(&sem_location);

  改動後的程式碼如下:

 

5.   在完成原打字遊戲的改進後,我想再增加功能,把打字遊戲變成單詞練習遊戲,就像一些打字練習的軟體一樣

  基本思路是,生成一系列的小視窗,視窗有兩行,一行是單詞,隨機產生,一行空等待使用者輸入

  動畫效果還是主執行緒實現,定時迴圈。

  當用戶輸入的單詞完全匹配小視窗上的單詞時,視窗消失(不要delwin(),應該回收到一個pool中,以重複使用)

  程式碼如下:

 

  這個單詞練習遊戲還有很多地方沒有完善,比如單詞庫隨機功能,計數功能有問題(懶得改了),或者還有bug,但跑起來還像那麼回事,如下圖:

6.  需要說明的是refresh()函式的功能,在這上面犯了不少錯誤:

refresh()就是重新整理主螢幕(預設的螢幕)

a)   程式初始化階段,清除主螢幕,否則有時候程式啟動後,視窗上很多亂碼和不知名的符號!

b) 如果程式裡生成了好幾個視窗,並頻繁操作它們的位置,那麼也需要定時地重新整理主螢幕,否則同樣是視窗上顯示混亂!