C言語~ゲームプログラミングの館・32節に関する質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
fffff

C言語~ゲームプログラミングの館・32節に関する質問

#1

投稿記事 by fffff » 17年前

 こんばんわ。
 32節(初期化の箇所)でちょっと分からないところがあったので、質問に来てみました。

 ――――――――――――――――――――――――――――――――――――――――――――――

SRand(10); //乱数の初期値を10で設定。
printfDx("%d\n",GetRand(10000)); //0~10000までの乱数を生成
printfDx("%d\n",GetRand(10000));
printfDx("%d\n",GetRand(10000));
printfDx("%d\n",GetRand(10000));
ScreenFlip();

 ――――――――――――――――――――――――――――――――――――――――――――――

 この SRand という関数は、一体何を意味しているのかがイマイチ分かりにくくて……
 ランダムで数値を入力したいのであれば、()内の GetRand で既に入力できてるというか、
 ここだけでも良いような気がしてきます。

 プログラム全体を見てみると、
 「一度ランダムに入力(出力)された値を、もう一度繰り返して表示する」
 みたいな感じになっているのだと思うのですが、確実にそうだと言い切れる自信がちょっと無くて……

 そもそも、ここの解説で指している『乱数の初期値』というのは、一体どういうものなんでしょうか?

水孤

Re:C言語~ゲームプログラミングの館・32節に関する質問

#2

投稿記事 by 水孤 » 17年前

DXライブラリ置き場 リファレンスページのSRandより引用
コンピューター上の乱数というものはすべて疑似的なものであり、 結果的には計算で算出するので初期値が同じであれば初期値を 設定した後に取得できる乱数は常に同じものとなります。
(中略)
普通ゲームソフトなどでは毎回違う結果が出るように ソフトの起動時にその時のパソコンが保持している日時データなどを 元に初期値を設定したりします。
 DXライブラリでは標準でこの処理を行うのですが、時に自分で 初期値を明示的に設定したい時などがあります。

上に書いてあるように、乱数をといっても完全なランダムではなく、初期値が一緒なら出てくる数字は常に一緒です。そのときの初期値は様々です。しかし、時には乱数を決まった数で出したいときがあり、その時にSRandを使い決まった初期値を設定します。
もし、そのプログラムでもしSRandをなくせば数値は同じ数字は出なくなってしまいます。

管理人

Re:C言語~ゲームプログラミングの館・32節に関する質問

#3

投稿記事 by 管理人 » 17年前

まず、乱数ってなんでしょう?
ランダムな数?
いえ、そうではないんです。
「ランダムなように見える数」です。
randという乱数を生成する関数をご存知ですよね?
以下のプログラムを実行してみましょう。


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

int main(){

	printf("%d\n",rand());
	printf("%d\n",rand());
	printf("%d\n",rand());
	printf("%d\n",rand());

	return 0;
}

実行結果1回目

41
18467
6334
26500

ランダムっぽく見えますね。じゃもう一度実行してみましょう。

実行結果2回目

41
18467
6334
26500

念のためもう一度実行してみましょう。

実行結果3回目

41
18467
6334
26500

よく見て下さい。ランダムな数を生成したはずなのに、プログラムを実行させるたびに同じ数が出ています。
そう、コンピュータは
「適当に作ってくれ」「だいたいでいいから作ってくれ」「いい加減な数を作ってくれ」
という指示が本当に苦手です。
指示したことしかしませんから、乱数も予め用意された値が出ているだけなのです。
これでは使い物になりません。
これでゲームを作ったのでは毎回同じゲーム結果になってしまいます。
ジャンケンを乱数を利用して作ったらいつも同じものしか出さないでしょう。

そこで「初期値」を設定しようとするわけです。
今41が1回目に出ていますが、この最初に出る数を自分で指定してみます。
ためしに1326で設定してみましょう。
初期値を設定する関数はsrand()です。


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

int main(){
	srand(1326);
	printf("%d\n",rand());
	printf("%d\n",rand());
	printf("%d\n",rand());
	printf("%d\n",rand());

	return 0;
}

実行結果

4368
6026
17865
27127

結果が変わりましたね。初期値を設定すると、その初期値に依存した乱数が出続けます。
逆に言えば、同じ乱数の初期値を設定すれば、同じ結果にする事が出来るわけです。

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

int main(){
	srand(111);
	printf("%d\n",rand());
	printf("%d\n",rand());
	printf("%d\n",rand());
	srand(111);
	printf("%d\n",rand());
	printf("%d\n",rand());
	printf("%d\n",rand());
	return 0;
}

実行結果

401
21144
5313
401
21144
5313

初期値を設定し、3回乱数を呼び出してその後で、同じ初期値でまた3回呼び出しています。
すると乱数は同じ乱数が出せています。
これはゲームリプレイを作るときなどによく利用されるものですが、
ゲーム中そこまで利用する機会が無いものなので、
「以前と同じ乱数を出せるもの」とだけ覚えておけばいいでしょう。

DXライブラリでの乱数はいつも適切に適当に初期化してくれているのでいつも違う値が出ますが、
randなどの標準関数はいつも同じ値が出てしまうので、「今の秒数」などで初期化するのが一般的です。

tk-xleader

Re:C言語~ゲームプログラミングの館・32節に関する質問

#4

投稿記事 by tk-xleader » 17年前

コンピューターによる乱数列というのは、完全にでたらめな数ではなくて、コンピューターが順番に計算して出している数の並びなのです。
そこには、ある規則に従われた計算方法が存在し、人間がぱっと見ただけでは計算方法が分からないような数列を成しています。(実は、乱数列から乱数の計算方法を知る事は可能なのです。)

んで、「一度ランダムに出力された値を、もう一度繰り返して表示する」というのは、さっき説明したように、「ある規則に従われた計算方法」で構成された乱数列は、たいていがその乱数列の、「X回前に出力された値とY回目に出力された値を取り出して、これこれこんな計算をして…」といった計算方法が取られています。
つまり、出力された乱数列から計算/出力するわけですから、その計算には、必ず初期値なるモノが必要になります。(要は、出力された乱数列が無いので、最初だけはそれを決める必要があるって事)

なので、初期値を同じにした場合、その後出力された値はずっと一緒ってことになります。
まぁ分かりにくければ、エクセルでちょっと作ってみましたので、初期値のところをいろいろいじくってみてください。(初期値の概念がよく分かるはずです。)

fffff

Re:C言語~ゲームプログラミングの館・32節に関する質問

#5

投稿記事 by fffff » 17年前

>解釈
 ランダムの関数は、ある法則性にのっとって、用意されている一定の値を返す。
 そのため、関数で設定した初期値が同じである以上、同じ値しか返ってこない。
 しかし、初期値を与えてやれば返される数値に変化が起こる。

 Srand は、一度出した値を出したいときに用いる関数である。
 Rand に至っては、常に同じ数値しか返らない。

 ただ、このままでも一定の値しか返らないため、初期値を変更するなりの処置を行い、
 プログラム中で意図的に、数値をいじる必要がある。

 ……と、こんな感じの解釈でよろしかったでしょうか?
 ちょっと回答に自信がないので、どなたかの意見を伺いたいところなのですが……



 それと、少々タイミングが早いのですが、この場を借りてお礼を。

>水狐様
 確か、前回の質問でも助けていただきましたね。お陰で勉強がはかどります。
 いつもありがとうございます。(^^)

>管理人様
 毎度ながらお世話になります。やはり、実例を交えて解説をいただけると非常に分かり易くて助かります……
 今後ともよろしくお願いいたします。それと、今回もありがとうございました。 (_ _)

>tkmakwins15 様
 解説だけでなく、エクセルのファイルまで用意してくださって……(驚愕)
 どうもありがとうございました~。(_ _)
 
 

tk-xleader

Re:C言語~ゲームプログラミングの館・32節に関する質問

#6

投稿記事 by tk-xleader » 17年前

乱数の概念については、大まか合ってます。たいていの場合、毎回違う乱数列が出て欲しいわけですから、初期値には現在時刻などを設定したりします。

ただ、DxライブラリのGetRand()関数は、初期値を設定せずとも、ただ呼び出すだけで、毎回違う乱数が出ます。

SRand()関数の使い方も、大体そうなります。

標準関数のrand()の場合、初期値が毎回同じなので、srand()関数で毎回違う値を指定するわけです。毎回違う値の典型的な例として、現在時刻があるわけです(一度過ぎ去った時は二度と戻ってこないですよね?)

管理人

Re:C言語~ゲームプログラミングの館・32節に関する質問

#7

投稿記事 by 管理人 » 17年前

少し混合されていらっしゃるといけないので改めて説明しますと、
私は先ほど4種類の関数を示しました。

rand()
 ‥stdlibの標準関数で、乱数を生成する関数。初期値を与えないと毎回同じパターンの乱数になる

srand()
 ‥これも標準関数で、rand()関数の初期値を設定する関数。現在の時刻などで初期化するとgood

GetRand()
 ‥DXライブラリの関数で、乱数を生成する関数。初期値を与えなくても毎回違う乱数が出る。

SRand()
 ‥DXライブラリの関数で、乱数の初期値を設定する関数。GetRandは毎回違う乱数が生成されるので
  以前と同じパターンで乱数を生成したい時以外に用いる必要の無い関数

の4つです。
私は上で「予め用意されている値が出ているだけ」と言いましたが、少しニュアンスが正確ではなく
「予め用意された計算式にのっとった値が出ているだけ」が正確です。
実際に見たほうがわかりやすいと思いますので、似たようなことが出来る関数を作ってみました。
以下ご覧下さい。


#include <stdio.h>

int val=32172;

int rand_2(){
	val= val+12345;
	val= val%6827;
	return val;
}

int main(){
	
	printf("%d\n",rand_2());
	printf("%d\n",rand_2());
	printf("%d\n",rand_2());

	return 0;
}

実行結果

3555
2246
937

 
これの意味がお解かりいただけるでしょうか。
前回の計算結果に依存した、適当に計算した結果を返しています。

※わかりやすいように実際とは異なる仕様にしてあります。

では初期化できる関数を追加してみます。


#include <stdio.h>

int val=32172;

//乱数の計算種を初期化
void srand_2(int seed){
	val=seed;
}

//乱数を生成
int rand_2(){
	val= val+12345;
	val= val%6827;
	return val;
}

int main(){

	srand_2(111);
	printf("%d\n",rand_2());
	printf("%d\n",rand_2());
	printf("%d\n",rand_2());
	srand_2(111);
	printf("%d\n",rand_2());
	printf("%d\n",rand_2());
	printf("%d\n",rand_2());

	return 0;
}

実行結果

5629
4320
3011
5629
4320
3011


いかがでしょうか。
このプログラムを理解されれば乱数について少し解ると思います。

fffff

Re:C言語~ゲームプログラミングの館・32節に関する質問

#8

投稿記事 by fffff » 17年前

 rand と srand 、そして Getrand と SRand はそれぞれ違う効果を持つ関数だったのですね……
 文字の大小で区別されてる関数があったとは、調査不足でした。
 tkmakwins15様,管理人様、どうもありがとうございます。



>管理人様
 度々申し訳ありません、質問があります。
 レスで頂いた前半部分の乱数のプログラムは大丈夫なのですが、
 後半のプログラムに関してうまく理解できず、解説をお伺いしたい箇所があります。

――――――――――――――――――――――――――――――――――――――――――――――
//乱数の計算種を初期化

void srand_2(int seed){

val=seed;
――――――――――――――――――――――――――――――――――――――――――――――

 この部分なのですが、void という宣言は、
 これまでのサンプルではあまり見かけなかった宣言のように思います。
 お恥ずかしい限りなのですが、正直に言うと、私はこの void という関数が何を意味しているのかも理解できていません。
 ネット上で検索してみても、どうにもいまいちピンと来るもの(解説)が得られず……

 申し訳ないのですが、この部分の解説をお願いしてもよろしいでしょうか?

木霊

Re:C言語~ゲームプログラミングの館・32節に関する質問

#9

投稿記事 by 木霊 » 17年前

 その部分は「関数が返す値の型」です。

 voidだとその関数は値を返さない、ということです。
 intやdoubleだと値を返す関数ということになるので「return ○○;」(○○のところは数値あるいは変数)
で関数を終わらせる必要があります

fffff

Re:C言語~ゲームプログラミングの館・32節に関する質問

#10

投稿記事 by fffff » 17年前

>木霊様
 ありがとうございます。
 返信が遅くなってしまって申し訳ありませんでした……

閉鎖

“C言語何でも質問掲示板” へ戻る