これまで学んだ
C 言語の様々な機能を総合的に使って,簡単な応用プログラムを作成してみましょう。何を作るのかは皆さんの自由ですが,以下のスライドでは,簡単な ゲームの例を示します。このゲームでは次のような機能が用いられています。
- #define 指令 -
文字列処理
-ファイル入出力
-
疑似乱数
その他に新しい機能として,実行時間の測定方法について学びます。
簡単な応用プログラムとして,タイピングゲームを作ってみましょう。これはディスプレイに表示さ れるランダムな文字を,ユーザー(プレイヤー)ができるだけ素早く正確にキーボードから打ち込 むゲームで,終了後にスコアが表示されます。また,これまでの最高点の保持者の名前がファイ ルに記録されます。
このスライドはこのゲームの実行例です。プログラムを実行すると,端末に 第1回目です.お手本どおりにタイプしてください.
と表示された後,次の行に英字の小文字がランダムに10 個表示されます。たとえばこのスライド の例では:
glsuapspxt
プレイヤーは,この文字列をできるだけ素早く正確にキーボードから入力します。
入力が終わると,プログラムはこの入力が正しいかどうかを判定し,スコアを表示します。この例 では:
正解です.スコアは92点です.
となっています。
このスコアがこれまでの最高得点なら,プログラムは,もしやしてこのプレイヤーはこれまでの最 高記録保持者(この例ではWatanabe さん)ではないかとばかりに,なぜか英語で
New record! Are you Watanabe? Enter your name.
ではこのプログラムの内容を解説します。コードは5枚のスライドに渡ります。1枚目のこのスライ ドは,プログラム冒頭のグローバル変数の宣言などの部分です。
最初に,必要なヘッダファイルをインクルードします。stdio.hは端末入出力,stdlib.hは疑似乱 数,string.hは文字列,time.hは時間計測のために必要です。
続いて,ゲームで使う定数MAXTRY, STRLEN, SIZE を#define 指令で定義します。それぞ れの意味は指令の右にコメントとして書いてあるので確認してください。
さらに#define 指令でSCORE_FILE という定数を“score.dat” という文字列として定義していま す。これは,これまでの最高スコアの値とその達成者の名前を記録するためのファイルの名前を 表す文字列として使います。
続いて,グローバル変数の定義で,上記のファイル用のファイルポインタfp,最高点を格納す
る変数high_score(初期値は0),及び最高記録の達成者名を格納する文字列用の配列
champion(初期値は”Watanabe”)を宣言しています。
このスライドからmain 関数が始まります。最初の6行は変数の宣言です。最初の5つの意味は,
コメントを参照してください。
6つ目の宣言は今回新しく学ぶ内容です。time_tというのは,時刻を抽象的に表すデータ型で,
time.hをインクルードしておくと使えるものです。ここでは2つの変数start_time, end_timeが時刻 を表すデータであると宣言しています。後のコードを読むとわかるのですが,前者は問題を出題 した時刻を表し,後者はプレーヤーの入力が終了した時刻を表し,その差によって入力に要し た時間を計測することを意図しています。
main 関数の実行部分では,最初に名前がSCORE_FILE で表されるファイルを読み込み用
(“r”) にオープンして,ファイルポインターをfpとします。このファイルの実体は#define で定義さ れた“score.dat” で,万一このファイルが存在していなければfp==NULL という条件が真と なり,存在する場合はfp != NULL という条件が真となります。
このファイルには最高スコアの値とその達成者名がこの順番に記録されているので,fscanf関 数を用いて,最高スコアは10進数(%d)で読み込んでint 型変数high_scoreに格納し,達成者 名は文字列(%s)で読み込んでchar 型配列(文字列)champion に格納します。(配列にデータを 読み込むときは,配列名の左に& を付けないことを思い出してください。)その後,忘れないうち にこのファイルをクローズします。
このスライドは,問題(ランダムな文字列)を生成して出題し,プレイヤーの入力を読み込み,入 力にかかった時間を計測する部分です。
問題はランダムに生成するので,現在時刻time(NULL) を用いて,疑似乱数のシード(種)を
srand関数で初期化します。
いよいよゲーム開始ですが,プレイヤーにMAXTRY (=3) 回のトライを可能とするために,1か らMAXTRY まで動く制御変数try を用いたfor 文で,以下の処理をMAXTRY 回だけ反復し ます。各回の最初では,何回目か(=try の値)を示すとともに,タイプを促すメッセージを表示し ます。
続いて,問題を生成します。問題は英字の小文字をランダムに生成して作ります。そのため,
rand() で生成した疑似乱数(整数)を26で割った余り(0~25のほぼランダムな値となる)を文
字’a’ に加算することで,文字’a’~’z’ をほぼランダムに生成します。
これを所定の文字数の回数,すなわちSTRLEN (=10) 回繰り返し,文字配列の要素
problem[0] からproblem[STRLEN-1] までに格納します。その末尾problem[STRLEN] には,
C 言語の約束にしたがって,ヌル文字を格納します。
printfによってこの文字列を表示することによって,問題が出題されたことになります。
ここでプレイヤーが入力する文字列をscanf(“%s”, input) によって文字配列input に読み込む ことになりますが,その時間を測定するために,scanfを始める直前の時刻をstart_timeに記録し,
scanfが終わった直後の時刻をend_timeに記録します。
このスライドは,プレイヤーの入力が正しいか否かを判定し,入力に要した時間を考慮して,ス コアを計算する部分です。
出題した文字列problem とプレーヤーが入力した文字列input が等しいかどうか,strcmp関数 で判定します。
文字列が等しいときはその関数値は0 になるので,「正解です.」と表示します。
入力に要した時間は,出題時と入力完了時の時刻の差end_time - start_time(単位 は秒)で得られます。100から入力時間を差し引いた値をスコアとします。ただし,その値が負に なるときは,スコアを 0 点とします。つまり,スコアは,入力が一瞬で終わったら100点,100秒 以上かかったら 0 点です。
一方,2つの文字列が等しくないときは,「間違いです.」と表示し,スコアを0点にします。
このスライドはプログラムの最後の部分で,今回のスコアがこれまでの最高スコアを超えたとき の処理を含みます。
まず,前のスライドで計算したスコアscore を表示します。
続くif 文で,score がこれまでの最高スコアhigh_score(スライド3/6 のfscanfでファイルから読 み込んだ数値)を超えるかどうかを判定します。
もし超えていたら,今回のscore をhigh_scoreに格納することにより,最高スコアの値を更新し ます。
そして,新記録であること(New record!) を表示し,このプレイヤーがこれまでの最高スコアの 達成者champion(スライド3/6 のfscanfでファイルから読み込んだ文字列)であるかもしれない ので,そのこと(Are you …?) を表示し,続いてプレイヤーの名前を入力(Enter your name.) させ ます。その入力によって,champion に格納されている文字列(記録保持者の名前)が更新されま す。
以上を反復するのがfor ループです。反復が終わったら,先ほど読み込み用にオープンした ファイルSCORE_FILE を今度は書き込み用(“w”) にオープンし,最高スコアhigh_scoreと記録
保持者名champion をそれぞれ10 進数(%d) と文字列(%s) の書式で書き込み,クローズしま
す。これでプログラムが終了です。