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

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

ただいまの
回答率

90.35%

  • C

    3956questions

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

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

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 494

Alyn

score 15

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

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

 該当のソースコード

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

int hantei(char y, char u)
{
    if(y==u)
    {
        return 1;
    }
    else
    {
        return -1;
    }
}

int main(void)
{
    char moji4[15][5]={"getc","putc","feof","gets","puts","case","else","goto","char","long","main","null","void","math","enum"};

    char input, retry;
    int ha, rns, miss, j, i;
    double req_time ;
    clock_t start, end;

    do{
            printf("\n【タイピング練習プログラム】スペースキーを押してスタートです");
            while(1)
            {
                input=_getch();
                if(0x20==input)
                {
                    putchar('\n');
                    miss=0;
                    break;
                }
            }
            srand((unsigned int)(time(NULL)));
            start=clock();

            for(j=0; j<10; j++)
            {
                printf("\n第%d問\n",j+1);
                rns=rand() % 15;

                printf("【 %s 】を入力してください:",&moji4[rns][0]);
                for(i=0; i<4; i++)
                {
                    while(1)
                    {
                        input=_getch();
                        if(ha=hantei(moji4[rns][i],input)==1)
                        {
                            printf("%c",input);
                            break;
                        }
                        else
                        {
                            putchar('\a');
                            miss++;
                        }
                    }
                }
                putchar('\n');
            }

        end=clock();
        req_time = (end-start)/1000;
        printf("\n≪タイピング練習プログラム終了≫\n   Time:%.1f秒 / Miss:%d回\n\n",req_time,miss);

        printf("もう一度挑戦しますか?(YESはスペースキーを入力/NOはスペースキー以外を入力)");
        retry=_getch();
        puts("\n");

    }while(0x20==retry);

    return 0;
}

 試したこと

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Alyn

    2018/06/16 15:02

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

    キャンセル

回答 4

checkベストアンサー

+2

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

[追記]

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

// data[0]~data[size-1]のナカミを(乱数使って)デタラメに入れ換える
void shuffle(int data[], int size) {
  int i;
  for ( int i = 0; i < size; ++i ) {
    int pos = rand() % (size-i);
    // data[pos] と data[size-i-1] を入れ換える
    int tmp = data[size-i-1];
    data[size-i-1] = data[pos];
    data[pos] = tmp;
  }
}

// おためし
int main() {
  int index[15];
  int i;    
  // index[] を 0,1,2... で埋める
  for ( i = 0; i < 15; ++i ) { 
    index[i] = i; 
  }
  // indexをかきまぜる
  srand((unsigned int)(time(NULL)));
  shuffle(index, 15);
  // 結果確認
  for ( i = 0; i < 15; ++i ) { 
    printf("%2d ", index[i]);
  }
  printf("\n");
  return 0;
}

/* 実行結果
14  2 12  9  1  5  8  0  3  6  7 11 13 10  4
*/


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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/16 14:53

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

    キャンセル

  • 2018/06/16 16:35

    追記しといた

    キャンセル

  • 2018/06/16 17:54

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

    キャンセル

+2

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

しかし、私だったら単語数がこんな程度では満足できず、数千ぐらいの語彙をもたせたいと思いますね。そんな場合はシャッフル法は明らかに非効率的であり、次のような方法がよさそうに思えます。

  1. 乱数で適当に単語を選ぶ。
  2. 「すでに選んだ単語のリスト」にその単語が入っていないかチェック。入っていたら、前段をやり直す。
  3. 選んだ単語を「すでに選んだ単語のリスト」に追加
  4. ゲーム本体の処理

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/16 13:41

    これが効率的かしら?

    数千の語彙で問題数も同程度のとき、上記[2]のステップで今まで選ばれていない問題を引き当てる確率が落ちていき何度もやり直しになります。

    「まだ選んでいない単語のリスト」から選ぶんならわかるけど、それにしたってシャッフルと同程度と思いますが。

    キャンセル

  • 2018/06/16 14:18

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

    キャンセル

  • 2018/06/16 14:59

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

    キャンセル

  • 2018/06/16 16:38

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

    キャンセル

  • 2018/06/16 16:54

    私もシャッフルのほうが無難であると思います。まあ、母数に対して選ぶ数が少ないならばこの方法も有用ではあると思いますが、どう使うかは回答者次第なので無難な方が適切だと思いますよ。


    まとめると、シャッフルの場合は「乱配列の準備が手間、準備後の乱数の取得は容易」、こちらの方法の場合は「乱配列の準備は不要、乱数取得の際に逐次処理が必要」。

    キャンセル

  • 2018/06/16 17:57

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

    キャンセル

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/16 14:52

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

    キャンセル

0

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/16 14:54

    MTとは何でしょうか?

    キャンセル

  • 2018/06/16 15:56

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

    キャンセル

  • 2018/06/16 17:56

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

    キャンセル

同じタグがついた質問を見る

  • C

    3956questions

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