電子書籍の厳選無料作品が豊富!

C#で複重しない乱数

とにかく自分の書いたプログラムの一部分を見てください

Bitmap my1 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my2 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my3 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my4 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my5 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my6 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my7 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my8 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my9 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my10 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my11 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my12 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my13 = new Bitmap(GetType(), rand.Next(1,52) + ".png");
Bitmap my14 = new Bitmap(GetType(), rand.Next(1,52) + ".png");

こんなかんじで、なんかプログラムが回りくどかったり下手くそだったりするのは触れないでくださいww
1~52の乱数を発生させてるのですが、コレが同じ数字が出て欲しくないんですけど
やり方が分かりません^^;
どなたか教えてくれませんか

A 回答 (6件)

動かしてみて動作確認をとってみました。


これで動くと思います。

class UniqueRandom
{
private int rand_max;
private int rand_min;
private int rand_range;
bool[] check;
System.Random rand;
private int last_num;

public UniqueRandom(int imin, int imax)
{
rand_max = imax;
rand_min = imin;
rand_range = imax - imin + 1;
check = new bool[rand_range];
for (int i = 0; i < rand_range; i++) {
check[i] = false;
}
rand = new System.Random();
last_num = 0;
}

#if false
public int urand()
{
int num;
do {
num = rand.Next(rand_min, rand_max);
} while (check[num - rand_min]);
check[num - rand_min] = true;
return(num);
}
#else
public int urand()
{
int i, j;
int num = rand.Next(rand_min, rand_max);
for (i = last_num + 1, j = rand_min; j <= rand_max; i++)
{
if (i >= rand_range) {
i = 0;
}
if (!check[i]) {
if (j == num) break;
j++;
}
}
check[i] = true;
last_num = i;
return(i + rand_min);
}
#endif
}

乱数の取り方は
// 乱数生成用のオブジェクト
UniqueRandom u_rand = new UniqueRandom(1, 52);
// num に 1~52のどれかをユニークに取り込み
int num = u_rand.urand();

当然ながら、52回を超えると空きの数値が無いので帰ってこなくなります。
    • good
    • 0
この回答へのお礼

つまり、それ以上はランダムは出来ないってことですか?
プログラム試しました
すごいです。重複しませんでした

難しいですね
とりあえずこれを使ってプログラムを作っていきたいと思います
ありがとうございました

お礼日時:2010/06/09 11:16

52という数字で重複禁止というところからするとトランプの山でも作りたいのでしょうか。


発想の方向を変えて、「1~52の数値を持つ配列をシャッフルし、頭から順次抜き出す」という手法を紹介しておきます。
#たぶんこのままクラスに突っ込んでも動作するんじゃないかな?
#シャッフル部分は実装してませんので注意

配列と現在位置:
int numbers[52];
int current;

シャッフルするルーチン:
// num = シャッフル回数
void shuffle(int num)
{
int i;
for(i = 0; i < 52; i ++)
{
// 配列の初期化
numbers[i] = i + 1;
}
// 配列をシャッフル
for(i = 0; i < num; i ++)
{
// 適当なシャッフルルーチン
// rand二回の実施結果で一枚ずつ入れ替える、というのがとりあえずは楽か
}
// 参照位置を頭にする
current = 0;
}

// 配列を先頭から順次取っていく
// 取れなくなった(=モノがなくなった)ら0を返す
int get()
{
if(current < 52) return numbers[current++];
return 0;
}

この回答への補足

そうですねトランプです
大富豪を作ろうと思っているのですが全然進まないので
基本的なことから作っていこうと思いまして
手札にとりあえず14枚カードが配られるようなプログラムを作っています

考え方はわかるのですが・・・
なるほど・・・少しづつ解読していきます

補足日時:2010/06/06 22:09
    • good
    • 0

> public int rand()


> の部分でrandにエラーが出てきてしまいます
> randの定義をすでに含んでいますって感じです

 System.Randomのオブジェクトとクラスの関数(メソッド)名がダブってましたね。
 どちらを変えても同じですけど、関数名の方を適当に変えてください。

 public int urand()

 とか……(関数を呼び出してるところも)
    • good
    • 0
この回答へのお礼

だいぶ理解してきました

でも結局うまくいきませんでした・・・
すいませんこんなに詳しく描いてもらったのに
今後この技術も活用させてもらいたいと思います

ありがとうございました

お礼日時:2010/06/06 21:54

> voidがダメみたいです無効なパラメーター型です。

っていわれます

 C#だと引数のない場合は何も書かないみたいですね。
(CとかC++の方が慣れてるから、ついvoidを書いてしまいましたが)

public int rand()

 で良いと思います。
    • good
    • 0

#1 の補足です。


 check[num]とあるのはcheck[num - rand_min]に置き換えてください。


 下記の例ではテーブルに出た乱数毎にフラグを立てて、その値にフラグが立ってるかどうかの判断を行っていますが、この場合、値の範囲に対して乱を使う回数が少ない場合は良いのですが、テーブルがフラグで埋まってくると新しい値を取り出すのに時間がかかってきます。
 したがって、範囲内の値をある程度多く使う場合は、乱数を取り出した値を直接テーブルのインデックスにして判断するのではなく、取り出した乱数でテーブルのフラグの立ってない部分を順次探していくような形にした方が効率的になります。
 例えば、下記のUniqueRandomクラスを変更するなら

// クラス変数の追加
private int last_num;

// コンストラクタの追加
last_num = 0;

// 関数本体(置き換え)
public int rand()
{
int i, j;
int num = rand.Next(rand_min, rand_max);
for (i = last_num + 1, j = rand_min; j <= rand_max; i++)
{
if (i >= rand_range) {
i = 0;
}
if (!check[i]) {
if (j == num) break;
j++;
}
}
check[i] = true;
last_num = i;
return(j);
}

この回答への補足

こんなに早く、詳しく返答ありがとうございます

少しづつですが部分的に理解ができてきました

public int rand()
の部分でrandにエラーが出てきてしまいます
randの定義をすでに含んでいますって感じです

お手数かけてすいません

補足日時:2010/06/06 20:19
    • good
    • 0

 乱数はランダムに値を生成しますが、同じ値を生成しないという機能はありません。

特に上下限値を指定した場合は値の取りうる範囲が狭いので、重複した値が出る確率は高くなります。

 重複した値を排除したいのであれば、自分で管理するしないでしょう。

例えば
class UniqueRandom
{
private int rand_max;
private int rand_min;
private int rand_range;
bool[] check;
System.Random rand;

UniqueRandom(int min, int max)
{
rand_max = max;
rand_min = min;
rand_range = max - min + 1;
check = new bool[rand_range];
for (i = 0; i < rand_range; i++) check[i] = false;
rand = new System.Random();
}

public int rand(void)
{
int num;
do {
num = rand.Next(rand_min, rand_max);
} while (check[num]);
check[num] = true;
return(num);
}
}
というようなユニーク値を返す乱数クラスを作って

UniqueRandom u_rand = new UniqueRandom(1,52);
Bitmap my1 = new Bitmap(GetType(), u_rand.rand() + ".png");

というのもひとつの方法です。

この回答への補足

public int rand(void)

すいません、この部分でエラーが出てしまいます
いろいろ試してみたのですが、分からないです・・・^^;
voidがダメみたいです無効なパラメーター型です。っていわれます

教えてもらってるのにすいません・・・

補足日時:2010/06/06 19:52
    • good
    • 1
この回答へのお礼

すごいです・・・
えーっとクラスを作ってこのプログラムを入力すればいいのでしょうか・・・

ごめんなさい、C#はまだ勉強中でいまいち理解できてなくて

お礼日時:2010/06/06 19:41

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!