• ベストアンサー

確率を設定したい

FLASHを使って、 以下のサイトのように 確率を設定してあたりを出したいのです。 http://www.net-hp.co.jp/flash/pachisuro/flash-pachi.html http://www.net-hp.co.jp/flash/kuji/flash-kuji.html 参考にできる書籍、サイト等がありましたら 教えてください。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
noname#35109
noname#35109
回答No.1

はっきり言って, このような問題と言うか,ご質問は大変好きな部類に入ります。 いろいろ思考するのは楽しいです。 参考にできる書籍、サイト等知りませんが,原理ならわかります。 等数の数が多く,説明しにくいので,「1等」,「2等」,「3等」だけだっとして説明します。 仮に 「1等」に 4,「2等」に 3,「3等」に 2  という値が入力されたとします。 その場合, 「1等」と書かれたボールを4個, 「2等」と書かれたボールを3個, 「3等」と書かれたボールを2個, 合計9個のボールを用意し,一つの箱に入れて,無作為に抽出すれば, 「1等」と書かれたボールを取る確率は4/9, 「2等」と書かれたボールを取る確率は3/9, 「3等」と書かれたボールを取る確率は2/9, となります。 当然,「1等」を取る確率が一番高く,「3等」を取る確率が一番低くなります。 これをスクリプトにすれば良いわけです。 また,取ったボールの等数によって,その後のアニメーションを変えれば,確率変動したアニメーションになります。 「T1」 「T2」 「T3」 という変数名のテキスト入力のテキストフィールドを用意します。 また「Ans」という変数名のテキストボックスと,適当なボタンを用意します。 そして,作ったボタンに ---コピペ可------------------ on (release) { mojiretsu = ""; for (i=0; i<T1; i++) { mojiretsu = mojiretsu+"1"; } for (i=0; i<T2; i++) { mojiretsu = mojiretsu+"2"; } for (i=0; i<T3; i++) { mojiretsu = mojiretsu+"3"; } mojisuu = mojiretsu.length; ransuu = Math.floor(Math.random()*mojisuu)+1; Ans = substring(mojiretsu, ransuu, 1); } -------------------------- というようなスクリプトを書いて,パブリッシュ。 テキストフィールド「T1」 「T2」 「T3」 に適当な数値を入力し,ボタンをクリックすれば, 「Ans」という変数名のテキストフィールドに「1」か「2」か「3」の数字が出力されます。当然,指定された確率で出ます。 この1~3の場合によって,以降のアニメーションを動作させれば良いわけです。 上のスクリプトの説明を書いておきます。 全角空白文字が入っていますので,そのままコピペは不可です。 -------------------------- on (release) {   //変数 mojiretsu を初期化   mojiretsu = "";   //T1に入力された数字の回数分,下をループ   for (i=0; i<T1; i++) {     //変数 mojiretsu に mojiretsu と "1" という文字を連結     mojiretsu = mojiretsu+"1";   }   //T2に入力された数字の回数分,下をループ   for (i=0; i<T2; i++) {     //変数 mojiretsu に mojiretsu と "2" という文字を連結     mojiretsu = mojiretsu+"2";   }   //T3に入力された数字の回数分,下をループ   for (i=0; i<T3; i++) {     //変数 mojiretsu に mojiretsu と "3" という文字を連結     mojiretsu = mojiretsu+"3";   }   // mojiretsu の中の文字数を計算   mojisuu = mojiretsu.length;   // 1~文字数 の乱数を取得   ransuu = Math.floor(Math.random()*mojisuu)+1;   // 変数Ans に mojiretsu の ransuu番目の文字を出力   Ans = substring(mojiretsu, ransuu, 1); } --------------------------- もっと簡単に言うと, T1に 4, T2 に 3, T3 に2 という数値が入力されたとき, 111122233 という文字列(mojiretsu)を作成し, 1~7までのランダムな数(ransuu)を得て, もし,その乱数が 5 だったら, 111122233 のうち 5番目,つまり "2" という文字を Ans に出力しろ ということです。 ちなみにスロットの場合ですが, 「START」ボタンにこのようなスクリプトを用意し, もし,Ans が 1 であれば, どの「STOP」ボタンをクリックしても,「1等」つまりスロットで言うラッキー「7」しか出ないようになっています。 ですから,目押しはできないのです。 応用すれば,色々つくれます。

rabu_chihaha
質問者

お礼

ありがとうございます。 仕組みがわかりました。 動きはともかく、設定した確率であたりが出るようになりました。 ありがとうございます。 またよろしくお願いします。

その他の回答 (1)

  • DPE
  • ベストアンサー率85% (666/776)
回答No.2

アニメや演出はさておき、クジの部分だけを考えますが。 1~ 100 の範囲で乱数を作った時、乱数の出方に偏りがないことを前提とすると、ある特定の1つの数字(仮に1とします)が出る確率は、1 ÷ 100 x 100 で1%です。 1か2のどちらかでいいとなれば、2 ÷ 100 x 100 で2%にアップします。 つまり、例えば 10 %の確率とは、1~ 100 の間で乱数を作り、この数が1~ 10 の間であれば何かをする、という方法でも表現できます。 例えばパチスロで、大当たりの確率が 10 %であれば (↓各行頭に全角のスペースが入っています。コピーする際は、全て半角のスペースかタブに置き換えてください)  //1~100の間で乱数を作る  rnd = Math.floor( Math.random() * ( 100 - 1 + 1 ) ) + 1;  //10%の確率で大当たり、それ以外はハズレ  if( rnd >= 1 && rnd <= 10 )  {   /*ここに、大当たりの処理を書く*/  }  else  {   /*ここに、ハズレの処理を書く*/  } こんな感じになります。 福引のように、当たる確率が1等 10 %・2等 30 %・3等 60 %という、全部合わせて 100 %になり、必ずいずれかの等級に決まるような場合でも、考え方は同じです。 範囲で確率を決める場合、大切なのは出た乱数が含まれうる範囲の広さだけであって、どの範囲に属するかはどうでもいいことです。 上記の例では1~ 10 までの乱数が出れば大当たりとしましたが、その代わりに 91 ~ 100 の数字であれば大当たりとしても、10 %の確率であることに変わりはないからです。 福引ですと、スクリプトは次のようになります。  //1~100の間で乱数を作る  rnd = Math.floor( Math.random() * ( 100 - 1 + 1 ) ) + 1;  //10%の確率で1等  if( rnd >= 1 && rnd <= 10 )  {   /*ここに、1等当せんの処理を書く*/  }  //30%の確率で2等  else if( rnd >= 11 && rnd <= 41 )  {   /*ここに、2等当せんの処理を書く*/  }  //それ以外は3等  else  {   /*ここに、3等当せんの処理を書く*/  } ------------------------------------------------------------ ところで、福引の確率ですが。 福引のポスターに  1等 × 10 本  2等 × 30 本  3等 × 60 本 とあったら、1等の確率は 10 ÷ 100 × 100 = 10 で、10 %だと思いますよね。 しかし、ガラガラ式(^^;)の福引で途中で玉を追加しないものとすると、これは、まだ誰も引いていない、福引が始まった直後の状態での確率にすぎません。 既に1等が 10 本出た後だったら、自分が引く頃には1等は絶対に出ない、つまり1等の確率は0%ということになります。 逆に、2等と3等が全て出た後でガラガラの中に1等の玉しか残っていないようなら、1等の確率は 100 %です。 ご提示のサンプルでも、当せん本数に限りがあり、既に指定の本数だけ出てしまった等は絶対に出ないようになっています。 この確率の作り方を考えてみましょう。 いろいろな考え方があります。 簡単なのは、クジを引く度にガラガラの中の玉を減らしていく要領で、配列に情報を用意し、抽せんの度に出た要素を削除していく方法です。 配列変数とは、同じ名前で管理番号(インデックスといいます)だけが違う複数の変数の集まりです。 インデックスは他の変数などを使っても指定できます。 配列変数の各要素の中に等級を記述しておき、乱数を作って配列変数内の要素を1つ、ランダムに選択します。 要素がいくつあるかは、Array.length というプロパティを見ると分かります。 例えば length が5の時、配列変数の要素は5つありますが、インデックスは0から始まることに注意しましょう。配列変数の名前が lot なら、lot[ 0 ] ~ lot[ 4 ] という名前の変数があります。 従って、0~ length - 1 までの範囲で乱数を作ることで、配列内の要素をランダムに1つ取り出せるようになります。 なお、指定の範囲内で乱数を作る方法についてはこちらをご参考になさってください。  ・Math.random() でランダムな整数を取得する方法   http://www.macromedia.com/jp/support/flash/ts/documents/fl0173.html 取り出す番号を作成できたら、そのインデックスの配列変数に格納された値を見ます。 このあたりは、#1の方と同じ発想です。 1度引いたクジは無効になります。同じクジを重複して引かないように、配列変数から要素を削除してしまいましょう。 配列を扱う Array クラス( Flash MX 以前はオブジェクト)には、指定のインデックスを持つ要素を削除する、splice という機能(メソッドといいます)があります。このメソッドで、1度出た要素は削除していきます。 削除するインデックスは、乱数で出てきた数値を指定します。 要素を削除すると、length の値も変化します。乱数を作る時には、length を参照して作るスクリプトにするといいでしょう。 length が0になっていれば、クジは1本も残っていないことになります。福引終了のアニメなどに利用してください。 この方法は考え方もシンプルで分かりやすいのですが、1つ欠点があります。 クジの総数が 100 本くらいならまだしも、空クジが大量にあるなどで総数が 1000 ・ 2000 本と多い場合、length が 1000 や 2000 になる巨大な配列変数が必要になります。 配列変数はメモリを占有しますので、要素数が多いほどメモリを圧迫してしまいます。 今時のパソコンであればあまりケチくさく考えなくても大丈夫ですが、できれば効率よくデータを管理したいものです。 そこで、冒頭でご紹介しました、ランダムに選んだ数字がどの範囲に属するかで決める方法を思い出していただきたいのですが。 これと配列変数を組み合わせた方法をご紹介します。 Flash の配列変数には、仕切りを設定して複数の情報を管理できる機能があります。 例えば  lot[ 0 ] = { prize : 1 , num : 10 }; とすると、lot[ 0 ] には prize と num という仕切りがあり、同じ lot[ 0 ]という名前の変数で2つの情報を保持できます。 参照する時は  lot[ 0 ].prize このように書きます。 この機能を利用して、何等の情報であるかの情報と、等ごとの残り本数を1つの要素で管理します。 としますと、配列変数は等の数だけ用意しておけば用が足ります。 これとは別に、クジの総数を変数で管理します。仮に、この変数を lot_max とします。 クジを引くごとに lot_max を減算していけば、クジの残り総数が分かります。 更に、当せんした等級の本数も減らしていきます。 乱数は1から lot_max までの範囲で作り、できた数がどの範囲に属するかで、当せんした等級を決めます。 例えば、1等 x 10 ・2等 x 30 ・3等 x 60 の福引では、  1 ~ 10 :1等  11 ~ 40 :2等  41 ~100 :3等 と判断するものと考えます。 クジを引く度に本数が減っていきますので、この範囲は変動します。 そこで、配列変数に保存されている各等ごとの残り本数をもとに、随時範囲を決め直して判定することにします。 スクリプトにしてみますと、大体、次のようになります。 まずはクジのデータとクジの総本数を管理する変数を作ります。 このスクリプトはフレームに設定してください。 ここではクジのデータを予めスクリプトで作っていますが、ご質問文にあるサンプルのように、ユーザーから入力してもらった数値から作ることもできます。  //クジのデータを作成  //要素 prize:等級 num:本数  lot = new Array();  lot[ 0 ] = { prize : 1 , num : 10 };  lot[ 1 ] = { prize : 2 , num : 30 };  lot[ 2 ] = { prize : 3 , num : 60 };  //クジの総数を算出  lot_max = 0;  for( i = 0 ; i < lot.length ; i++ )  {   lot_max += lot[ i ].num;  } ステージに、クジを引くボタンインスタンス lot_btn があるとします。 このボタンには、実際にクジの処理をするスクリプトを書きます。  on(release)  {   //クジが全てなくなったら終了   if( lot_max <= 0 )   {    //ボタンを押せなくする    lot_btn._alpha = 30;    lot_btn.enabled = false;    trace( "終了しました" );   }   else   {    //1~クジの総数の範囲で乱数を作る    rnd = Math.floor( Math.random() * ( lot_max - 1 + 1 ) ) + 1;    //クジの等級を調べる    //配列の要素を全てチェックするか、等級が確定したらチェック終了    lot_result = -1;    range_begin = 1;    for( i = 0 ; ( i < lot.length ) && ( lot_result == -1 ) ; i++ )    {     //各等の残り本数から、範囲の終点を決める     range_end = range_begin + lot[ i ].num;     //引いた乱数がこの範囲にあれば、等級を確定     if( rnd >= range_begin && rnd < range_end )     {      //等級と配列の番号を記録      lot_result = lot[ i ].prize;      array_index = i;     }     //次の範囲の始点を変更     range_begin = range_end;    }    //本数を更新    lot_max--;    lot[ array_index ].num--;    //空になった等級は配列から削除    if( lot[ array_index ].num <= 0 )    {     lot.splice( array_index , 1 );    }   }  } クジのデータは lot という配列変数の中に作ります。 確定した等級は、lot_result という変数に入っています。この値を元に、賞品配送の手続きや画面演出等を行うことになるかと思います。 最初は福引が始まったばかりで、クジが 100 本まるまる残っている状態です。 1~ 100 の範囲で乱数を作り、仮に、5が出たとしましょう。 1~ 10 までが1等ですから、いきなり1等当せんですね ^^; クジの総数を管理する lot_max と、1等の情報を管理している lot[ 0 ] の num から、それぞれ本数を1ずつ減らします。 次の乱数の範囲は1~ 99 、1等の範囲は1~9までとなります。 他の等級も同様に、当せんする度に本数を減らしていきます。 もし1等が 10 本全て出た、つまり lot[ 0 ].num が0になった場合は、lot[ 0 ] を配列変数から削除します。 すると、lot の中には2等と3等の情報だけが残ります。 例えば、2等が 10 本、3等が 20 本残っているとしましょう。 引き続き1~クジの残り( lot_max = 30 )の範囲で乱数を作り、残った等の本数から改めて範囲を設定して等級を判断します。 範囲は  1 ~ 10 :2等  11 ~ 30 :3等 となり、1本も残っていない1等は出なくなります。 1等の情報を削除すると、この時に配列変数 lot の要素数( length )は2つに減り、欠番になったインデックスには後ろの要素が順次前に詰められます。 最初は lot[ 0 ] = 1等・lot[ 1 ] = 2等・lot[ 2 ] = 3等となっていたのですが、1等が尽きた後は lot[ 0 ] = 2等・lot[ 1 ] = 3等に変わります。 つまり、配列のインデックスと等級は一致しないため、インデックスをもとに等級を決めたり、等級からインデックスを指定するといったことはできません。 上記のスクリプトでは、インデックスが変わっても等級を取得できるようにとの意味で、配列変数の中に prize という仕切りを作って等級の情報を保存しています。 等級の判断と範囲の決め方が、少々分かりにくいかと思います。 できた乱数がどの範囲に含まれるかで等級を決めるわけですが、ループを使って配列変数にある要素の数だけ判定します。 もし、ある等が全て出ていれば配列からは削除されているはずなので、本数が尽きた等級と判断されることはありません。 仮に、1等x5本、2等x 10 本、3等x 20 本、残っているとします。 この状態では、範囲は  1 ~ 5 :1等  6 ~ 15 :2等  16 ~ 35 :3等 となります。 範囲は常に1から始まりますから、ループに入る前に範囲の始点を1に設定しておきます。上記のスクリプトでは、range_begin という変数に入れています。 範囲の終点である range_end は、始点+各等の残り本数で求めます。上記の例ですと、1等なら1+5=6になるので、判定する時は range_end 未満(終点は含まない)です。 出た乱数が最初の範囲になければ、次の等級のデータを見て、次の等に当せんしているかどうかを調べます。 次の等級の範囲の始点は、前の range_end がそのまま使えます。次のループに入る前に range_start に代入しておくことで、次の範囲を指定できます。 これを繰り返して、等級を確定します。 ループ内で等級が確定しても、本数を減らしたり配列変数から削除するといった後処理は、クジの結果を判定するループ内では行わないようにしましょう。 ある等級の本数が尽きて配列変数から削除した場合、lot.length の値が変化してループが正常に継続しなくなることがあります。 後始末のためには、どの要素を操作するのかを控えておく必要があります。 実はループ後のループカウンタ i を利用することもできますが、分かりにくいので、等級が確定した時に array_index に i の値を保存して、ループの外でも操作する要素を参照しやすくしています。 ・・・文字だけの説明ですと、ちょっと分かりにくいかもしれません。 データを少なくして計算だけで何とかする方法が難しいならば、まずは簡単な、配列に全クジのデータを作って少しずつ切り落としていく方法で作ってみるといいと思いますよ。 長くなってすみませんでした。

rabu_chihaha
質問者

お礼

大変詳しい説明ありがとうございます。 確率って考えれば考えるほど難しくなっていきます(泣) 今後もよろしくお願い致します。

関連するQ&A