第2章20 do~while文で繰り返し処理を作る@イチからゲーム作りで覚えるC言語

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章21 for文で繰り返し処理を作る
NEXT : 2章21 for文で繰り返し処理を作る
2章19 while文で繰り返し処理を作る : PREV

この記事でやること

前回はプロジェクト「0150_while」を新しく作り、暗黙の型変換ルールについてお話ししました。
今回は、新しくプロジェクト「0160_doWhile」を作り、繰り返し処理を行うdo ~ while文についてお話します。この書き方を知っていることで、特定の処理をループ(繰り返し)させることで同じ処理を何度も書く必要がなくなります。

なお、繰り返し処理はC言語で幾つかあります。下の順番でお話したいと思います。

  1. while ( 繰り返す条件 ) {… 繰り返す内容 …}
  2. do { … 繰り返す内容 … } while ( 繰り返す条件 ) ←ココのお話
  3. for ( 最初の処理 ; 繰り返し条件 ; 繰り返し完了時の処理 ) {…繰り返す内容… }
  4. 繰り返し処理の多重構造と break、continue などのジャンプ文
この記事はゆる~くC言語でコンソールゲームを作りながらプログラミングを学ぶための連載記事です。シリーズものですので記事の一覧はこちらを参照してくださいね。

繰り返し処理を行うプログラム

繰り返し処理をくみこんだソースコードを実際にプログラムを動かして結果を見てみましょう。

#include <stdio.h>
int main() {
 int hp = 40;       // 体力
 int maxhp = 100;   // 最大体力
 int mp = 3;        // 魔力
 int maxmp = 3;     // 最大魔力
 int kaifuku = 25;  // 回復魔法で回復する体力
 char namae[] = "ぷらんく";
 printf("%s の体力は %d / %d です。\n", namae, hp, maxhp);
 do {
   if ( mp <= 0 ) { // 魔力が 0 以下なら
     printf("魔力が不足しています。\n");
     break;
   }
   mp--;
   hp = hp + kaifuku;
   if (hp > maxhp) { // 体力が最大体力以上なら
     hp = maxhp;
   }
   printf("回復魔法で %s の体力が %d 回復しました。\n", namae, kaifuku);
   printf("%s の体力が %d / %d になりました。\n", namae, hp, maxhp );
   printf("%s の魔力が %d / %d になりました。\n", namae, mp, maxmp);
 } while( hp < maxhp );
 printf("%s の回復がおわりました。\n", namae);
}

このコードを実行してみるとこんな結果になったかと思います。

ぷらんく の体力は 40 / 100 です。
回復魔法で ぷらんく の体力が 25 回復しました。
ぷらんく の体力が 65 / 100 になりました。
ぷらんく の魔力が 2 / 3 になりました。
回復魔法で ぷらんく の体力が 25 回復しました。
ぷらんく の体力が 90 / 100 になりました。
ぷらんく の魔力が 1 / 3 になりました。
回復魔法で ぷらんく の体力が 25 回復しました。
ぷらんく の体力が 100 / 100 になりました。
ぷらんく の魔力が 0 / 3 になりました。
ぷらんく の回復がおわりました。

疲れて体力のおちた ぷらんく が回復魔法を使って、魔力があるなら最大体力になるまで回復し続けるプログラムです。

do~while繰り返し文とは

do~while 文とは、1回以上繰り返し処理をするような、ループ処理を作るのに向いています。書き方は下のようになります。

do { …繰り返し処理… } while ( 繰り返し条件 );

プログラムは上から下に順番に処理されていき while ( 繰り返し条件 )の条件に合致する(繰り返し条件≠0のとき)とき、 do { …繰り返し条件… } の中の頭から処理を繰り返します。

流れは下のようなイメージです。

do~while文の処理の流れ

do~while文の処理の流れ

ソースコードの処理を追ってみる

今回のソースコードの中身を確認してみましょう。
9行目までは変数の宣言と初期化をしているだけですね。

 printf("%s の体力は %d / %d です。\n", namae, hp, maxhp);

9行目で一部の変数を使ってプレイヤーのステータス(体力)を表示しています。
この時点では、それぞれの変数はこんな内容になっています。

  • int 型変数の hp には 整数 40 が入っている。体力。
  • int 型変数の maxhp には 整数 100 が入っている。最大体力。
  • int 型変数の mp には 整数 3 が入っている。魔力。
  • int 型変数の maxmp には 整数 3 が入っている。最大魔力。
  • int 型変数の kaifuku には 整数 25 が入っている。回復魔法で回復する体力の幅。
  • char型配列の変数 namae には “ぷらんく” という文字列が入っている。プレイヤーの名前。

10行目からが do~while文 (繰り返し文)となっています。

 do {
   if ( mp <= 0 ) { // 魔力が 0 以下なら
     printf("魔力が不足しています。\n");
     break;
   }
   mp--;
   hp = hp + kaifuku;
   if (hp > maxhp) { // 体力が最大体力以上なら
     hp = maxhp;
   }
  printf("回復魔法で %s の体力が %d 回復しました。\n", namae, kaifuku);
  printf("%s の体力が %d / %d になりました。\n", namae, hp, maxhp );
  printf("%s の魔力が %d / %d になりました。\n", namae, mp, maxmp);
} while( hp < maxhp ); ) {

10行目の「do {」自体は特になにも処理はされず、次の行にすすみます。

11行目から14行目で、if文を使った、条件に合致するときのみ実行される処理が書かれています。if 文の構成は下の部分です。

   if ( mp <= 0 ) { // 魔力が 0 以下なら
     printf("魔力が不足しています。\n");
     break;
   }

魔力(mp)が 0 以下のときだけ、12行目~13行目が実行されます。
※if 文については以前お話しているので、見返す場合にはこちらからどうぞ!

さて、11行目に初めて来たときは、 変数 mp は 3 なので、条件には合致しません。( 条件「mp <= 0」の結果は 偽であり、0であり、falseとなります。)ですので、12行目~13行目は実行されず、14行目の「}」の次にジャンプします。

15行目では mp–; という式が書いてあります。

 mp--;
 hp = hp + kaifuku;

これは mp = mp – 1; と同じ意味となります。mp を 1 減らしています。
この時点で、mp(魔力)が 3 から 2 に減ります。
また、16行目で、 hp が kaifuku(25)ぶん増加します。hp は 40 から 65 に増えますね。

17行目からは、別の if 文が書いてあります。

 if (hp > maxhp) { // 体力が最大体力以上なら
   hp = maxhp;
 }

hp(体力)が maxhp(最大体力)を超えて回復した時を考えて、もしも体力あふれて鼻血が出るようなときは、「hp = maxhp;」 で hp を最大体力に合わせるように代入しています。

最初にここを通過するときは、 hp > maxhp の条件に合致しないため、中身は実行されずに if の終了である 19 行目の直後にジャンプします。

20行目~23行目はプレイヤーのステータスを表示しています。

 printf("回復魔法で %s の体力が %d 回復しました。\n", namae, kaifuku);
 printf("%s の体力が %d / %d になりました。\n", namae, hp, maxhp );
 printf("%s の魔力が %d / %d になりました。\n", namae, mp, maxmp);

24行目で、繰り返すかの条件チェックが行われます。

 } while( hp < maxhp );

while の条件は「体力(hp) < 最大体力(maxhp)」 であることとなっています。
つまり、まだプレイヤー体力がいっぱいではなく、回復する余地があるときは、ループするということです。1回目にここに到達したときは、
「65 < 100」 であり、条件に合致するので、 10 行目の 「do {」にジャンプして、同じ処理を繰り返します。

do~while を繰り返した時の変数の動き

10行目の「do {」、24行目の「 } while ()」に来た時の変数の動きは下のようになります。

do ~ while 繰り返しと、変数の中身
do~while回数コード行hp(体力)mp(魔力)
はじめて10行目 do {403
24行目 while652
2回目10行目 do {652
24行目 while901
3回目10行目 do {901

3回目の繰り返し処理で、15行目からの処理を見てみましょう。
15行目で mp(魔力) は 1 から 0 になり、
16行目で hp(体力)は 90 から 115 になります。

 mp--;
 hp = hp + kaifuku;
 if (hp > maxhp) { // 体力が最大体力以上なら
   hp = maxhp;
 }

17行目の if 文で、「 hp > maxhp」は「115 > 100」となり条件を満たしているので、 18 行目の hp = maxhp; が実行され、hp(体力) に 100 が代入されます。(最大体力を超えることがない)

その後、23行目まですすみ、while ( hp < maxhp ) の条件「hp < maxhp」は、「100 < 100」ですので、条件は満たしていないこととなり、do~while 文のループから抜け出すこととなります。

do~while文の中で使えるジャンプ文

while文と同様、繰り返し処理の{ … }の中で特定の場所にジャンプするための文があります。ここでは break文continue文についてお話します。

do~while文の中のbreak文

今回のサンプルプログラムでも下の部分で break; 文は使ってますね。

   if ( mp <= 0 ) { // 魔力が 0 以下なら
     printf("魔力が不足しています。\n");
     break;
   }

例えば、今回のプログラムで最初のプレイヤー mp(魔力)を 3 ではなく、1 などにすると、do~while のループの中で、体力が最大になる前に魔力が 0 になり、この if 文の中が実行されます。

break文が実行されると、do~while文の繰り返し処理から抜け出して、その直後から処理を続行します。下のようなイメージになります。

do~while文の中で break 文を実行したとき

do~while文の中で break 文を実行したとき

例えば、mp = 1 としたときは、1度だけ do~while をループして、下のような結果になります。

ぷらんく の体力は 40 / 100 です。
回復魔法で ぷらんく の体力が 25 回復しました。
ぷらんく の体力が 65 / 100 になりました。
ぷらんく の魔力が 0 / 3 になりました。
魔力が不足しています。
ぷらんく の回復がおわりました。

do~while文の中のcontinue文

今回のサンプルプログラムでは continue 文はありませんが、do~while文の中で 「continue;」と書くと、do { …繰り返し処理…} の中の最後にジャンプします。
繰り返し処理の途中で、次の繰り返しに移りたい時などに使われます。
ジャンプのイメージは下のようになります。

do~while文の中で continue文を使ったときの流れ

do~while文の中で continue文を使ったときの流れ

無限ループや最初の処理にご注意!

do~while 文では最初の一回は実行される処理が書きやすい文となっています。一回は実行されるけど、問題ないか、プレイヤーのいろいろなパラメータを考えて、繰り返し処理を書いてあげる必要があります。

今回のサンプルプログラムでは、プレイヤーの体力が最大のときでも回復魔法を使って mp を消費してしまっていますね。
具体的には、hp が 100、maxhp が 100 のときでも魔力を 1 使って、回復魔法を使ってしまう処理となっています。魔力のムダですね。

これはゲームシステムとして良いかはさておき、do~while 文は必ず繰り返し内容が、一回は実行されるので、思わぬバグにならないように、より注意して、いろいろな数値のケースを考えてプログラミングする必要があります。

この辺りはプログラムの「テスト」というコードを書くことによって、バグに気づける可能性が上がったりします。プログラムのデバッグ、テストについては後の章でお話できればと思います。

今回はここまで。お疲れさまでした。

あとがき

繰り返し文の一つである do~ while 文をお話しました。
while 文を理解した後であれば、わりと理解しやすかったのではないでしょうか。ただ単に do~while 文だけだと単調になってしまいますので、今回は if 文を while 文の中に混ぜ込んで、少しゲームプログラミングでも使えるような実用的な流れを書きました。
今後も繰り返し処理はいろいろなところで使われる予定です!

今回はここまで。おつかれさまでした。

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章21 for文で繰り返し処理を作る
NEXT : 2章21 for文で繰り返し処理を作る
2章19 while文で繰り返し処理を作る : PREV

非常に参考になったサイトさまや、参考文献など

ページの更新履歴

更新日更新内容
更新なし