Powered by SmartDoc

ソフトウェア概論及び演習[演習] (2006/11/17)
Ver. 1.0

2006年11月17日
栗野 俊一
kurino@math.cst.nihon-u.ac.jp
http://edu-gw2.math.cst.nihon-u.ac.jp/~kurino/2006/soft/soft.html
ソフトウェア概論及び演習Tom & jerry の解説

目次

実習の目標

モジュール

C言語に関らず、プログラミング言語では、複数のプログラム部品を組み合わせることによって一つのプログラムを作りあげることができる。

このように、組み合わせを前提に作成されたプログラムの部品を「モジュール」と呼ぶことにする。

C言語では、「関数」が、「モジュール」となる。

C言語のプログラムでは、(原則として) main関数が必要だが、main関数以外の関数は、モジュールとして扱われる。

実習の目標

本日の実習の目的は、モジュールの利用によって様々な利点が得られるので、それを体験しようというものである。

実習の内容

実習の材料

今回の実習では、前回 (2006/11/10) の演習の課題soft17_1を題材とする。

ファイル分割

soft17_1は、既に複数の関数からなっているので、このままでも良いのだが、後のことを考えて、次のような形で、ファイルを分割する。

game.c以外は、該当する関数を単にそのまま、抜き出して、新しい名前を付けて保存するだけである。game.cは元のsoft17_1.cから、逆に、該当する関数を取り去ったものであるが、上記にあるように、取り去った後に、#includeを指定することによって、結果的に、元のsoft17_1.cと同じように動作する。

表示の変更

表示周りは、全てdisplay.cに集まっているので、これを変更することにより、表示の様子を変更することができる。

エスケープシーケンス

エスケープシーケンス(1)機能とは、特別な文字列(2)を、画面上(3)に出力することにより、様々な効果をもたらす機能のことであり、状況によって使えたり、使えなかったりするのだが、Windows 上では利用可能なので、これを利用して、表示上の効果を実現する。

  1. C言語のprintf関数で利用するエスケープシーケンス(\t,\nなど.. )と同じ呼び方だが、異なるものであることに注意。ややっこしいが...。
  2. この文字列をエスケープシーケンスと呼ぶ
  3. 画面以外では意味がないことに注意。画面特有の機能と考えてよい。

エスケープシーケンス機能の利用

エスケープシーケンス機能は、単に、出力する文字列に特別な符号を追加するだけであるが、プログラムの読みやすさを実現するために、エスケープシーケンス機能を実現するためファイル( esc.h )を作成し、それをdisplay.cの中で利用する。

esc.h
#define crt_flush() fflush(stdout)
#define crt_out(s) fputs(s,stdout);crt_flush()
#define crt_pos(x,y) printf("\x1b[%02d;%02dH",(y)+1,(x)+1)
#define crt_clear() crt_out("\x1b[2J")

#define	CRT_BLACK	30	// 黒
#define	CRT_RED		31	// 赤
#define	CRT_BLUE	32	// 青
#define	CRT_PURPLE	33	// 紫
#define	CRT_GREEN	34	// 緑
#define	CRT_YELLOW	35	// 黄
#define	CRT_SKY_BLUE	36	// 水色
#define	CRT_WHITE	37	// 白

#define	CRT_DEFAULT	0	// デフォルト
#define CRT_REVERSE	7	// 反転

#define crt_color(color) printf("\x1b[%dm",color)

表示の変更

表示の変更として、次の三つを行う。

トムの振舞いの変更

トムの振舞い

トムの振舞いは、tom.cの中で記述されているjump_distanceによって定められている。

この関数の振舞い、簡単に言えば、次のような流れになっている。

この方法なので、次のような現象がおきる。

これは、ちょっと、トムも芸がないし、また、ジェリーの逃げ方と無関係に勝敗が決るのもつまらない(4)

そこで、tom.c (の中のjump_distance )を変更して、もう少しゲーム風にしてみよう。

  1. まあ、トムがジェリーの周りをウロチョロして、中々捕まらないという点では、確かに、原作に忠実といえないこともないが...。

トムの振舞いの設計

では、トムの振舞いをどのように考えてみればよいだろうか?トムがアニメの主人公(?)としても、やっぱり、現実の制約を受けることは間違いない。特に、トムはジェリーに比較して体が大きいので慣性法則は、無視できないだろう。

そこで(5)、次のような方針を考える。

  1. などと、色々ともっともらしいことを述べているようだが、当然、これは、単に、次の設計方針を正当化するためだけの「故事付け」でしかない。

トムの振舞いの変更

上記の設計方針の為に、プログラムに次の変更を加える。

再設計

上記のトムの設計だと、最初、巣穴の前に待ち構えていたトムが急激にジェリーに近付いてくる様子が実現され、最初の要望は改善されたのだが、問題は、一旦すれちがってしまうと、もう、トムがジェリーに追い付くことができない。

方向転換が難しいという点が仇になったわけだ。

これでは、ゲームとして余りにも面白くないので、方向転換が急激にできるようにしよう(6)

すなわち、次のような変更をtom.cの中にあるjump_distanceに加えることにする。

tom.c の変更前
  } else if ( d > 0 ) {		/* すれちがった */
    tom_v = tom_v + 1;		/* 右方向に加速 */
  } else {
tom.c の変更後
  } else if ( d > 0 ) {		/* すれちがった */
    if ( tom_v < 0 ) {		/* すれちがったので急転換を許す */
      tom_v = 2;
    } else {
      tom_v = tom_v + 1;	/* 右方向に加速 */
    }
  } else {

また、すれちがった後に、追い掛ける余裕を与えるために、ゲーム板を少し大きくしてみよう。この為に、game.cに手を加えよう。

game.c の変更前
#define  LENGTH      54         /* 通路の長さ */
#define  HOLE        50         /* 穴の位置 */
game.c の変更後
#define  LENGTH      64         /* 通路の長さ */
#define  HOLE        60         /* 穴の位置 */

これで、多少ゲームとしてバランスが取れるようになった。

  1. 「慣性の法則」はどうなったんだとの、お叱りの声も聞こえそうだが、なんせ、トムはアニメの主人公なのだから... (と、さっきと全く違う主張を... )

ジェリーの挙動

ジェリーは人間が操作することになっているが、これを計算機に任せることを考えてみよう。

この為には、jerry.cのrunaway_distanceを書き換えれば良い。この関数は、引数として、人間から入力をおこなっているが、これは無視して、計算機の考えた結果を返せばよい。

ここでは、簡単に、トムの挙動を無視して、兎に角、穴に入ることを考えることしよう(7)

jerry.c の変更後の runaway_distance
int runaway_distance(int cmd)
{

  switch ( HOLE - jerry ) {	/* もし、移動可能な場所に HOLE があれば */
  case -1:
  case 1:
  case 3:
  case 5:
    return HOLE - jerry;	/* HOLE に飛び込む */
    break;
  default:			/* そうでなければ、ひたすら右へ.. */
    return 5;
  }
}
  1. 当然、このような形では、トムにあっというまに食べられてしまう..

提出

自分なりに作った、jerry.cを提出してください。

Link