プログラミング コラム

ハイ・アンド・ローを作る 第1回


今回から数回に分けて、プログラミング初心者にお勧めのテーマ「ハイ・アンド・ロー」をC言語で作ってみたいと思います。

ハイ・アンド・ローは、いわゆる「数当てゲーム」で、コンピュータが無作為に決定した数値(正解)をプレイヤーが予想します。
ただ、当てずっぽうでは中々正解しないので、正解とプレイヤーが選んだ数値が異なる場合、その大小関係をヒントとして表示します。

例)正解が 50 の場合

プレイヤーが 40 を入力 = 正解の方が大きいです
プレイヤーが 60 を入力 = 正解の方が小さいです
プレイヤーは 50 を入力 = 正解!

このように、ヒントを頼りに正解するまでプレイヤーは入力を続けます。

プログラミングを始めたばかりの頃は、作りたいものはあっても
どうやって作れば良いのか?どこから作れば良いのか?イメージができないことも多いですが、
私と一緒に、ゆっくり、少しずつ作っていきましょう。

まず、このゲームで必要になるのは、正解となるコンピュータが無作為に決めた数値です。
無作為な数値を得るためには「乱数」を使う必要がありそうですね。
ゲーム全体のことは少し先において、乱数の練習をしてみましょう。

今回は1~100までの数値を正解の選択範囲にします。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int answer;

	srand( time(NULL) );

	answer = (rand() % 100) + 1;
	printf("answer = %d\n" , answer);	

	return 0;
}

srand関数で乱数の基準値(種)を指定し、rand関数で乱数を生成しています。
C言語のrand関数は、srand関数で指定された基準値を元に生成されるため、同じ基準値であれば同じ乱数が生成されます。

試しに、以下のように基準値を 1 に固定して複数回乱数を生成してみましょう。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int answer;
	int i;

	srand( 1 );
	
	for(i = 0;i < 10;i++)
	{
		answer = (rand() % 100) + 1;
		printf("answer = %d\n" , answer);	
	}

	return 0;
}

このプログラムを何度か実行してみて下さい。
確かに無作為な数値ですが、毎回同じパターンの数値になっているはずです。

ということは、プログラム実行時に毎回異なる数値をsrandに与える必要がありますね。
一般的には「プログラム実行時の時刻を与える」手法を使います。

time関数はUNIXタイムスタンプ(エポック秒)を取得します。
UNIXタイムスタンプは1970年1月1日からの経過秒数で、プログラムで時間を扱う際は幅広く採用されています。

では、time関数の実験をしてみましょう。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{	
	printf("現在のUNIXタイムスタンプ = %ld\n" , time(NULL) );
	
	return 0;
}

このプログラムを実行すると、桁の多い数値が表示されるはずです。
しばらく時間をおいて、何度かプログラムを実行してみましょう。
少しずつ数値が増えているはずです。

UNIXタイムスタンプは秒数なので、1秒経過すれば異なる数値になります。
この数値を乱数の基準値に指定することで、毎回異なる乱数を生成できそうですね。

さて、最後に「どうやって1 ~ 100までの乱数を生成するか?」を考えてみます。
最近の言語では、簡単に任意の範囲で乱数を得ることもできますが、残念ながらC言語にはありません。
rand関数の戻り値は 0 ~ 32767(開発環境によって異なります) の範囲から無作為に選ばれた整数になります。

数値を任意の範囲に収めるには剰余を使うテクニックが一般的です。
例えば、ある数値を 10 で割った余りは、必ず 0 ~ 9 になりますね。
この特性を活かし、rand関数の戻り値を欲しい範囲の数値で剰余してみましょう。
今回は 1 ~ 100 まで、100通りの数値なので、以下のように100で剰余します。

rand() % 100

しかし、これでは得られる数値の範囲は 0 ~ 99 になりますね。
そこで、剰余の結果に 1 を加えて、数値の範囲をずらしてみましょう。

(rand() % 100) + 1

これで 1 ~ 100 までの乱数を生成することができました。

さて、ここまでくると、最初に書いたソースコードの意味が鮮明になっていませんか?

今回お伝えしたかったのは、プログラミングに自信が持てなかったり、常にバグに悩まされてしまう状況は、
よく分からないもの(理解していないもの)が集まってしまうことが大きな原因ということです。

この記事で最初に書いたソースコードを、そのままコピーしても動くでしょう。
そこで安心せず、乱数や時刻など、個々の仕組みについて、少し掘り下げて確認してみましょう。
これを繰り返していくと、徐々に分からない部分が消え、何のためにそのコードを書いているのか鮮明になります。

また、プログラミングを始めたばかりの頃は、初めからプログラム全体の事を考えてしまいがちです。
まずは一つ一つの仕組みを丁寧に確認してから、次の段階に進みましょう。

面倒に感じるかもしれませんが、それが一番の近道だと思います。

次の記事では、プレイヤーの入力と正解の判定をテーマにします。
written by Tomoji Onishi / 2023.01.08
コラム一覧