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

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

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

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

Q&A

解決済

5回答

7509閲覧

C言語のBINGOの作成でわからないことがあります。

n6n9Qsmt8gLjwKw

総合スコア29

C

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

0グッド

0クリップ

投稿2016/01/06 17:44

編集2016/01/07 15:23

以前、ビンゴの作成に関する質問をして、コードの改良を行ったのですが、どうしてもわからないことがあるので知恵をお借りしたいです。

作成条件は
・5X5のカード
・数値が重複しないようにする。
・数値の範囲は075
・縦一列目は1
15,縦二列目は1630,縦三列目は3145,縦四列目は4660,縦五列目は6175の範囲で作成

下記のコードでビンゴ変数代入時に15ずつ動くように設定しようとしたのですが、出力時に数値が重複してしまい、値が15ずつずれないです。
どの箇所が問題なのかご指摘をいただきたいです。できればコードも載せていただけると非常にありがたいです。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <time.h> 4 5#define BINGO_HEIGHT (5)//縦5 6#define BINGO_WIDTH (5)//横5 7#define MAX_NUM (15)//数値範囲(最大値15*5=75) 8 9int main(void) 10{ 11 int bingo[BINGO_HEIGHT][BINGO_WIDTH];//ビンゴカード 12 int number[MAX_NUM];//ビンゴナンバー 13 int i; 14 int j; 15 int k; 16 int s; 17 18 srand((unsigned)time(NULL));/* 乱数系列の変更 */ 19 20 21 for (s = 0; s < MAX_NUM; s++) {//配列初期化 22 number[s] = s; 23 } 24 25 26 27 //bingo変数への代入 28 for (i = 0; i < BINGO_HEIGHT; i++) { 29 k = rand() % (MAX_NUM);//乱数生成 30 31 for (j = 0; j <BINGO_WIDTH; j++) { 32 if (j==0) { 33 bingo[i][0] = number[k]+(k*0); 34 } 35 else if (j == 1) { 36 bingo[i][1] = number[k] + (k*1); 37 } 38 else if (j == 2) { 39 bingo[i][2] = number[k] + (k*2); 40 } 41 else if (j == 3) { 42 bingo[i][3] = number[k] + (k*3); 43 } 44 else if (j == 4) { 45 bingo[i][4] = number[k] + (k*4); 46 } 47 } 48 } 49 50 51 //bingo変数の表示 52 for (i = 0; i <BINGO_HEIGHT; i++) { 53 for (j = 0; j <BINGO_WIDTH; j++) { 54 printf("%2d ", bingo[i][j] );//出力 55 } 56 putchar('\n');//改行 57 } 58 return 0; 59}

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

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

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

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

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

guest

回答5

0

ベストアンサー

番号生成部分をざっくり解析すると、

・縦ループ(i:0~4) ・ランダム値作成(k:0~14) ・横ループ(j:0~4) ・各マスの値作成 :配列(i,j) = k + (k * j) ・横ループEnd ・縦ループEnd

となっているようです。
(机上で解析しただけなので、はずしていたらすみません。)

縦ループ⇒横ループとしているため、各マスの値は
①②③④⑤
⑥⑦⑧・・
・・・・・
・・・・・
・・・・25
の順で作成されていくとおもいますが、乱数の生成を縦ループ内でしか行っていないため、横方向のランダム性がありません。
例えば①~⑤を作成する際にk=3の乱数となった場合、①は3、②は6、③は9となってしまうように思います。
さらに縦方向についての重複チェックが行われていません。

というわけで、不足しているのは
・縦方向の重複チェック
・横方向へのランダム性
だと思います。

これを改善するとすれば、

・横ループ(j:0~4) ・縦ループ(i:0~4) ・ランダム値作成(k:0~14) ・ランダム値の重複チェック ⇒配列(0~i,j)で同じ値が使用されていないかチェック ⇒重複した場合、重複しない値となるまでランダム値を再生成、再チェックを繰り返す ・各マスの値作成 :配列(i,j) = k + (j * 15) ・縦ループEnd ・横ループEnd

のような処理にすればよいと思います。

具体的なコード提示ではありませんが、頑張ってみてください。

投稿2016/01/07 01:38

jawa

総合スコア3013

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

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

0

こんにちは。

・縦一列目は015,縦二列目は1630,縦三列目は3145,縦四列目は4660,縦五列目は61~75の範囲で作成

いきなり仕様がよろしくない印象です。第一列目のみ16個の数字で他は15個の数字ですね。恐らく、下記間違いではないでしょうか?

・縦一列目は115,縦二列目は1630,縦三列目は3145,縦四列目は4660,縦五列目は61~75の範囲で作成

前回はnumber[]に昇順で値を設定した後、シャッフルしてました。シャッフルですので値が重複することはありません。
今回はシャッフルせず、発生した乱数を少し加工して「bingo変数」へ設定しているだけです。(number[k]はkと等しいままですね。)つまり、同じ乱数値が複数回生成されると値が重複します。
前回のようにシャッフルした方がよいと思います。

次にj=0~BINGO_WIDTH-1の値を設定する際にオフセットを加えて重複を避けようとしていると思いますが、乱数k*jでは重複してしまいます。
例えば、k=0の時はjの値に無関係に0ですね。また、k=1の場合j=4のオフセットは4ですね。この時、付けたいオフセットは61ではないでしょうか?

全体的に見直すのであれば、前回のozwkさんの回答ベースで下記イメージが好ましいと思います。

C

1int number[BINGO_HEIGHT]; 2(中略) 3for (j = 0; j <BINGO_WIDTH; j++) { 4 for (s = 0; s < BINGO_HEIGHT; s++) {//配列初期化 5 number[s] = s+オフセット; // オフセットは第j列目に設定したい最小値 6 } 7 ここでnumber[]をシャッフルする。 8 9 for (i = 0; i < BINGO_HEIGHT; i++) { 10 bingo[i][j]=number[j]; 11 } 12}

後、質問とは無関係ですが、

C

1for (j = 0; j <BINGO_WIDTH; j++) { 2 if (j==0) { 3 bingo[i][0] = number[k]+(k*0); 4 } 5 (中略) 6}

は、下記でも同じ結果になると思います。

C

1for (j = 0; j <BINGO_WIDTH; j++) { 2 bingo[i][j] = number[k]+(k*j); 3}

投稿2016/01/07 01:19

編集2016/01/07 01:25
Chironian

総合スコア23272

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

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

0

何がおかしいか

for (i = 0; i < BINGO_HEIGHT; i++) { k = rand() % (MAX_NUM);//乱数生成 for (j = 0; j <BINGO_WIDTH; j++) { if (j==0) { bingo[i][0] = number[k]+(k*0); ...

kに適当な値を入れてどういう値になるか計算してみてください。
例えば奇跡的にkが毎回0だったとしましょう。
どうなりますか?
15ずつズレますか?ズレませんね。

プログラムはあくまで作業手順をコンピュータに代替させる手段なので、
根本の作業手順がしっかりできてないといけません。
慣れないうちは手順を他人に指示するつもりで、詳細まで作りこんでから
プログラムを組んでください。

今回の場合は、例えば、
「ビンゴの縦n列は、1~15の数字をランダムに並び替えた数列の、
先頭5つにそれぞれ15*(n-1)足したもの」とすれば条件をみたすので、
これをコードにすれば実現できます。

投稿2016/01/07 01:16

ozwk

総合スコア13512

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

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

0

皆様回答ありがとうございます。
コードを見直したところ、下記のコードで解決できました。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <time.h> 4 5#define BINGO_HEIGHT (5)//縦5マス 6#define BINGO_WIDTH (5)//横5マス 7#define MAX_NUM (15)//ビンゴの数値幅 8 9int main(void) 10{ 11 int bingo[BINGO_HEIGHT][BINGO_WIDTH ];//ビンゴカード 12 int number[MAX_NUM];//ビンゴナンバー 13 int rnd;//乱数 14 int i; 15 int j; 16 int k; 17 18 19 srand((unsigned)time(NULL));/* 乱数系列の変更 */ 20 21 22 for (k = 0; k< MAX_NUM; k++) {//配列初期化 23 number[k] = k+1; 24 } 25 26 27 28 //bingo変数への代入 29 for (i = 0; i < BINGO_HEIGHT; i++) { 30 for (k = 0; k < MAX_NUM; k++) { 31 rnd = rand() % (k + 1);//乱数生成 32 j = number[k]; 33 number[k] = number[rnd]; 34 number[rnd] = j; 35 } 36 37 for (j = 0; j < BINGO_WIDTH ; j++) { 38 if (j == 0) { 39 bingo[i][0] = number[rnd] + (MAX_NUM * 0); 40 } 41 else if (j == 1) { 42 bingo[i][1] = number[rnd] + (MAX_NUM * 1); 43 } 44 else if (j == 2) { 45 bingo[i][2] = number[rnd] + (MAX_NUM * 2); 46 } 47 else if (j == 3) { 48 bingo[i][3] = number[rnd] + (MAX_NUM * 3); 49 } 50 else if (j == 4) { 51 bingo[i][4] = number[rnd] + (MAX_NUM * 4); 52 } 53 } 54 } 55 56 57 //bingo変数の表示 58 for (i = 0; i <BINGO_HEIGHT; i++) {//ビンゴカードのマスを生成した数値で埋める 59 for (j = 0; j <BINGO_WIDTH ; j++) { 60 printf("%2d ", bingo[i][j] );//出力 61 } 62 putchar('\n');//改行 63 } 64 return 0; 65}

投稿2016/01/07 01:03

n6n9Qsmt8gLjwKw

総合スコア29

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

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

Chironian

2016/01/07 01:23

回答している間に自己解決されたようですね。 でも、よく見てみて下さい。第j列の値は第j-1列の値に+15したものになっていないでしょうか?
ozwk

2016/01/07 01:43 編集

何度か実行してみたところ普通に値が重複します。 srand(0)で 15 30 45 60 75 11 26 41 56 71 15 30 45 60 75 15 30 45 60 75 12 27 42 57 72
n6n9Qsmt8gLjwKw

2016/01/07 15:12

申し訳ありません。 Chironianさんとozwkさんの指摘通り、何度か実行すると数値が重複してしまいました。 回答を参考に見直します。
guest

0

C

1#include <stdio.h> 2#include <stdlib.h> 3 4void set_bingo_numbers(int* bingoLine, int start, int end); 5void show_bingo(int bingo[][]); 6#define ROW 5 7#define COL 5 8int main() { 9 int bingo[ROW][COL]; 10 //line1: 1-15, 11 //line2: 16-30, 12 //line3: 31-45, 13 //line4: 46-60, 14 //line5: 61-75 15 set_bingo_number(bingo[0], 1, 15); 16 set_bingo_number(bingo[1], 16, 30); 17 set_bingo_number(bingo[2], 31, 45); 18 set_bingo_number(bingo[3], 46, 60); 19 set_bingo_number(bingo[4], 61, 75); 20 21 show_bingo(bingo); 22 23 return 0; 24} 25/// start - end 範囲のランダム値を取得する 26/// 取得した場所は取得済みの印として 0 を設定する 27/// buffer の走査は、bufferSize で割ったあまりの乱数値の数分走査するが、 28/// 取得済みの 0 が入っている場所は読み飛ばす。 29/// 30int seed(int *buffer, int bufferSize) { 31 int n = rand() % bufferSize + 1; 32 33 int retVal = 0, pos = 0; 34 while (n > 0) { 35 if (buffer[pos] == 0) { 36 pos++; 37 continue; 38 } 39 n--; 40 } 41 retVal = buffer[pos]; 42 buffer[pos] = 0; 43 return retVal; 44} 45void set_bingo_numbers(int* bingoLine, int start, int end) { 46 int buffer[end - start]; 47 48 for (int i=start;i <= end;i++) { 49 buffer[i-start] = i; 50 } 51 int size = end - start; 52 for (int i=0;i < COL;i++) { 53 54 bingoLine[i] = seed(buffer, size--); 55 56 } 57} 58void show_bingo(int bingo[][]) { 59 for (int i=0;i < ROW;i++) { 60 61 for (int x=0;x < COL;x++) { 62 printf("%3d",bingo[i][x]); 63 } 64 printf("\n"); 65 } 66}

動作確認していません。コンパイルさえしていませんが、こんな感じですか。

投稿2016/01/06 18:50

ipadcaron

総合スコア1693

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

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

ozwk

2016/01/07 00:28

エラー直してコンパイル通したところ 1 2 3 4 5 16 17 18 19 20 31 32 33 34 35 46 47 48 49 50 61 62 63 64 65 となりました
ipadcaron

2016/01/07 00:33

ありゃ、駄目だった。もう一回チャレンジします
n6n9Qsmt8gLjwKw

2016/01/07 01:09

ご回答ありがとうございます。 私のコードよりもipadcaronさんの引数に範囲指定するやり方のほうがわかりやすいように思いました。 一応自己解決できたのですが参考になりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問