質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

4681閲覧

C言語で乱数を毎回異なるものにしたい

Alyn

総合スコア50

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2018/06/15 14:26

同じ文字列が複数回出力されないように乱数を異なるものにしたい

C言語でタイピングを練習するプログラムを作っています。
配列の中の文字列をランダムに出力して、その通り文字を入力させるものです。
正誤判定は1文字ずつhantei関数で行い、間違えると警告音が鳴りMissがカウントされます。
しかしこのままでは同じ文字列が複数回出力されることがあります。
また今後配列の中の文字列は25~30くらいに増える予定です。
このことを考慮して同じ文字列が複数回出力されないようにするにはどうしたらいいですか?

該当のソースコード

C言語

1#include<stdio.h> 2#include<stdlib.h> 3#include<time.h> 4#include<conio.h> 5 6int hantei(char y, char u) 7{ 8 if(y==u) 9 { 10 return 1; 11 } 12 else 13 { 14 return -1; 15 } 16} 17 18int main(void) 19{ 20 char moji4[15][5]={"getc","putc","feof","gets","puts","case","else","goto","char","long","main","null","void","math","enum"}; 21 22 char input, retry; 23 int ha, rns, miss, j, i; 24 double req_time ; 25 clock_t start, end; 26 27 do{ 28 printf("\n【タイピング練習プログラム】スペースキーを押してスタートです"); 29 while(1) 30 { 31 input=_getch(); 32 if(0x20==input) 33 { 34 putchar('\n'); 35 miss=0; 36 break; 37 } 38 } 39 srand((unsigned int)(time(NULL))); 40 start=clock(); 41 42 for(j=0; j<10; j++) 43 { 44 printf("\n第%d問\n",j+1); 45 rns=rand() % 15; 46 47 printf("【 %s 】を入力してください:",&moji4[rns][0]); 48 for(i=0; i<4; i++) 49 { 50 while(1) 51 { 52 input=_getch(); 53 if(ha=hantei(moji4[rns][i],input)==1) 54 { 55 printf("%c",input); 56 break; 57 } 58 else 59 { 60 putchar('\a'); 61 miss++; 62 } 63 } 64 } 65 putchar('\n'); 66 } 67 68 end=clock(); 69 req_time = (end-start)/1000; 70 printf("\n≪タイピング練習プログラム終了≫\n Time:%.1f秒 / Miss:%d回\n\n",req_time,miss); 71 72 printf("もう一度挑戦しますか?(YESはスペースキーを入力/NOはスペースキー以外を入力)"); 73 retry=_getch(); 74 puts("\n"); 75 76 }while(0x20==retry); 77 78 return 0; 79}

試したこと

ネットで探してみたのですが、様々なやり方があってわかなかったです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Alyn

2018/06/16 06:02

いただいた回答にあるシャッフルというのがよくわかりません。どのように組み込めばよいのでしょうか?
guest

回答4

0

要素数が20とか30とかなら、皆さんが言うようにシャッフルした配列をつくる手が考えられますね。

しかし、私だったら単語数がこんな程度では満足できず、数千ぐらいの語彙をもたせたいと思いますね。そんな場合はシャッフル法は明らかに非効率的であり、次のような方法がよさそうに思えます。
0. 乱数で適当に単語を選ぶ。
0. 「すでに選んだ単語のリスト」にその単語が入っていないかチェック。入っていたら、前段をやり直す。
0. 選んだ単語を「すでに選んだ単語のリスト」に追加
0. ゲーム本体の処理

投稿2018/06/16 03:54

KojiDoi

総合スコア13671

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2018/06/16 04:41

これが効率的かしら? 数千の語彙で問題数も同程度のとき、上記[2]のステップで今まで選ばれていない問題を引き当てる確率が落ちていき何度もやり直しになります。 「まだ選んでいない単語のリスト」から選ぶんならわかるけど、それにしたってシャッフルと同程度と思いますが。
KojiDoi

2018/06/16 05:18

数千の語彙でプレイも数千回繰り返すならおっしゃる通りでしょうね。
Alyn

2018/06/16 05:59

シャッフルとは違うやり方ですね。mainの外に関数を作って行うのでしょうか?
episteme

2018/06/16 07:38

高々数千個のシャッフルなら数ミリ秒もかからんでしょうから効率とか考慮することないんじゃないかしら。
HogeAnimalLover

2018/06/16 07:54

私もシャッフルのほうが無難であると思います。まあ、母数に対して選ぶ数が少ないならばこの方法も有用ではあると思いますが、どう使うかは回答者次第なので無難な方が適切だと思いますよ。 まとめると、シャッフルの場合は「乱配列の準備が手間、準備後の乱数の取得は容易」、こちらの方法の場合は「乱配列の準備は不要、乱数取得の際に逐次処理が必要」。
Alyn

2018/06/16 08:57

回答ありがとうございました。KojiDoiさんのやり方も試してみようと思います!
guest

0

ベストアンサー

  • int index[15]; を用意し、0~14 で埋める
  • 上記 index[0]~index[14]のナカミを(乱数使って)デタラメに入れ換える
  • i = 0,1,2... に対し moji4[index[i]] を使う

[追記]

C

1#include <stdlib.h> 2#include <stdio.h> 3#include <time.h> 4 5// data[0]~data[size-1]のナカミを(乱数使って)デタラメに入れ換える 6void shuffle(int data[], int size) { 7 int i; 8 for ( int i = 0; i < size; ++i ) { 9 int pos = rand() % (size-i); 10 // data[pos] と data[size-i-1] を入れ換える 11 int tmp = data[size-i-1]; 12 data[size-i-1] = data[pos]; 13 data[pos] = tmp; 14 } 15} 16 17// おためし 18int main() { 19 int index[15]; 20 int i; 21 // index[] を 0,1,2... で埋める 22 for ( i = 0; i < 15; ++i ) { 23 index[i] = i; 24 } 25 // indexをかきまぜる 26 srand((unsigned int)(time(NULL))); 27 shuffle(index, 15); 28 // 結果確認 29 for ( i = 0; i < 15; ++i ) { 30 printf("%2d ", index[i]); 31 } 32 printf("\n"); 33 return 0; 34} 35 36/* 実行結果 3714 2 12 9 1 5 8 0 3 6 7 11 13 10 4 38*/

※ C++なら std::shuffle(index, index+15, mt19937()); の一行で済むんだが...

投稿2018/06/15 22:46

編集2018/06/16 07:42
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Alyn

2018/06/16 05:53

入れ替えのやり方を教えていただけませんか?
episteme

2018/06/16 07:35

追記しといた
Alyn

2018/06/16 08:54

とても丁寧にありがとうございました!
guest

0

重複を許さいないならば、予め出力候補全リストを作ってシャッフルすることが挙げられます。

ついでにc標準の乱数関数は偏りが大きいことで有名です。実用するならばMTとかの検討が有効です。

投稿2018/06/16 02:42

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Alyn

2018/06/16 05:54

MTとは何でしょうか?
HogeAnimalLover

2018/06/16 06:56

MTとはメルセンヌツイスターと呼ばれる乱数生成法です。ついでにシャッフルとは乱数によるかき混ぜです。
Alyn

2018/06/16 08:56

回答ありがとうございました!
guest

0

文字列をシャッフルするやり方ですよね。
過去ログを参照すれば幸せになれますよ。
https://teratail.com/questions/11484

投稿2018/06/15 15:48

TaroToyotomi

総合スコア1430

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Alyn

2018/06/16 05:52

自分のプログラムにどのように組み込めばいいのかよくわかりません… シャッフルってヘッダーはどれですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問