10月からC言語を習い始め、学校で以下のような課題が出たのですが全くわかりません
問題
1から30までの範囲の乱数を5つ発生させる.ただし,発生させる乱数は必ず前の数よりも大きいものとし,それ以上大きいものが必要な数だけ出せなくなった場合には,それが判明した時点でストップさせるようにすること.
・最後まで表示できた場合の出力例
Random numbers: 2 10 17 24 26
・途中で打ち切られた場合の出力例
Random numbers: 25 28 -- Sorry! Impossible to print all.
特にわからないのは「発生させる乱数は必ず前の数よりも大きいものとする」ところと、どのように条件付けしてストップするのかです
どなたか回答・解説していただけると幸いです
助けてください
Re: 助けてください
俺も迷いましたが
乱数の範囲を「割った余り」の考え方で制御
↓
直前に出した乱数が30だったらそこで打ち切り
違ったら乱数を出しなおす
これでいけないですかね?
乱数の範囲を「割った余り」の考え方で制御
↓
直前に出した乱数が30だったらそこで打ち切り
違ったら乱数を出しなおす
これでいけないですかね?
毎回ゲーム作ろうとするたびに壁にぶち当たる
Re: 助けてください
以下のコードを見て、理解できたら教えてください。
尚、わざと汚く書いています(このまま提出したら怒られると思います)
理解してからきちんと書き直して提出することをお勧めします。
わからないことがあればちゃんと言ってください。時間がある限り教えますので^^
尚、わざと汚く書いています(このまま提出したら怒られると思います)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(){
int num[5];
srand((unsigned)time(NULL));
num[0] = rand()%30+1; printf("%2d ",num[0]);
for(int i=1;i<5;){
if( num[i-1]+i>=30 ) goto ERROR;
num[i] = rand()%30+1;
if( num[i-1] < num[i] ){
printf("%2d ",num[i++]);
}
}
return 0;
ERROR:
printf("Sorry! Impossible to print all.\n");
return 1;
}
わからないことがあればちゃんと言ってください。時間がある限り教えますので^^
ほら、来いよ!! 誤字や矛盾を指摘したい奴から、前に出てこいよぉおおおおおおおッ!!!
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※
Re: 助けてください
なので単に30だけではいけない。168 さんが書きました:それ以上大きいものが必要な数だけ出せなくなった場合には,それが判明した時点でストップさせるようにすること。
例えば 29, 30 Sorry! Impossible to print all. という表示はNGで、29の時点でSorry! Impossible to print allを出さなければならない。
なぜならば、前回より大きい値を最後まで出し続けなければならないからです。それが途中で不可能になった時点で中断出力を行うのが、キモですね。
ちなみにプログラムは全体を一気に考えるのではなく、いくつかに分けて段階を踏んで考えていくと良いと思います。今回で言えば
A. まずは1から30の範囲で乱数を発生させるプログラム
B. 次は、Aで作ったプログラムを利用して、前回の値より大きい数字だけを表示させるプログラム
C. そして、途中で打ち切りSorry! Impossible to print allを表示させるプログラム
くらいに切り分けて進めていくといいと思いますよ。
参考に示されたコードが、果たしてそれぞれをどのように実装しているのか、それぞれのどの部分がどのコードに対応しているのかを見ながら読んでいくと、理解もしやすくなると思います。
Re: 助けてください
そのまま提出できないような書き方ですが、参考になりますか?
rand() の呼び出しは最大 5回です。
#include <stdio.h> // printf, putchar
#include <stdlib.h> // srand, rand
#include <time.h> // time
int main(void)
{
int n, r, i;
srand(time(0));
for (r = i = 0, n = 30; i < 5 && n > i; i++, n = 30 - r)
printf("%d ", r += rand() % n + 1);
if (i < 5) printf("Sorry! Impossible to print all.");
putchar('\n');
return 0;
}
Re: 助けてください
出来るだけわかりやすく書いてみました。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main( int argc, char **argv )
{
int Min; /* 乱数発生値の下限 */
int Val; /* 発生させた乱数値 */
int i;
/* 下限値初期化 */
Min = 1;
/* 乱数初期化 */
srand(time(0));
/* 処理本体 */
for ( i = 0; i < 5; i++ )
{
/* 下限値が30を超えたら「最後まで表示出来なかった」*/
if ( Min > 30 )
{
printf("Sorry! Impossible to print all.");
break;
}
/* 乱数発生 */
Val = rand() % (30 - Min + 1) + Min;
/* 下限値更新 */
Min = Val + 1;
/* 発生値表示 */
printf("%d ", Val );
}
printf("\n");
getchar();
}
Re: 助けてください
他の方と被りますが手順としては、
1.30以下の乱数を発生させる
2.発生した乱数を下限値として保持しておく
3.下限値から判定して残りの個数分乱数が発生できない場合は打ち切る
となるかと思いますが、3の打ち切り判定がネックかなと思います。
打ち切られています。
これは乱数を5個発生させなければならないという条件から、2回目で28が出てしまうとあと3個乱数を発生させることができないために
打ち切る必要があるものと認識しています。
そのため30までの乱数を前回よりも必ず+1させた上で5個発生させる場合、
一番大きい値(しきい値)は以下の様になります。
1回目:26 2回目:27 3回目:28 4回目:29 5回目:30
上記の通り、1回目の乱数が26を超えた場合には残り4個の乱数を出力できないので
打ち切りとなります。
何回目の乱数を発生するのかをNにして一般化すると、N回目の乱数は30-(5-N)以下である必要があります。
(打ち切りの場合の出力例では1回目は25で1回目のしきい値以下なので継続、
2回目は28で2回目のしきい値を超えているので値の出力後打ち切るという流れと思います)
打ち切り判定をいつやるかとその判定内容がネックかと思います。
1.30以下の乱数を発生させる
2.発生した乱数を下限値として保持しておく
3.下限値から判定して残りの個数分乱数が発生できない場合は打ち切る
となるかと思いますが、3の打ち切り判定がネックかなと思います。
上記の出力例を見ると二回目に28が出力されていて、まだ29、30が出力できるにも関わらず168 さんが書きました: ・途中で打ち切られた場合の出力例
Random numbers: 25 28 -- Sorry! Impossible to print all.
打ち切られています。
これは乱数を5個発生させなければならないという条件から、2回目で28が出てしまうとあと3個乱数を発生させることができないために
打ち切る必要があるものと認識しています。
そのため30までの乱数を前回よりも必ず+1させた上で5個発生させる場合、
一番大きい値(しきい値)は以下の様になります。
1回目:26 2回目:27 3回目:28 4回目:29 5回目:30
上記の通り、1回目の乱数が26を超えた場合には残り4個の乱数を出力できないので
打ち切りとなります。
何回目の乱数を発生するのかをNにして一般化すると、N回目の乱数は30-(5-N)以下である必要があります。
(打ち切りの場合の出力例では1回目は25で1回目のしきい値以下なので継続、
2回目は28で2回目のしきい値を超えているので値の出力後打ち切るという流れと思います)
打ち切り判定をいつやるかとその判定内容がネックかと思います。
そのプログラムの場合、打ち切り出力例のように1回目が25、2回目が28だったとしても3回目の乱数が出力されてしまうと思います。boo123 さんが書きました:出来るだけわかりやすく書いてみました。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。
Advanced Supporting Developer
無理やりこじつけ(ぉ
無理やりこじつけ(ぉ
Re: 助けてください
なるほど仰るとおり打ち切り条件違ってますね。asd さんが書きました:他の方と被りますが手順としては、
打ち切り判定をいつやるかとその判定内容がネックかと思います。
そのプログラムの場合、打ち切り出力例のように1回目が25、2回目が28だったとしても3回目の乱数が出力されてしまうと思います。boo123 さんが書きました:出来るだけわかりやすく書いてみました。
発生させる乱数値の下限をそれまで発生した乱数値+1としているのが特徴です。
御指摘いただき有り難うございます。
正しい打ち切り条件の場合、
if ( Min > 30 )
を
if ( Min > (26+i) )
に修正すると実現できます。
修正したソース下記です。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char **argv)
{
int Min; /* 乱数発生値の下限 */
int Val; /* 発生させた乱数値 */
int i;
/* 下限値初期化 */
Min = 1;
/* 乱数初期化 */
srand(time(0));
/* 処理本体 */
for (i = 0; i < 5; i++)
{
/* 最後の乱数発生で下限値が30を超えると予想される場合「最後まで表示出来なかった」*/
if (Min > (26+i))
{
printf("Sorry! Impossible to print all.");
break;
}
/* 乱数発生 */
Val = rand() % (30 - Min + 1) + Min;
/* 下限値更新 */
Min = Val + 1;
/* 発生値表示 */
printf("%d ", Val);
}
printf("\n");
getchar();
}