За последние 24 часа нас посетили 22146 программистов и 1119 роботов. Сейчас ищут 733 программиста ...

Вывести из базы 1 строку с шансом

Тема в разделе "PHP и базы данных", создана пользователем #Ivan, 30 ноя 2019.

  1. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    У меня есть такой запрос

    PHP:
    1. SELECT * FROM `prizes` WHERE `caseid`='{$id}' AND `winner`='0' ORDER BY RAND() LIMIT 1
    Я получаю рандомный приз из базы, но есть проблема, при выдачи выдается рандом полный, т.е может 4 раза подряд выпасть дорогой приз а дешевый нет. Я добавил в таблицу параметр chance подскажите как мне получить так-же 1 строку из базы но уже сделать выборку не только рандомно но и по шансу. Шанс до 100, т.е если указано 90 выпадает чаще чем если указано 89 и наоборот. Если указано 10 выпадает реже если указано 90 но выпасть может.

    В базе 11 тысяч призов.

    Иван, поместить вопрос в раздел "Сделайте за меня" значит объявить себя тупым и ленивым.
    Не будь таким :)
    — Модераторъ
     
    #1 #Ivan, 30 ноя 2019
    Последнее редактирование модератором: 1 дек 2019
  2. Алекс8

    Алекс8 Активный пользователь

    С нами с:
    18 май 2017
    Сообщения:
    1.730
    Симпатии:
    359
    подпишусь))
     
    #Ivan нравится это.
  3. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Очень тяжело найти ответ на этот вопрос, уже три дня ищу нормальный ответ, обошел все форумы, ответа даже в гугле нет. Странно..
     
  4. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Тут нет ничего странного, либо рандом, либо чёткая последовательность шанса с мнимым рандомом.
     
    #Ivan нравится это.
  5. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Я понимаю, но ведь чёткая последовательность шанса с мнимым рандомом. зависит от владельца сайта? я ведь просто хочу чтобы шанс выпадения какого-то дорогого приза был реже чем дешевых. Как мне это реализовать правильно?
     
  6. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    выбираешь например 50 дорогих, 500 средних и 5000 дешёвых призов, перемешиваешь и сохраняешь в БД эту последовательность, таких последовательностей сохраняешь несколько раз, вот тебе "случайные" призы на много лет вперёд, просто берёшь уже не рандомно, а строго в этой сохранённой последовательности по порядку. Если изменятся условия, то перегенерировать подобный список дело считанных секунд.
     
    #Ivan нравится это.
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    @#Ivan Подумай о таком трюке как shuffle. Берешь любую последовательность значений без повторов, один раз перемешиваешь её и потом последовательно выбираешь из неё значения. Результат выглядит как "случайно и без повторов".

    Если надо чтобы шанс выпадения был неодинаковым, ну напихай в исходную последовательность несколько экземпляров того, что должно быть более вероятным. Далее — всё так же.

    https://ru.stackoverflow.com/a/501992/176610
     
    #7 artoodetoo, 30 ноя 2019
    Последнее редактирование: 1 дек 2019
    #Ivan нравится это.
  8. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    А это кодом php можно как-то сделать проще? при условии что допустим в базе осталось только 50 призов что тогда делать? очень непонятно. :(
     
  9. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    это и нужно делать на РНР, а потом сохранить в БД
    PS нет смысла эту генерацию последовательности проводить на уровне СУРБД, если только ради спортивного интереса, но лично мне не настолько скучно.
     
    #Ivan нравится это.
  10. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Для меня это сложно конечно будет реализовать, не так поставил вопрос, есть какой-то простой метод?
     
  11. qdevelopment

    qdevelopment Новичок

    С нами с:
    13 окт 2019
    Сообщения:
    41
    Симпатии:
    13
    Легче с помощью php получить число, что-то типа
    PHP:
    1. function getChance(array $arr) {
    2.     $rand = mt_rand(1, array_sum($arr));
    3.     foreach ($arr as $value) {
    4.         $rand -= $value;
    5.         if ($rand <= 0) {
    6.             return $value;
    7.         }
    8.     }
    9. }
    10.  
    11. $chance = getChance(range(1,100));
    Потом делать запрос
    Код (Text):
    1.  
    2. SELECT * FROM `prizes` WHERE `chance` = $chance ORDER BY RAND() LIMIT 1
    Работоспособность не проверял, но скажу заранее, это не гарантирует 100% результат. Вполне возможно что chance 1 будет 1000 раз подряд, хотя и маловероятно)
     
  12. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Вывел циклом 10 раз подряд, вот что получилось.
    Код (Text):
    1. 91
    2. 96
    3. 74
    4. 85
    5. 91
    6. 30
    При таком рандоме, шансы по моему бесполезны. Меня так ограбят ;)
     
  13. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Что значит в базе осталось 50 призов? Сдаётся мне вы еще меньше понимаете, чем спрашиваете.
    Например у вас есть 10 разных позиций дорогих призов, за месяц вам их надо раздать 50 штук, Вы рандомно выбираете 50 штук из этих 10. В итоге у вас 3 хододильника, 5 телевизоров, 7микроволновок и тд. общее количество 50. То же самое и с остальными ценовыми категориями.
    Про наличие призов на складе - это уже отдельная тема. Но ничего не мешает при отсутствии выбранного приза на складе взять следующий "по списку".
    --- Добавлено ---
    @qdevelopment, код должен гарантировать 100% результат по ТЗ. Иначе такой код абсолютно не имеет смысла.
     
    #Ivan нравится это.
  14. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Вам не будет сложно показать пример как это сделать? я не совсем понимаю как это реализовать.
    Я объясню по простому:
    В базе допустим 20 строк, у 5 строк шанс равен 10, у 10 шанс 50, у остальных 10 шанс равен 95.
    По шансу, чем больше шанс, тем больше он выпадает чем строка у которой нет шанса, но задача усложняется тем чтобы выпадала строка еще с меньшим шансом но намного реже. Я не понимаю как это сделать.

    Если делать последовательность как я хотел, то я сталкиваюсь с проблемой №2.
    Допустим пользователь A открыл кейс 4 раза и ему выпал предмет с шансом 95, 95, 95, 95, 50
    Пользователь B открыл кейс и ему выпал предмет с шансом 10%
    --- Добавлено ---
    Дополню про базу, допустим если в базе нет тех строк с максимальным шансом берется строка с меньшим шансом (меньшим т.е большим числом напр. 90)
     
  15. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @#Ivan, без понимания периода, нет смысла в процентах шанса.
     
  16. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Всм?
    --- Добавлено ---
    Период в том смысле за сколько выдать?
    --- Добавлено ---
    Период не нужен, мне нужно просто выдать приз с малой долей вероятности выпадения дорогого, но под понятием дорогой, средний и дешёвый как раз нужны шансы, разве нет?
     
  17. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Без периода вся затея не имеет смысла. Вот смотри. Допустим сегодня ты рассчитал шанс выпадения одних процентов относительно других процентов. И о чудо выпал главный приз, как ты при том же алгоритме расчёта гарантируеш, что завтра чуда не случится? Ответ. Никак. Поэтому расчёт должен быть относительно периода. И чем больше период, тем точнее расчёт.
     
    #Ivan нравится это.
  18. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Я до сих пор не понимаю для чего нужен расчет периода в моем случае, если допустим у всех призов будут одинаковые проценты.

    10% - редкий приз.
    60% - не редкий приз.
    80% - частый приз.
    100% - выпадает всегда. (чисто для примера)
    --- Добавлено ---
    Я думаю что я усложняю все то что нужно в конечном итоге получить и это можно реализовать проще. o_O
     
  19. Алекс8

    Алекс8 Активный пользователь

    С нами с:
    18 май 2017
    Сообщения:
    1.730
    Симпатии:
    359
    а если сделать так....
    1. Выбираем число от 1 до 100.. к примеру выпало 34
    2. В базе у нас у каждой позиции уже прописаны значений из цитаты допустим в столбце chance.
    3. Просто берем Ваш запрос и добавляем условие
    Код (Text):
    1.  
    2. SELECT * FROM `prizes` WHERE `caseid`='{$id}' AND `winner`='0' AND chance > 34 ORDER BY RAND() LIMIT 1
    вот и все.. теперь все популярные призы участвуют.. редкие не участвуют..
     
    #Ivan нравится это.
  20. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @#Ivan, для начала надо определится, что именно нужно простота или гарантии?
    Можешь пойти по другому принципу. Создаёшь массив из 90 нулей и 10 единиц, перемешиваешь и выбираешь один элемент, если единица, то отдаёшь главный приз, если ноль, то по тако му же принципу рассчитываешь для 60 и тд.
    Но опять же никаких гарантий, что не отдашь главный приз 100 раз подряд.
     
  21. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Рандом дело такое, может и сразу выпасть 10) и придется отдать главный приз.. а вообще мне на другом форуме сказали следующие:
    "За ORDER BY RAND() Вам могут отрубить руки"
     
  22. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @#Ivan, программимту могут и отрубить, правда 11 тысяч для бд это не тот порядок, чтоб волноваться. Но проблема с ордер бай ранд давно известна и легко решаема. Но почему владельцу магазина, кто-то будет рубить руки?
    --- Добавлено ---
    @#Ivan, Алекс говорил не об этом. Если выпадет 0 или 10 это не значит, что сразу надо отдать главный приз, просто он будет участвовать в рандомной выборке на ровне со всеми. Тоже приемлимый вариант и тоже абсолютно без каких либо гарантий.
     
    #Ivan нравится это.
  23. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    хмм сразу не понял что там стоит знак > больше. Идея мне нравится, остановлюсь на ней.
    --- Добавлено ---
    Тут даже можно использовать функцию рандома выше?
    --- Добавлено ---
    Код (Text):
    1. function getChance(array $arr) {
    2.     $rand = mt_rand(1, array_sum($arr));
    3.     foreach ($arr as $value) {
    4.         $rand -= $value;
    5.         if ($rand <= 0) {
    6.             return $value;
    7.         }
    8.     }
    9. }
    10. $chance = getChance(range(1,100));
    --- Добавлено ---
    Проблема этого кода в том что я вывел 100 раз и было 0 строк меньше 15
     
  24. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Ну как разоритесь, приходите, посочувствуем.
     
    #Ivan нравится это.
  25. #Ivan

    #Ivan Новичок

    С нами с:
    7 ноя 2019
    Сообщения:
    28
    Симпатии:
    1
    Меня пугает ваше сообщение.. Что не так?