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

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

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

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

2回答

6145閲覧

重み付き抽選で複数を同時に取り出す場合のロジック

KazukiKudo

総合スコア37

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

1クリップ

投稿2016/03/16 08:38

重み付き抽選機能を実装したいと思っております。
1つを取り出す場合は、調べたら色々やり方が出てくるのですが、今回やりたいのは重みづけに従って複数を同時に取り出したい場合です。
さらにもう一つ縛りがあって、重みづけを表す割合(確率)は、整数ではなく0~1の間の小数で定義されております。

例えば以下のような連想配列(キーに対する値がその割合を示す)があったとして、これから3つを取り出す場合はどのようなプログラムになりますでしょうか?
(もちろんこの場合'5'が選ばれる確率が一番高いことになります。)

php

1$a = array( 2 '1' => 0.1, 3 '2' => 0.3, 4 '3' => 0.1, 5 '4' => 0.1, 6 '5' => 0.4 7);

できればPHPでコードを示していただくのが一番嬉しいですが、ロジックがわかりやすければ何でも大丈夫です。
すみませんが、どなたかご教示の程、何卒よろしくお願い致します。

ちなみに1つの場合は以下のサイトを参考にしました。
http://lab.sonicmoov.com/development/gacha-logic/
http://pro-tyablog.blogspot.jp/2013/10/php.html
http://d.hatena.ne.jp/moroto1122/20100108/1262936688

0~1の乱数生成はこちらを参考にしました。
http://webkaru.net/php/function-mt-getrandmax/

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

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

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

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

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

yuba

2016/03/16 09:38

5を取り出した後、5は抽選箱に戻されるのですか、戻されないのですか?
KazukiKudo

2016/03/17 03:51

戻されないです。同時に取り出すという表現をしたのですが、伝わりにくくて申し訳ございません。
guest

回答2

0

ベストアンサー

やりたいことはこういうことでしょうか。

php

1<?php 2// 各要素の重み。合計して 1 になっている必要なし 3$weight = array( 4 '一' => 0.1, 5 '二' => 0.3, 6 '三' => 0.1, 7 '四' => 0.1, 8 '五' => 0.4 9); 10 11 12// 抽選を行う 13function roll() { 14 global $weight; 15 $result = array(); // 抽選結果 16 $rest = array(); // 抽選の残り要素 17 foreach ($weight as $key => $w) { 18 $rest[$key] = array('w' => $w); 19 } 20 // ここまでで各要素の重みを初期化 21 22 for ($i = 0; $i < 3; $i++) { // 三回抽選を引く 23 $limit = 0; 24 foreach ($rest as $key => $val) { 25 $limit += $val['w']; 26 $rest[$key]['limit'] = $limit; 27 } 28 // ここまでで $rest の各要素ごとの累積重みを計算 29 // $limit に累積重みの合計値が入る 30 foreach ($rest as $key => $val) { 31 $rest[$key]['limit'] = $rest[$key]['limit'] / $limit; 32 } 33 // ここまでで $rest の各要素ごとの正規化した累積重み X を計算 34 // 0 から 1 までの乱数を発生した場合、直前の要素の X と自分の X の間に 35 // 入る確率は、残っていた要素の重みの大きさに比例する 36 // ので一つ選ぶ 37 $rnd = lcg_value(); 38 $selected = null; 39 foreach ($rest as $key => $val) { 40 if ($rest[$key]['limit'] >= $rnd) { 41 $selected = $key; 42 break; 43 } 44 } 45 unset($rest[$key]); // 選んだ要素は $rest から削除 46 array_push($result, $selected); 47 } 48 return $result; 49} 50 51for ($i = 0; $i < 10; $i++) { 52 print $i . ' --> '; 53 foreach (roll() as $value) { 54 print "[" . $value . "]"; 55 } 56 print "\n"; 57}

投稿2016/03/16 10:57

unau

総合スコア2468

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

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

KazukiKudo

2016/03/17 03:53

ありがとうございます!!試しに動かしたところ、問題なさそうです。 コードも見やすくて大変助かります。
guest

0

籤は無数に入っているのでしょうか?それとも固定数でしょうか?


引いても減らない
例えば例示の1~5の籤が抽選箱にそれぞれ無限に入っており、
ただ出てくる確率が「5」は40%「4」は10%である。
というなら、同時に引く個数と同じ回数、一つずつ引く抽選を行えばいいと思います。


各種1つしかない
そうではなく抽選箱にはそれそれ1つづつ合計5個の籤しか入っていない場合は
そこから複数同時に取り出すということは、抽選箱の中の籤が減っていく引き方になります。
そういう場合の抽選は籤の当選確率を固定には出来ません。
当選確率0.01%の籤でも、5つ同時に引くなら100%引き当てるからです。
こういう場合は重みを確率に変換する作業を行えば良いです。

例のリストから同時に3つ引くことを考える場合
・1つずつの抽選を3回行います。
・抽選毎に重みに従って籤の当選確率を決定します。当選率 = 対象籤の重み / 残り籤の重みの合計

1回目は
[1]1/10(0.1/1) [2]3/10(0.3/1) [3]1/10(0.1/1) [4]1/10(0.1/1) [5]4/10(0.4/1)
ランダム生成を1~10(重みの合計値)にすると簡単かも知れません。
ここで例えば「5」が引き当てられたなら

2回目は次の4つからの抽選です。
[1]1/6(0.1/0.6) [2]3/6(0.3/0.6) [3]1/6(0.1/0.6) [4]1/6(0.1/0.6)
ここで例えば「2」が引き当てられたなら

3回目は次の3つからの抽選です。
[1]1/3(0.1/0.3) [3]1/3(0.1/0.3) [4]1/3(0.1/0.3)

投稿2016/03/16 10:08

hirohiro

総合スコア2068

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

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

KazukiKudo

2016/03/17 03:57

わかりやすくロジックをご説明いただき大変ありがとうございます。勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問