連携処理5:スクリプト処理2

授業内容に入る前に,「高専生活に関するアンケート」を済ませよう. Blackboard にログイン → コース:[2018 年度]高専生活に関するアンケート(3J)
掲載されているアンケートの説明・手順をしっかり読むこと.

今回の授業内容は,前回の続きです. 開発中のエデュテイメントアプリの完成度を高めよう. (もし,前回の作業が完了していない場合, まずは大至急,追いつくこと. pdcl は ver.2,pendraw は ver.4.)

教科書の該当範囲:なし
参考書の該当範囲:なし
参考資料:cursesライブラリの超てきとー解説

準備

作業用のディレクトリとファイルを用意し, 開発中のアプリの現在の状態を確認しておこう:

$  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);			// 異常終了
}

...
動的2次元配列 char *img の利用方法については, 以前の課題プログラム ttt.c を参考にしよう.

では,pendraw でPDCLスクリプトを再度実行してみよう. ペンが off状態でも,アニメーション表示される.

また,手動操作モードでは, 終了の取り消し(描画の続行)も可能となった.


本日の課題

  1. pendraw に自動操作中断機能を追加せよ.
  2. ファイルやスクリプトによる自動操作モードの途中でも [Q]キーの手動入力によってアニメーションを中止できるようにする.

    Hint:自動モードではファイル入力だけでなくキー入力を追加する. ただし,timeout(0) でキー入力なくても待たない. 一方,手動モードでは timeout(-1) でキー入力を待つの.
  3. pendrawpdcl にリセット機能を追加せよ.
  4. pendraw では,[!]キーで軌跡をクリアしペンを画面中央に戻す.

    pdcl では,resetコマンドで '!' を出力する.

  5. 独自に考案した図案を描くようなPDCLスクリプトを作成せよ.
上級者向け課題
  1. pdclrepeatコマンドの不具合を解消せよ.
  2. 反復回数がゼロ以下(repeat 0repeat -1)の場合, そのループ内(その repeat と対になる end まで) のコマンドを無視する.

    Note:多重ループでも適切に処理できること.
    Hint:proc() の引数として,無視する/しないのフラグ変数を追加. 反復回数を1回とし,無視フラグ off として再帰呼び出し. 無視フラグ on の場合,repeat-end 以外のコマンドを読み飛ばす.
  3. pdcl に サブルーチン(外部スクリプトファイル)を実行するための execコマンドを追加せよ.
  4. 書式:exec スクリプトファイル名

    Note:fclose() を忘れるな.
  5. pdcl にペンをランダムな方向へ移動させるための randdir コマンドを追加せよ.
  6. 書式:randdir 反復回数

    'h''j''k''l' の内どれか1つのキー文字を連続出力する.

    例:randdir 5 ⇨ kkkkk

    Hint:ソースコード的には, char s[] = "hjkl" としておいて s[...] の出力でも良いが, 変数を使わず "hjkl"[...] とするのが効率的.
  7. ペンの軌跡をカラー化せよ.
  8. pendraw では,数字キー [0]〜[8] の入力で色番号を指定. 軌跡画像には文字 '#' ではなく,色番号数字を記録し, その色で文字 '#' を表示する.

    pdcl では,数字キーを出力する colorコマンドを追加.
    書式:color 色番号

  9. その他,独自のアイディアにより改良せよ.

提出:


(c) 2018, yanagawa@kushiro-ct.ac.jp