BINGOゲーム作成にあたって重複しない乱数の生成の仕方

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

BINGOゲーム作成にあたって重複しない乱数の生成の仕方

#1

投稿記事 by underthesea » 2年前

現在、ビンゴゲームを作成しているのですが、重複しない乱数を生成するにはどうすればいいのか教えていただきたいです。
このソースに、どのようなコードを加えれば重複しないようになるのかを具体的に示していただけたら幸いです。

コード:

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

int a, i, j;
int state[100];
int card[5][5];

int GetNumber()
{服
	while (1)
	{
		a = rand() % 100 + 1;

		if (state[a] == 0)
		{
			state[a] = 1;
			break;
		}
	}
	return a;
}

void Dis()
{
	printf("                          ******BINGOゲーム******\n");


	for (i = 0; i<5; i++)
	{
		printf("\n");

		for (j = 0; j<5; j++)
		{
			printf("    %2d ", card[i][j]);



		}
		printf("\n");

	}
}


int NumberCheck(int m)
{
	for (i = 0; i<5; i++)
	{
		for (j = 0; j<5; j++)
		{
			if (card[i][j] == m)
			{
				printf("                         やったね!%.2dはあるよ!\n", m);
				card[i][j] = 0;
				return 1;
			}
		}
	}
	printf("                ざんねーん。%.2dはないよ\n", m);
	return 0;
}

// カードの縦、横、斜めいずれか1列が全て空いたらBINGO

int BingoCheck()
{
	for (i = 0; i<5; i++)
	{
		a = 0;

		for (j = 0; j<5; j++)
		{
			a += card[i][j];
		}
		if (a == 0)
		{
			return 1;
		}
	}

	for (i = 0; i<5; i++)

	{
		a = 0;
		for (j = 0; j<5; j++)
		{
			a += card[j][i];
		}
		if (a == 0)
		{
			return 1;
		}
	}

	a = 0;

	for (i = 0; i<5; i++)
	{
		a += card[i][i];
	}
	if (a == 0)
	{
		return 1;
	}

	a = 0;

	for (i = 0; i<5; i++)
	{
		a += card[i][4 - i];
	}
	if (a == 0)
	{
		return 1;
	}
	return 0;
}



int main()
{
	srand((unsigned)time(NULL));

	for (i = 0; i<100; i++)
	{
		state[i] = 0;
	}

	// 1~100 の番号をランダムに配置
	for (i = 0; i<5; i++)
	{
		for (j = 0; j<5; j++)
		{
			card[i][j] = GetNumber();
		}
	}
	// カード中央のマスにfreeすマスとして「0」 をあらかじめ配置しておく。
	card[2][2] = 0;

	for (i = 0; i<100; i++)
	{
		state[i] = 0;
	}

	// カード初期状態を表示
	Dis();


	while (1)
	{
		// ENTERキーの入力
		printf("\n");
		printf("                             ENTERを押してね!\n");

		getchar();

		// 乱数を取得し番号に適用する。乱数を用いた番号の抽選を開始する
		if (NumberCheck(GetNumber()))
		{

			// 最新のカードの状態を表示する。
			Dis();
			// ビンゴしたかどうかをチェックする。
			if (BingoCheck())
			{
				printf("ビンゴ~!!\n");
				break;
			}
		}
	}

	printf("終了します。\n");

	return 0;
}
 

maru
記事: 150
登録日時: 8年前

Re: BINGOゲーム作成にあたって重複しない乱数の生成の仕方

#2

投稿記事 by maru » 1年前

数値を重複しないようにするには、候補の数値を順番に並べて置き、それをシャッフルしてから順番に取り出すのが定石だと思います。

コード:

#include <iostream>
#include <random>
#include <assert.h>

const size_t MaxNumber = 100;

typedef struct tagBingoNumber
{
	int numbers[MaxNumber];
	size_t	seq;
}	BingoNumber;


void shuffle(BingoNumber* p, size_t maxNum)
{
	for (size_t i = 0; i < maxNum; ++i)
	{
		int j = rand() % maxNum;
		// スワップ
		int	dum = p->numbers[i];
		p->numbers[i] = p->numbers[j];
		p->numbers[j] = dum;
	}
}

void init(BingoNumber* p, size_t maxNum)
{
	for (size_t i = 0; i < maxNum; ++i)	p->numbers[i] = i;
	shuffle(p, maxNum);
	p->seq = 0;
}

int getNUmber(BingoNumber* p)
{
	assert(p->seq < MaxNumber);	// 要素番号チェック!
	return p->numbers[p->seq++] + 1;
}

int main(void)
{
	BingoNumber	numbers;
	init(&numbers, MaxNumber);
	for (int i = 0; i < 25; ++i)
		cout << i << ":" << getNUmber(&numbers) << endl;
	return 0;
}
確認はしていませんが、重複はしていないはずです。
最後に編集したユーザー maru on 2017年10月30日(月) 18:07 [ 編集 1 回目 ]

maru
記事: 150
登録日時: 8年前

Re: BINGOゲーム作成にあたって重複しない乱数の生成の仕方

#3

投稿記事 by maru » 1年前

質問主さんのプログラムをよく見てみたら、カードの作成と抽選の両方に GetNumer() を使用していますね。
これで重複を許さないと、絶対にビンゴにならないと思いますが...
カード用と抽選用に二つの配列を用意するか、カードの作成後に再シャッフル(+シーケンス番号リセット)すれば解消すると思います。

かずま

Re: BINGOゲーム作成にあたって重複しない乱数の生成の仕方

#4

投稿記事 by かずま » 1年前

Random r(a, b) で、r は a から bまでの乱数を保持するオブジェクトとなります。
r.get() で乱数が取得できます。全部取得し終わったあとは a-1 が返ります。
r.reset() で再取得できるようになります。

コード:

#include <iostream> // cout, endl
#include <cstdlib>  // srand, rand
#include <ctime>    // time
using namespace std;
 
class Random {
    int a, n, size, *data;
public:
    Random(int a, int b) : a(a), n(b-a+1), size(n), data(new int[n]) {
        for (int i = 0; i < n; i++) data[i] = i;
    }
    ~Random() { delete[] data; }
    int get() {
        if (n <= 0) return a - 1;
        int k = rand() % n, t = data[k];
        data[k] = data[--n];
        return (data[n] = t) + a;
    }
    void reset() { n = size; }
};
 
int main()
{
    srand(time(0));
    Random r(1, 100);
    for (int i = 0; i < 25; ++i) cout << ' ' << r.get();
    cout << endl;
    r.reset();
    for (int i = 0; i < 25; ++i) cout << ' ' << r.get();
    cout << endl;
}
実行結果

コード:

 42 25 55 52 86 13 92 6 68 31 40 12 35 53 74 32 63 48 43 33 9 22 16 96 76
 54 33 17 19 23 40 71 79 93 26 72 15 69 27 89 5 65 62 41 61 100 10 36 21 66

かずま

Re: BINGOゲーム作成にあたって重複しない乱数の生成の仕方

#5

投稿記事 by かずま » 1年前

簡略化して C で書いてみました。

コード:

#include <stdio.h>   // printf
#include <stdlib.h>  // srand, rand
#include <time.h>    // time

#define MAX_VALUE  100
 
int n = MAX_VALUE, data[MAX_VALUE];

int get(void)
{
    if (n <= 0) return 0;
    int k = rand() % n, t = data[k];
    data[k] = data[--n];
    return (data[n] = t) + 1;
}

int main(void)
{
    srand(time(0));  // 乱数の初期設定
    for (int i = 0; i < n; i++) data[i] = i;  // 初期化
    for (int i = 0; i < 25; ++i) printf(" %d", get());
    putchar('\n');
    n = MAX_VALUE;  // 再設定
    for (int i = 0; i < 25; ++i) printf(" %d", get());
    putchar('\n');
    return 0;
}

返信

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