今回の授業内容は,前回の続きです. 開発中のエデュテイメントアプリの完成度を高めよう. (もし,前回の作業が完了していない場合, まずは大至急,追いつくこと. pdcl は ver.2,pendraw は ver.4.)
作業用のディレクトリとファイルを用意し, 開発中のアプリの現在の状態を確認しておこう:
$ mkdir c-1106 # 今回のディレクトリを作成 $ cp c-1103/*.c c-1106/ # 前回のディレクトリc-1103 からソースファイルをコピー $ cd c-1106 # 今回のディレクトリで作業 $ ls # ソースファイルを確認 pdcl.c pendraw.c $ cc pdcl.c -o pdcl # コンパイル $ cc pendraw.c -lncurses -o pendraw $ vim script.txt # 動作テスト用PDCLスクリプトの作成... up 10 repeat 10 off up 3 left 5 on down 5 right 3 end $ ./pdcl script.txt # バックエンドプログラムの動作確認 kkk...lllq # キーシーケンス $ ./pendraw # フロントエンドプログラムの動作確認 ... # [P]キーでスクリプトを実行
バックエンドで生成されたキーシーケンスによって フロントエンドのペンが自動操作される.
まずは,フロントエンドプログラム pendraw について, ペンが off状態の場合にも画面上にカーソルを表示し, ペンの位置を把握できるようにしてみよう.
現状(前回のバージョン)の pendraw.c では, ペンの軌跡を描画する間は erase() を封印し, 画面に表示したものがすべて残るようにしていた. しかし,erase() しないままでは, off状態のカーソルの軌跡も残ってしまうことになる.
そこで,画像を画面に記録するのではなく, 2次元配列に記録しておき, その画像とカーソルとを画面に再表示し続けるように, プログラムの構成を変更しよう.
ソース pendraw.c:(ver.5)
... #include <stdlib.h> // malloc() /* 画像全体に文字を記入する. img:画像 w, h:画面サイズ c:文字 */ void FillImg(char *img, int w, int h, char c) { int x, y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { img[w*y + x] = c; } } } /* 画像を端末画面に表示する. img:画像 w, h:画面サイズ */ void ShowImg(char *img, int w, int h) { int x, y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { mvaddch(y, x, img[w*y + x]); } } } /* ペンを端末画面に表示する. pen:ペンの状態 x, y:ペンの位置 */ void ShowPen(int pen, int x, int y) { char c; switch (pen) { case 0: c = 'O'; break; // off状態のカーソル case 1: c = '#'; break; // on状態のカーソル } mvaddch(y, x, c); } /* ペンの軌跡を画像に書き込む. img:画像 w:画面サイズ pen:ペンの状態 x, y:ペンの位置 */ void Draw(char *img, int w, int pen, int x, int y) { if (pen) img[w*y + x] = '#'; } ... /* ゲーム本体 fin:操作入力用ファイルポインタ fout:操作記録用ファイルポインタ return:終了状態(0:正常,1:異常) */ int Game(FILE *fin, FILE *fout) //! 型 { ... int key; char *img; // 軌跡画像(動的配列)へのポインタ // 初期設定 erase(); getmaxyx(stdscr, h, w); pen = 0; x = w/2; y = h/2; img = (char *)malloc(sizeof(char)*w*h); // 軌跡画像のメモリを確保 if (img == NULL) goto ERROR; // エラー処理 FillImg(img, w, h, ' '); // 画像を初期化 LOOP: // come from 終了取消 while (1) { // 描画 Draw(img, w, pen, x, y); // 軌跡を画像に記入 erase(); // 画面をクリア ShowImg(img, w, h); // 軌跡画像を表示 ShowPen(pen, x, y); // ペン(カーソル)を表示 refresh(); // 画面を表示 ... if (key == 'q') break; } if (Info("Done? (y/n)", w, h) != 'y') goto LOOP; // 終了確認・取消 free(img); // 軌跡画像のメモリを解放 return (0); // 正常終了 ERROR: // come from malloc() Info("Error... Hit any key!", w, h); // エラー確認 return (1); // 異常終了 } ...
では,pendraw でPDCLスクリプトを再度実行してみよう. ペンが off状態でも,アニメーション表示される.
また,手動操作モードでは, 終了の取り消し(描画の続行)も可能となった.
ファイルやスクリプトによる自動操作モードの途中でも [Q]キーの手動入力によってアニメーションを中止できるようにする.
pendraw では,[!]キーで軌跡をクリアしペンを画面中央に戻す.
pdcl では,resetコマンドで '!' を出力する.
反復回数がゼロ以下(repeat 0 や repeat -1)の場合, そのループ内(その repeat と対になる end まで) のコマンドを無視する.
書式:exec スクリプトファイル名
書式:randdir 反復回数
'h','j','k','l' の内どれか1つのキー文字を連続出力する.
例:randdir 5 ⇨ kkkkk
pendraw では,数字キー [0]〜[8] の入力で色番号を指定. 軌跡画像には文字 '#' ではなく,色番号数字を記録し, その色で文字 '#' を表示する.
pdcl では,数字キーを出力する colorコマンドを追加.
書式:color 色番号
提出: