Русское сообщество по скриптингу

Выбор N рандомных значений(без повторов)

Все вопросы по скриптингу для AMXX, помощь в редактировании плагинов.

Модераторы: Subb98, liFe iS GoOD

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только скриптинга для AMX Mod X.

Правила при создании новой темы:
1. При вставке кода плагина необходимо использовать тег [code=php].
2. Любые изображения должны быть загружены, как вложения к вашему сообщению.
3. При описании проблемы или запросе на помощь в редактировании плагина обязательно выкладывайте исходник sma плагина.

Выбор N рандомных значений(без повторов)

Сообщение Dorus » 09 янв 2018, 18:50

У меня есть переменная gTotalBox, которая равна количеству спавнов(подсчитывается из файла)
И есть дефайн SPAWN_BOX, который обозначает, сколько максимум коробок может заспавниться одновременно. Задача - выбрать рандомно SPAWN_BOX(5) коробок из gTotalBox и при этом, чтобы не было повторок.

Код: Выделить всё
#define SPAWN_BOX    5 //Сколько будет спавниться коробок 

new gTotalBox = 10 //Количество подсчитывается из файла, но для примера пусть будет равно 10
new gNum[SPAWN_BOX]

public NewRound()
{
    if(!gTotalBox)
        return
    
    new max_spawn 
= SPAWN_BOX
    if
(max_spawn >= gTotalBox) //Если количество SPAWN_BOX больше имеющегося gTotalBox
    {
        for(new i = 0; i < gTotalBox; i++)    //Просто спавним от 0 до gTotalBox
            spaw_lootbox(i)
        
        return
    
}
    
    for
(new i = 0; i < SPAWN_BOX; i++)
    {
        gNum[i] = random_num(0, gTotalBox)
        
        if
(== 0)    //Если это первый вход, то сравнивать нам не с чем
        {
            spaw_lootbox(gNum[i])
            continue
        
}
        
        if
(== 1)    //Если второй вход - сравниваем с первым
        {
            while(gNum[i] == gNum[0])
                gNum[i] = random_num(0, gTotalBox)
            
            spaw_lootbox
(gNum[i])
            continue
        
}
        
        for
(new k = 0; k < i; k++) //Проходим по всем уже имеющимся элементам
        {
            while(gNum[i] == gNum[k])
                gNum[i] = random_num(0, gTotalBox)
        }
        
        spaw_lootbox
(gNum[i])
    }
}

public spaw_lootbox(num)
{
    log_to_file("addons/amxmodx/logs/file.log", "Num: %d | Total: %d", num, gTotalBox)

Код мне вообще не нравиться, надерьмокодил я тут конечно((
Провел 10 тестов, вроде бы работает

Из file.log:
Код: Выделить всё
L 01/09/2018 - 16:47:45: Num: 18 | Total: 18
L 01/09/2018 - 16:47:45: Num: 5 | Total: 18
L 01/09/2018 - 16:47:45: Num: 6 | Total: 18
L 01/09/2018 - 16:47:45: Num: 3 | Total: 18
L 01/09/2018 - 16:47:45: Num: 10 | Total: 18
L 01/09/2018 - 16:47:45: Num: 16 | Total: 18
L 01/09/2018 - 16:47:45: Num: 0 | Total: 18
L 01/09/2018 - 16:47:45: Num: 4 | Total: 18
L 01/09/2018 - 16:47:45: Num: 14 | Total: 18
L 01/09/2018 - 16:47:45: Num: 17 | Total: 18

Как можно реализовать данную затею более элегантней?


Умммм... Вот такое выдало, аж две повторки(((
Код: Выделить всё
L 01/09/2018 - 17:14:59: Num: 13 | Total: 13
L 01/09/2018 - 17:14:59: Num: 1 | Total: 13
L 01/09/2018 - 17:14:59: Num: 12 | Total: 13
L 01/09/2018 - 17:14:59: Num: 0 | Total: 13
L 01/09/2018 - 17:14:59: Num: 10 | Total: 13
L 01/09/2018 - 17:14:59: Num: 11 | Total: 13
L 01/09/2018 - 17:14:59: Num: 6 | Total: 13
L 01/09/2018 - 17:14:59: Num: 2 | Total: 13
L 01/09/2018 - 17:14:59: Num: 10 | Total: 13
L 01/09/2018 - 17:14:59: Num: 13 | Total: 13
:thumbs_up :yahoo: :bravo:
Группа плагинов:
vk.com/remake_dorus
Аватара пользователя
Dorus
 
Сообщения: 172
Зарегистрирован: 28 авг 2014, 17:58
Благодарил (а): 27 раз.
Поблагодарили: 15 раз.
Опыт программирования: Больше трех лет
Языки программирования: PAWN
C++

Re: Выбор N рандомных значений(без повторов)

Сообщение Subb98 » 09 янв 2018, 21:17

Предлагаю простой алгоритм.

У нас есть N коробок. Пусть это будет 10.

Делим это число пополам (на две одинаковые части).

Берём случайную коробку из первой части - запоминаем её - удаляем элемент. Затем обращаемся ко второй части, делаем то же самое. И так до тех пор, пока не наберём нужное кол-во коробок.

Зачем вообще делить коробки на две части? Для большего рандома. В зависимости от кол-ва коробок, можно поделить и на большее число частей.
«Очень хорошо. Лучше вы, чем я» © Donald J. Trump
Аватара пользователя
Subb98
Модератор
 
Сообщения: 5485
Зарегистрирован: 24 мар 2011, 19:42
Откуда: г. Пермь
Благодарил (а): 1329 раз.
Поблагодарили: 2343 раз.
Опыт программирования: Больше трех лет
Языки программирования: PHP

Re: Выбор N рандомных значений(без повторов)

Сообщение xbass13 » 09 янв 2018, 23:44

Как это реализовать можно посмотреть в rockthevote_custom. Используется Array, выборка 5 рандомных карт
Код: Выделить всё
#define MAX_MAPS 5
#define MAX_MAP_LENGTH 64

bool:RetrieveMaps(s_MapsFound[][])
{
..
    new Array:a_Maps;
    new i_MapsCount = SaveAllMaps(p_File, a_Maps);//выгрузка списка карт в Array:a_Maps;
..

..

    new i_Rand, i_Cnt;
    while (i_Cnt != MAX_MAPS)
    {
        i_Rand = random_num(0, ArraySize(a_Maps) - 1);
        ArrayGetString(a_Maps, i_Rand, s_MapsFound[i_Cnt], MAX_MAP_LENGTH - 1);

        if (equal(s_MapsFound[i_Cnt], s_CurrentMap))
        {
            continue;
        }

        for (= 0; i < i_Cnt; i++)
        {
            if (equal(s_MapsFound[i], s_MapsFound[i_Cnt]))
            {
                break;
            }
        }

        if (== i_Cnt)
        {
            ArrayDeleteItem(a_Maps, i_Rand);
            i_Cnt++;
        }
    }
    ArrayDestroy(a_Maps);
    return true;
}



Обычный массив
Код: Выделить всё
public NewRound()
{
    new 
mBoxes[BOX_LOADED_MAX]
    for (new 
0gTotalBox; ++i)    mBoxes[i] = i//наполнение mBoxes индексами
    
    
new rand
    
for (new steps 1steps <= SPAWN_BOX; ++steps)
    {
        
rand random_num(0gTotalBox steps)
        
gNum[steps 1] = mBoxes[rand]
        
//сдвиг внутри mBoxes[]
        
for (new pos randpos gTotalBox steps; ++pos)
            
mBoxes[pos] = mBoxes[pos 1]
        
spaw_lootbox(gNum[steps 1])
    }
}
 
Аватара пользователя
xbass13
 
Сообщения: 96
Зарегистрирован: 13 июн 2012, 21:20
Благодарил (а): 36 раз.
Поблагодарили: 35 раз.
Опыт программирования: Больше трех лет
Языки программирования: pawn, c++, js, php


Вернуться в Скриптинг

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot], Yandex [Bot] и гости: 3