XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
DioD

offline
Опыт: 45,134
Активность:
Pool (no vJass no cJass no ZINC)
Обкаточная версия.

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

Пока что все значения хардкодед, 64 пула по 127 значений в каждом + 62 слота под метаданные, (два заняты изначально) выделение и сохранение метаданных не очень то и контролируется, так что туда можно писать что угодно в каком угодно порядке и система эти метаданные трогать не будет.

В ближайшее время планируется включить метаданные в общую обработку (увеличив размер пула до 187 чисел), подтянуть автоматическую (и не очень) склейку пулов в более большие.

Код:
library Pool

globals
    hashtable     HASH = InitHashtable()
    integer array VALUES
    real    array WEIGHT_META
    integer array META
endglobals

function POOL_NEW takes nothing returns integer
    local integer I = META[0]
    
    if I > 0 then
        set META[0] = META[META[0]]
    else
        if I == -64 then
            return F_NULL
        endif
        set META[0] = META[0] - 1
        set I = -META[0]
    endif
    
    set META[I] = -1
    return I
endfunction

function POOL_REM takes integer I returns nothing
    if META[I] != -1 then
        return
    endif
    set META[I] = META[0]
    set META[0] = I
    set META[127*I - 63 + 1] = 0
    set META[127*I - 63 + 2] = 0
endfunction

function POOL_ADD_INT takes integer POOL, integer VALUE, real WEIGHT returns nothing
    local integer TMP
    
    if META[POOL] != -1 or META[127*POOL -63 +1] == 127 then
        return
    endif
    
    set TMP = LoadInteger(HASH, POOL, VALUE)
    if TMP == 0 then
        set META[127*POOL -63 +1] = META[127*POOL -63 +1] +1
        set TMP    = 128*(POOL-1) + META[127*POOL -63 +1]
        call SaveInteger(HASH, POOL, VALUE, TMP)
        set VALUES[TMP] = VALUE
    endif
    if WEIGHT <= 0.0 then
        set META[127*POOL -63 +2] = 1
        return
    endif
    set WEIGHT_META[128*(POOL-1)] = WEIGHT_META[128*(POOL-1)] +WEIGHT -WEIGHT_META[TMP]
    set WEIGHT_META[TMP] = WEIGHT    
    
endfunction

function POOL_REM_INT takes integer POOL, integer VALUE returns nothing
    
    local integer I = LoadInteger(HASH, POOL, VALUE)
    
    if I == 0 then
        return
    endif
    
    call RemoveSavedInteger(HASH, POOL, VALUE)    
    set WEIGHT_META[128*(POOL-1)] = WEIGHT_META[128*(POOL-1)] -WEIGHT_META[I]
    
    set VALUES[I]                 =      VALUES[128*(POOL-1) +META[127*POOL -63 +1]]
    set WEIGHT_META[I]            = WEIGHT_META[128*(POOL-1) +META[127*POOL -63 +1]]
    
    call SaveInteger(HASH,POOL,VALUES[I],I)
    set META[127*POOL -63 +1] = META[127*POOL -63 +1] - 1
    
endfunction

function POOL_REM_LST takes integer POOL returns integer
    
    if META[127*POOL -63 +1] == 0 then
        return F_NULL
    endif
        
    call RemoveSavedInteger(HASH, POOL, VALUES[META[127*POOL -63 +1] +128*(POOL-1)])
    
    set WEIGHT_META[128*(POOL-1)] = WEIGHT_META[128*(POOL-1)] -WEIGHT_META[META[127*POOL -63 +1] +128*(POOL-1)]
    set META[127*POOL -63 +1] = META[127*POOL -63 +1] - 1
    
    return VALUES[META[127*POOL -63 +1] + 128*(POOL-1) + 1]
        
endfunction 

function POOL_RND_INT takes integer POOL returns integer
    local real    RANDOM = 0
    local integer OFFSET = 128*(POOL-1)
    
    if META[127*POOL -63 +1] == 0 then
        return F_NULL
    endif
    
    if META[127*POOL - 63 + 2] != 0 then
        set OFFSET = GetRandomInt(1,META[127*POOL -63 +1]) + OFFSET
        return VALUES[OFFSET]
    else
        set RANDOM = GetRandomReal(0,WEIGHT_META[OFFSET])
        loop
            set OFFSET = OFFSET + 1
            set RANDOM = RANDOM - WEIGHT_META[OFFSET]
            exitwhen RANDOM <= 0
        endloop
        
        return VALUES[OFFSET]
    endif
    
endfunction

function POOL_COPY takes integer POOL returns integer
    local integer A = POOL_NEW()
    local integer B = META[127*POOL - 63 + 1]
    
    if META[POOL] != -1 or A == F_NULL then
        return F_NULL
    endif
    
    set META[127*A - 63 + 2]   = META[127*POOL - 63 + 2]
    set WEIGHT_META[128*(A-1)] = WEIGHT_META[128*(POOL-1)]
    set META[127*A - 63 + 1]   = META[127*POOL - 63 + 1]
    
    loop
        set VALUES     [128*(A-1) + B] = VALUES     [128*(POOL-1) + B]
        set WEIGHT_META[128*(A-1) + B] = WEIGHT_META[128*(POOL-1) + B]
        call SaveInteger(HASH, A, VALUES[128*(POOL-1) + B], 128*(A-1) + B)
        set B = B - 1
        exitwhen B == 0
    endloop
    
    return A
    
endfunction

function VALUE_WEIGHT takes integer POOL, integer VALUE returns real
    return WEIGHT_META[LoadInteger(HASH, POOL, VALUE)]
endfunction

function VALUE_CHANCE takes integer POOL, integer VALUE returns real
    if WEIGHT_META[128*(POOL-1)] > 0. then
        return WEIGHT_META[LoadInteger(HASH, POOL, VALUE)]/WEIGHT_META[128*(POOL-1)]
    endif
    return 0.
endfunction

endlibrary


Ну и собственно пример использования и применения.


Код:
local integer A = POOL_NEW()
    local integer B = 0
    local integer C = 0
    
    call POOL_ADD_INT(A,'Hpal',10 )
    call POOL_ADD_INT(A,'Hamg',10 )
    call POOL_ADD_INT(A,'Hmkg',10 )
    call POOL_ADD_INT(A,'Hblm',0.1)
    
    set B = POOL_COPY(A)
    
    loop
        set C = POOL_RND_INT(A)
        call POOL_REM_INT(A,C)
        call CreateUnit(Player(0),C,0.0,0.0,270.0)
        exitwhen C == F_NULL
    endloop
    
    loop
        set C = POOL_RND_INT(B)
        call POOL_REM_INT(B,C)
        call CreateUnit(Player(0),C,0.0,0.0,270.0)
        exitwhen C == F_NULL
    endloop



При выполнении этого кода будет создано 4 героя из набора при этом ни один герой не повториться.

Блудмаг будет появляться самым последним, так как шанс его выпадение в 100 раз меньше чем у остальных героев, первые три героя появляются с равной вероятностью.
Старый 22.01.2010, 07:03
Doc

offline
Опыт: 63,163
Активность:
Распиши пожалуйста все команды нужные для пользования, а то я по твоему примеру не все понял
DoctorGester добавил:
А хотя все понял, не понял только предназначение F_NULL
Старый 22.01.2010, 09:24
DioD

offline
Опыт: 45,134
Активность:
F_NULL это переменная содержащая число 0x27BC86AA которое указывает на то вызов провалился.
вторую версию опубликую с комментариями.
Старый 24.01.2010, 10:41
FunkieFoO

offline
Опыт: 7,159
Активность:
давно пора создать раздел под фишечки бай Диод...
а где это можно применить?
типо при раздаче "правильных" рандомов али какЪ?
Старый 24.01.2010, 11:22
DioD

offline
Опыт: 45,134
Активность:
да где угодно это можно применить, это тут 64 пула по 128, если подключить 10 массивов то будет 320 пулов (что больше чем много) по 256 чего за глаза хватит на любые задачи, вплоть до выдаче пасивок с мультиэффектом.
Старый 24.01.2010, 11:49
Doc

offline
Опыт: 63,163
Активность:
То что есть шанс выпадения это классно. Наверно даже использую систему в своей карте.
Старый 24.01.2010, 18:29
DioD

offline
Опыт: 45,134
Активность:
не советую так как система будет переписана чуть больше чем полностью очень скоро.
Старый 24.01.2010, 19:23
Rewenger
The culprit will not die
offline
Опыт: 35,873
Активность:
Да, версия с комментариями была бы очень кстати. Теоретически полезная штука, но разбираться без пояснений - не самое приятное занятие.

Отредактировано Rewenger, 24.01.2010 в 21:13.
Старый 24.01.2010, 21:08
iZucken
ШТО
offline
Опыт: 17,960
Активность:
Ммм, т.е. это все по сути просто рандомно размешивает данные?
Старый 24.01.2010, 21:47
Doc

offline
Опыт: 63,163
Активность:
DioD, ок, ждемс новой версии
Q_w_e_r_t_y, по сути это размешивает те данные, которые ты хочешь, с шансом выпадения, и без выпадения одинаковых данных
Старый 24.01.2010, 22:32
iZucken
ШТО
offline
Опыт: 17,960
Активность:
DoctorGester, ну да, я так это и мел ввиду ^^
Старый 25.01.2010, 05:27
DioD

offline
Опыт: 45,134
Активность:
ожидайте всё будет.
Старый 25.01.2010, 08:03
ManWhoKnows
just another wc3 modmaker
offline
Опыт: 915
Активность:
Уважаемый DioD!! объясни мне пожалуйста что нужно для того чтоб подключить это в свою карту, плюс, как воспользоваться этим )) , чтоб получать рандомное число от 1до100 и чтоб у каждого числа были равные шансы выпасть.
да, и насколько быстро это будет работать??

Отредактировано ManWhoKnows, 07.02.2010 в 04:35.
Старый 07.02.2010, 04:30
DioD

offline
Опыт: 45,134
Активность:
Для подключения достаточно скопировать данный код в любой триггер, для этого само собой требуется НьюГен редактор.
    call POOL_ADD_INT(A,1,1 )
    call POOL_ADD_INT(A,2,2 )
    call POOL_ADD_INT(A,3,3 )
    call POOL_ADD_INT(A,4,4 )
можно присваивать циклом, максимальный размер пула в этой версии 127.
Старый 07.02.2010, 10:55
ManWhoKnows
just another wc3 modmaker
offline
Опыт: 915
Активность:
окей, а потом вызываем set СЛУЧАЙНОЕ_ЧИСЛО = POOL_RND_INT(A) так?
да, и насколько быстро это будет работать? (на каждое получение урона мне необходимо рандомное число, число воинствующих юнитов у меня на карте примерно в 1,5-2 раза больше чем максимальное кол-во оных в стандартной игре.)
Старый 07.02.2010, 13:28
DioD

offline
Опыт: 45,134
Активность:
посчитай сам насколько это быстро у тебя перед глазами сорц.
Старый 07.02.2010, 13:30
ManWhoKnows
just another wc3 modmaker
offline
Опыт: 915
Активность:
а создателю кода не проще это сказать а если я тупой нуб, никак вот не могу разобрать кода? (честно, я не понимаю что значит " != " ). в общем я думаю что POOL_RND_INT() немного медленней чем просто стандартный гетрандом, но в функции есть цикл, а это меня загоняет в тупик(насколько он может замедлить выполнение). Я привёл ситуацию в которой описано с какой частотой мне нужно вызывать POOL_RND_INT() , не проще ли автору сего произведения дать ответ
Старый 07.02.2010, 22:34
DioD

offline
Опыт: 45,134
Активность:
не стоит думать о скорости, особенно когда не понимаешь что да как.
этот алгоритм предельно быстрый, быстрее на джаз не сделать.
Старый 07.02.2010, 22:43
Windrunner
Верь мне!
offline
Опыт: 4,565
Активность:
Я щас проверил с тем что дано в примере с помощью тупого вывода числа.Выдает 1 и те же числа.
Или мб я в чем-то ошибся но выдает все же=)
Тут стоят нули так как f_NULL не хотел мой редактор воспринимать
local integer A = POOL_NEW()
local integer B = 0
local integer C = 0

call POOL_ADD_INT(A,'Hpal',10 )
call POOL_ADD_INT(A,'Hamg',10 )
call POOL_ADD_INT(A,'Hmkg',10 )
call POOL_ADD_INT(A,'Hblm',0.1)

set B = POOL_COPY(A)

loop
set C = POOL_RND_INT(A)
call POOL_REM_INT(A,C)
BJDebugMsg(I2S(C))
exitwhen C == 0
endloop

loop
set C = POOL_RND_INT(B)
call POOL_REM_INT(B,C)
BJDebugMsg(I2S(C))
exitwhen C == 0
endloop
Старый 15.03.2010, 07:45
YellowStar
poon
offline
Опыт: 15,144
Активность:
а ты сделаи значения рандома в редакторе не жесткими и не парься.
Старый 15.03.2010, 12:30
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 06:00.