2015-01-26 2 views
0

Я борюсь с (возможно, простым) алгоритмом перетасовки и генерации массива.Упорядочить массив определенным образом (элементы колеса рулетки)

Я создаю простой бэкэнд (PHP/MySQL) для игры в рулетку (JS/HTML). Рулетка не имеет числовых значений, как обычно, вместо этого есть четыре приза, которые пользователь может выиграть, распределенные в 12 сегментах рулетки.

мне нужен массив так:

// Note that PRIZE4 is listed only once as it is valuable prize. 
// PRIZE3 is less valuable so it is listed twice, etc. 
// Prizes are skipping each other so you should never see two identic prizes next each other. 
var items = [PRIZE1, PRIZE2, PRIZE1, PRIZE2, PRIZE1, PRIZE2, PRIZE1, PRIZE2, PRIZE1, PRIZE3, PRIZE4, PRIZE3]; 

И у меня есть призы в таблице SQL, как это:

+----+------------+--------------+ 
| id | name  | giveaway_cap | 
+----+------------+--------------+ 
| 1 | PRIZE1  |   255 | 
| 2 | PRIZE2  |   300 | 
| 3 | PRIZE3  |   30 | 
| 4 | PRIZE4  |   15 | 
+----+------------+--------------+ 
4 rows in set (0.00 sec) 

Колонка giveaway_cap определяет, как многие из каждого приза можно выиграть (Я храню эти счета в другой таблице), но может использоваться как вес каждого приза.

Мне нужен алгоритм (желательно PHP), который будет генерировать массив, как описано выше на основе этой таблицы.

Спасибо.

+0

Если «giveaway_cap» из 3 призов очень низок, а 1 приза очень высок, невозможно создать массив, где не две одинаковые цены находятся рядом друг с другом. – pbaldauf

+1

Псевдокод: for (array_length) {rand между 1 и 3; if (так же, как и раньше) rand (между оставленными значениями)} – Comum

+1

Поскольку @Comum предлагает использовать случайную функцию. Выделяется ли значение между 0 и 1 ценой 1. Между 1 и 2 = цена 2. Между 2 и 2.5 цена 3. Между 2.5 и 2.95 цена 3. Между 2.95 и 3 цена 4 .... – pbaldauf

ответ

0
<?php 
$connect=mysqli_connect("localhost","my_user","my_password","my_db"); 

$sql="SELECT id,name,giveaway_cap FROM table"; 
$result=mysqli_query($connect,$sql); 

$prizes = array(); 
while($row=mysqli_fetch_array($result)) //iterate 4 times on caps != to 0 
{ 
$count = $row['giveaway_cap']; 
    if($count != '0') 
    { 
    $prizename = $row['name']; 
    $prizes[$prizename]=$count; 
    } 
} 

$prizewheel = array(); 
foreach ($prizes as $prize=>$value) // iterate 600 times if caps !=0 
{ 
$prizewheel = array_merge($prizewheel, array_fill(0, $value, $prize)); 
} 

$finalprize=array(); 

$f = 0; 
while($f < 12) //iterate 12 times is # of caps >= 12,final array 
{ 
$prizename = $prizewheel[array_rand($prizewheel)]; 
$finalprize[] = $prizename; 
$f++; 
} 
?> 
0

Вы можете сгенерировать массив случайных вроде этого:

$rows = array(
    array(
     'id' => 1, 
     'name' => 'PRIZE1', 
     'giveaway_cap' => 255, 
    ), 
    array(
     'id' => 2, 
     'name' => 'PRIZE2', 
     'giveaway_cap' => 300, 
    ), 
    array(
     'id' => 3, 
     'name' => 'PRIZE3', 
     'giveaway_cap' => 30, 
    ), 
    array(
     'id' => 4, 
     'name' => 'PRIZE4', 
     'giveaway_cap' => 15, 
    ), 
); 

$output = array(); 

foreach ($rows as $row) { 
    for ($i = 0; $i < $row['giveaway_cap']; $i++) { 
     $output[] = $row['name']; 
    } 
} 

shuffle($output); 

//to get the next prize 
$nextPrizeKey = array_rand($output); 
$nextPrize = $output[$nextPrizeKey]; 

//remove the won prize 
unset($output[$nextPrizeKey]); 

Что это делает создает отдельный элемент в массиве для каждого из призов giveaway_caps. Затем в качестве выигрышей вы уменьшаете количество giveaway_cap, и это уменьшит вероятность того, что пользователь снова ударит по этому призу.

Если вы хотите, чтобы массив был статическим, вы можете сохранить его после первоначального генерации, либо в базе данных, либо в кешировании (APC, Memcahche). Затем вы просто удалите каждую запись, которую пользователи приземлятся до тех пор, пока ее не останется. Вы можете получить следующий приз с array_rand, а затем удалить ключ из массива.

Надеюсь, это поможет.

Mic

1

Я нашел это действительно хороший algorithm поиск на SO. Он генерирует случайные числа, основанные на весе. С его помощью, один подход к вашей проблеме может быть следующим:

// This is the function that generates random numbers based on weigth. 
function getRandomWeightedElement(array $weightedValues) { 
    $rand = mt_rand(1, (int) array_sum($weightedValues)); 
    foreach ($weightedValues as $key => $value) { 
     $rand -= $value; 
     if ($rand <= 0) { 
      return $key; 
     } 
    } 
} 

$items = [ "PRIZE1" => 255, "PRIZE2" => 300, "PRIZE3" => 30, "PRIZE4" => 15];// Array of available prizes. It can be retrieved from the DB. 
$total = (int) array_sum($items);// Total. I use it to work out the weight. 
$items_w = [ "PRIZE1" => (255/$total) * 1000, "PRIZE2" => (300/$total) * 1000, "PRIZE3" => (30/$total) * 1000, "PRIZE4" => (15/$total) * 1000];// find out the weight somehow. I just divide number of available items by the total. 
$res = []; 
$previous = NULL; 
while (count(array_diff(array_keys($items), $res))) {// Loop until the result has all available prizes. 
    $res = []; 
    for ($i = 0; $i < 12; $i++) { 
     while ($previous == ($new = getRandomWeightedElement($items_w))) {}// Two consecutive prizes of the same type aren't allowed. 
     $res[] = $new; 
     $previous = $new; 
    } 
} 

echo implode(',', $res); 

Это просто решение, я уверен, что существует несколько способов решения этой проблемы.

Примечание: Я использую синтаксис короткого массива php 5.4, если ваша версия PHP ниже PHP 5.4, замените [] на array(). Также имейте в виду, что могут быть проблемы в определенных ситуациях, например, есть только один тип приза, или если невозможно создать массив призов без двух последовательных призов, то же самое. В любом случае вам придется управлять этими ситуациями.

Надеюсь, это поможет.

+0

Этот код выглядит многообещающим. :) Я попытаюсь включить его в свой существующий код. Спасибо, сейчас! – MaRmAR

Смежные вопросы