Генератор случайных чисел без повторений

Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Алгоритм
Инициализация:
Задать private constant integer RandMemMax на нужное количество запоминаемых чисел. Максимум: 8191
Использование:
Функция GetRandomIntMem принимает 2 integer: нижняя граница и верхняя граница, включительно. Возвращает случайный integer (между ними). Сгенерированные ранее числа хранятся в массиве размером RandMemMax, при переполнении массив полностью обнуляется. Поэтому следует задавать его с оценкой обращений.
Функция ClearRandomIntMem ничего не принимает и не возвращает. Используется для обнуления массива запомненных чисел после сессии обращений.
library RandomIntGenMem

globals
    public integer RandMemMax = 8100
    private integer array RandMem
    private integer RandMemSize = 0
endglobals

private function CheckRandMem takes integer value returns boolean
    local integer i = 0
    loop
        exitwhen i >= RandMemSize
        if value == RandMem[i] then
            return false
        endif
        set i=i+1
    endloop
    return true
endfunction

private function SaveRandMem takes integer value returns boolean
    if RandMemSize > RandMemMax then
        return false
    endif
    set RandMem[RandMemSize] = value
    set RandMemSize=RandMemSize+1
    return true
endfunction

function ClearRandomIntMem takes nothing returns nothing
    set RandMemSize = 0
endfunction

function GetRandomIntMem takes integer lowBound, integer highBound returns integer
    local integer r
    local integer simple = 0
    if highBound<=lowBound or (highBound-lowBound) > RandMemMax then
        return highBound
    endif
    set simple = GetRandomInt(lowBound,highBound)
    set r = simple
    // BJDebugMsg("GetRandomIntMem: l="+I2S(lowBound)+",h="+I2S(highBound)+",si="+I2S(simple))
    loop
        exitwhen CheckRandMem(r)
        if r<highBound and r>=simple then
            set r=r+1   // BJDebugMsg("GetRandomIntMem: r=r+1 ("+I2S(r)+")")
        elseif r==highBound and simple>lowBound then
            set r=simple-1   // BJDebugMsg("GetRandomIntMem: r=simple-1 ("+I2S(r)+")")
        elseif r>lowBound and r<simple then
            set r=r-1   // BJDebugMsg("GetRandomIntMem: r=r-1 ("+I2S(r)+")")
        elseif r<=lowBound then
            set r=lowBound   // BJDebugMsg("GetRandomIntMem: r<=lowBound; exit ("+I2S(r)+")")
            exitwhen true
        endif
    endloop   // BJDebugMsg("GetRandomIntMem: exit")
    
    if SaveRandMem(r) then
        return r
    else
        call ClearRandomIntMem()
        call SaveRandMem(r)
        return r
    endif
endfunction

endlibrary

Простой пример

call BJDebugMsg(I2S( GetRandomIntMem(1,3) )) // 3
call BJDebugMsg(I2S( GetRandomIntMem(1,3) )) // 2
call BJDebugMsg(I2S( GetRandomIntMem(1,3) )) // 1
call BJDebugMsg(I2S( GetRandomIntMem(1,3) )) // 2, память была сброшена
call ClearRandomIntMem()
1
37
12 лет назад
Отредактирован ScorpioT1000
1
Пример использования. Мы имеем:
  • массив типов героев heroSelectorHeroTypes, их может быть много, больше чем самих игроков;
  • число элементов этого массива - heroSelectorHeroTypesCount;
  • массив выбранных типов для игроков playersHeroChoise с нулевыми значениями, если герой не был выбран;
  • переменная playersCount, означает общее число игроков.
Задача: выбрать случайные типы героев, без повторений, и задать их в playersHeroChoise только тем игрокам, у которых они еще не были выбраны.
Реализуется функцией heroSelectorChooseRandom.
// Дано
integer array heroSelectorHeroTypes // например: 'A000', 'A001', 'A002' итп.
integer heroSelectorHeroTypesCount // например: 32
integer array playersHeroChoise // например: 0, 0, 0, 'A000'
integer playersCount // например: 4
// Решение
function heroSelectorChooseRandom takes nothing returns nothing
    local integer i = 0
	call ClearRandomIntMem() // сбрасываем счетчик
	loop
	    exitwhen i >= playersCount // для каждого игрока
		if playersHeroChoise[i] == 0 then // Только если не был выбран
			// выбираем случайного от 0 до максимума возможных из нашего массива всевозможных героев
			// и задаем его в "выбор игрока"
			set playersHeroChoise[i] = heroSelectorHeroTypes[GetRandomIntMem(0, heroSelectorHeroTypesCount-1)] 
		endif
		set i = i + 1
	endloop
endfunction
В результате в массиве playersHeroChoise будут примерно такие значения:
'A006', 'A013', 'A00C', 'A000'
0
11
12 лет назад
0
Объясните непосвященному: дополнительных изменений система не требует?
0
19
12 лет назад
0
Чем это лучше расчётов Pool от Diod? Ничем я думаю, ведь у DioD, можно настраивать даже весомость выдаваемого значения (аля шанс)
8
37
11 лет назад
8
Код обновлён, добавлена карта-пример.
добавлена карта-пример
я сказал, добавлена =( хеллкор, иди вилкой фикси.
0
24
11 лет назад
0
Что это еще за костыль для проверки занятых значений? Выдели под систему отдельную хт, в нее кидай значения и спрашивай на прямую, было ли заюзано такое значение ._.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.