C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: ArrayListをランダムにシャッフル


(過去ログ 13 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■3675 / inTopicNo.1)  ArrayListをランダムにシャッフル
  
□投稿者/ Back (1回)-(2007/05/18(Fri) 19:17:55)

分類:[C# (Windows)] 

こんばんわ。

今イントロクイズゲームを作成してるんですが、ランダムの部分で良い方法がなくて困っています。

ファイル選択やフォルダごとの選択で、再生するファイル(基本的に複数)を指定

その選択されたファイルのパスをArrayListに入れる

ArrayListをランダムにシャッフルする

上から順番に再生していく(ボタンで制御) 問題再生 と 次の曲へ ボタンが存在。

簡単に説明するとこういうような流れです。
ここで、ランダムにする方法が思いつきません。
ArrayListの配列数値をランダムだと、同じ数字が出る場合があるのでそれはできないですし。
ArrayList[配列のMAX数値以内のランダムな整数を返す関数]
だと、同じ曲が何度もでてしまうので。
一度出た数値は覚えておいて、毎回その数値が以前に出た事があるかチェックしながらというのも考えましたが
かなり無駄な感じですし。
ArrayListの中をランダムソートできれば後は上から順番に見ていくだけで順不同の曲を1回ずつ抽出できますから
そうしたいのですが、ArrayListの中身をランダムソートがどうすれば実現できるかが思いつきませんでした。

何か良い方法はない物でしょうか?
別にArrayListを使わなくても、選択したファイル一覧リストのパスを
ランダムで、重複しないように保持できればどんな方法でも構いません。

引用返信 編集キー/
■3676 / inTopicNo.2)  Re[1]: ArrayListをランダムにシャッフル
□投稿者/ επιστημη (517回)-(2007/05/18(Fri) 19:32:04)
επιστημη さんの Web サイト
> ここで、ランダムにする方法が思いつきません。

data[0..N-1] があったとして。

1. N未満の乱数iを生成
2. data[0]とdata[i]を交換
3. 1,2 を数回繰り返す

引用返信 編集キー/
■3677 / inTopicNo.3)  Re[2]: ArrayListをランダムにシャッフル
□投稿者/ ぽぴ王子 (203回)-(2007/05/18(Fri) 19:39:49)
ぽぴ王子 さんの Web サイト
無駄でもなんでも、考えて実装してみたらどうでしょうか。
そこから何か新しいアイデアが浮かぶかもしれません。

…と突き放したままにするつもりはないので。

ArrayList の中から再生するファイルパスを取得したら、そのリストから Delete して
いくとか。

あるいは。

応用で、ランダムでファイルパスを取得したら別のリストに次々に Add しておいて、
元のリストからは Delete していく。元のリストがなくなったら、別のリストの先頭から
再生…とか。

いろいろと考え方はあると思います。

ところで、イントロクイズゲームは趣味で作成されているものですか?
引用返信 編集キー/
■3678 / inTopicNo.4)  Re[3]: ArrayListをランダムにシャッフル
□投稿者/ Back (2回)-(2007/05/18(Fri) 21:52:25)
>επιστημηさん
最初、これだとあまり変わらないようなと思いましたが
よくよく考えてみるとn番目からとってきた0番目と入れ替えてるんで、結構ばらけさせられそうですね。
要素数の半分ぐらいループすれば良い感じにできそうです。
シンプルで効果的な方法、ありがとうございます。
アルゴリズムが苦手で、なんか高度な手法書かれたら多分理解できずに終わりそうだったので。

>ぽぴ王子さん
Deleteを忘れてました・・・
ただ重複はいけそうですが、ランダム再生はそれでできるんでしょうか?
ひょっとして私が最初に書いた要素数ランダムで選曲後、Deleteで消すって事ですかね?
毎回要素数を取得しなおせばそれで対応できそうだと思ったので。

>ところで、イントロクイズゲームは趣味で作成されているものですか?
はい、そうです。
機能的には、「選択中の曲を再生」と「次の曲へ」があり、曲名は表示されています。
ジョイスティックに対応していて、4コントローラで、それぞれボタンを押すとその瞬間に再生がストップするようにしています。
押されたら画面に一番早く押したコントローラーの番号が表示されます。
出題者が再生→コントローラで回答者決定→正解なら「次の曲へ」を押す。不正解ならもう一度「選択中の曲を再生」で続行
を繰り返します。
出題者がPCを操作して、回答者にはディスプレイが見えないようにして使う感じです。

テレビ番組のイントロゲームで、回答者がボタンを押しても暫く(1〜2秒ですが)曲が流れるシステムを見て
もっと精度の良いソフトがあればいいなぁ、と思って作ってみようと思い立ちました。
イントロは極めると最初の1音2音でわかるので、押してから1秒も流れるとなんだかなーという感じになってしまうので。

引用返信 編集キー/
■3684 / inTopicNo.5)  Re[4]: ArrayListをランダムにシャッフル
□投稿者/ なちゃ (32回)-(2007/05/19(Sat) 02:03:06)
No3678 (Back さん) に返信
> >επιστημηさん
> 最初、これだとあまり変わらないようなと思いましたが
> よくよく考えてみるとn番目からとってきた0番目と入れ替えてるんで、結構ばらけさせられそうですね。
> 要素数の半分ぐらいループすれば良い感じにできそうです。
> シンプルで効果的な方法、ありがとうございます。
> アルゴリズムが苦手で、なんか高度な手法書かれたら多分理解できずに終わりそうだったので。

シャッフルは、まさにシャッフルするのが定石的な方法です。
覚えておくといいと思いますよ。
※実質的にまさにシャッフルになってるのは分かりますよね?

引用返信 編集キー/
■3689 / inTopicNo.6)  Re[5]: ArrayListをランダムにシャッフル
□投稿者/ ぽぴ王子 (204回)-(2007/05/19(Sat) 11:44:23)
ぽぴ王子 さんの Web サイト
とりあえずちょっとソースを書いてみました。
日本語で説明するのが面倒だったので(といういいわけ)。
元リストは手持ちのMP3ファイルからぶっこぬきました。
# 文句は言わせません(誰も言わない)

    // 元リスト
    ArrayList listSrc = new ArrayList();
    listSrc.Add("伊武雅刀 - 子供たちを責めないで.mp3");
    listSrc.Add("ダンディ坂野 - OH!NICE GET's!!.mp3");
    listSrc.Add("岡村靖幸 - カルアミルク(Live Version).mp3");
    listSrc.Add("筋肉少女帯 - 日本印度化計画.mp3");
    listSrc.Add("戸川純 - 諦念プシガンガ.mp3");
    listSrc.Add("聖飢魔II - 地獄への階段(完結編).mp3");
    listSrc.Add("椎名林檎 - 丸の内サディスティック.mp3");
    listSrc.Add("電気グルーヴ - ビーチだよ!電気GROOVE.mp3");
    listSrc.Add("怒髪天 - アストロ球団応援歌 〜絶叫ver.〜.mp3");
    listSrc.Add("平井堅 - POP STAR.mp3");
    listSrc.Add("矢野顕子 - ラーメンたべたい.mp3");
    listSrc.Add("槇原敬之 - 印度式.mp3");
    listSrc.Add("井上和彦 - よろしく仮面テーマ.mp3");
    listSrc.Add("塚田三喜夫 - ザ・チャンバラ.mp3");
    listSrc.Add("飯島愛 - ナイショDEアイ!アイ!.mp3");
    listSrc.Add("野際陽子 - 非情のライセンス(TVサイズ).mp3");

    // シャッフル後のリスト
    ArrayList listDst = new ArrayList();

    // 乱数
    Random rdm1 = new Random(unchecked((int)DateTime.Now.Ticks));

    // 元リストがなくなるまでループ
    while (listSrc.Count > 0)
    {
        int value = rdm1.Next(listSrc.Count);

        // 新リストへ追加
        listDst.Add(listSrc[value]);

        // 元リストから削除
        listSrc.RemoveAt(value);
    }

でも、なちゃさんが書かれているとおり、シャッフルだからトランプのシャッフルと同じように
するのがいいのかもしれないですね。

> アルゴリズムが苦手で、なんか高度な手法書かれたら多分理解できずに終わりそうだったので。

プログラムを組む上でアルゴリズムはなくてはならないものだと思いますので、苦手なものでも
勉強しておくことが大事かと。

# と言いつつ自分も奥村晴彦さんの「C言語による最新アルゴリズム事典」を途中で読み捨てているのは秘密

引用返信 編集キー/
■3693 / inTopicNo.7)  Re[6]: ArrayListをランダムにシャッフル
□投稿者/ επιστημη (521回)-(2007/05/19(Sat) 19:41:51)
επιστημη さんの Web サイト
>     // 乱数
>     Random rdm1 = new Random(unchecked((int)DateTime.Now.Ticks));
>     // 元リストがなくなるまでループ
>     while (listSrc.Count > 0) {
>         int value = rdm1.Next(listSrc.Count);
>         // 新リストへ追加
>         listDst.Add(listSrc[value]);
>         // 元リストから削除
>         listSrc.RemoveAt(value);
>     }

リスト二本も要らんかな。

for ( i = 0; i < N; ++i ) {
  int value = i以上N未満の乱数。
  i 番目と value 番目を交換
}

引用返信 編集キー/
■3695 / inTopicNo.8)  Re[7]: ArrayListをランダムにシャッフル
□投稿者/ ぽぴ王子 (205回)-(2007/05/19(Sat) 20:16:03)
ぽぴ王子 さんの Web サイト
No3693 (επιστημη さん) に返信

> リスト二本も要らんかな。

おー、そうッスねー。
というわけで、ループの部分を書き換えてみますた。

    // επιστημη版
    for (int i = 0; i < listSrc.Count; i++)
    {
        int value = rdm1.Next(listSrc.Count);
        object song = listSrc[value];
        listSrc[value] = listSrc[0];
        listSrc[0] = song;
    }

    // シャッフルと言うとこんな感じなんじゃないの?版(by王子)
    for (int i = 0; i < listSrc.Count; i++)
    {
        int value = rdm1.Next(listSrc.Count);
        object song = listSrc[value];
        listSrc.Add(listSrc[value]);
        listSrc.RemoveAt(value);
    }

引用返信 編集キー/
■3696 / inTopicNo.9)  Re[8]: ArrayListをランダムにシャッフル
□投稿者/ επιστημη (522回)-(2007/05/19(Sat) 21:24:24)
επιστημη さんの Web サイト
2007/05/19(Sat) 21:52:51 編集(投稿者)
> // シャッフルと言うとこんな感じなんじゃないの?版(by王子)
>     for (int i = 0; i < listSrc.Count; i++)
>     {
>         int value = rdm1.Next(listSrc.Count);
>         object song = listSrc[value];
>         listSrc.Add(listSrc[value]);
>         listSrc.RemoveAt(value);
>     }

なるほどー。
デッキからデタラメに一枚抜いてデッキのアタマに重ねるのか。
可変長"配列"だから途中から引っこ抜くのは時間計算量O(N)なんでちょびっと遅いか。

引用返信 編集キー/
■3711 / inTopicNo.10)  Re[5]: ArrayListをランダムにシャッフル
□投稿者/ Back (3回)-(2007/05/20(Sun) 09:46:19)
> シャッフルは、まさにシャッフルするのが定石的な方法です。
> 覚えておくといいと思いますよ。
このやり方がシャッフルっていう言葉があるぐらい有名な手法なんですかね?
定石とは全然知らなかったので、覚えておきたいと思います。

一応実装自体は最初の
1. N未満の乱数iを生成
2. data[0]とdata[i]を交換
3. 1,2 を数回繰り返す
この方法で実装して、無事ランダムに再生する事ができるようになりました。

お二人が追加で書いてくださったソースを試しながら、どういう動作をするのか勉強してみたいと思います。
ありがとうございました。
解決済み
引用返信 編集キー/
■3712 / inTopicNo.11)  Re[6]: ArrayListをランダムにシャッフル
□投稿者/ よねKEN (39回)-(2007/05/20(Sun) 11:37:24)
よねKEN さんの Web サイト
2007/05/20(Sun) 11:37:44 編集(投稿者)

No3711 (Back さん) に返信
>>シャッフルは、まさにシャッフルするのが定石的な方法です。
>>覚えておくといいと思いますよ。
> このやり方がシャッフルっていう言葉があるぐらい有名な手法なんですかね?

「ある集合から"重複無く"要素を取り出したい」という質問は
プログラミング言語の種類に関わらず昔からよく質問に上がるネタでして、
で、それらのたぶんほとんどすべての回答は、
トランプのシャッフルと同じ発想が効率がよいよというアドバイスに収束するので、
「シャッフル」という名のアルゴリズムがどこかで明確に定義されているわけではなく、
経験的に定番の手法ですよ、という意味だと思います。

解決済み
引用返信 編集キー/
■3727 / inTopicNo.12)  Re[7]: ArrayListをランダムにシャッフル
□投稿者/ なちゃ (33回)-(2007/05/20(Sun) 22:16:28)
ああすみません。

> 「シャッフル」という名のアルゴリズムがどこかで明確に定義されているわけではなく、
> 経験的に定番の手法ですよ、という意味だと思います。

っていうようなことです。

厳密に「シャッフル」を行うといっているのでもなくて、
なんというか、乱数を出して重複チェックをしながらとかではなく、
単に最初の配列などの要素を適当な方法で「入れ替える」のが定番だ、ってような意味でした。

※入れ替え方なんかもいろいろ考えられますが、その辺の細かいことまでは言及してません。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -