모듈:Random

리버티게임, 모두가 만들어가는 자유로운 게임
BANIP (토론 | 기여)님의 2023년 7월 26일 (수) 13:19 판 (uncached 의존성 해제)


모듈 설명문서[보기] [편집] [역사] [새로 고침]

난수를 다루는 lua함수를 모아둔 모듈입니다.

리버티위키를 비롯한 미디어위키 사이트는 구문분석기 캐싱이 허용되어 있기에 별도의 설정을 거치지 않으면 아무리 새로고침을 해도 같은값이 나오게끔 되어있습니다.

해당 모듈을 래핑하는 틀을 만들거나 {{#invoke:random}}를 사용하는 문서에 {{캐싱방지}}를 추가해주세요.

rand

이 부분의 본문은 틀:rand입니다.

choose

이 부분의 본문은 틀:choose입니다.

lotto

{{#invoke:random|lotto|a|b}}일 때, 1부터 b까지의 자연수 중 a개를 중복 없이 추출합니다.

사용법

파라미터별 설명

{{#invoke:random|lotto|추출할 표본수|전체갯수|추출할 보너스 갯수|표본 구분자|보너스 구분자|정렬 여부}}

파라미터 기본값

{{#invoke:random|lotto|6|45|1|, | + |true}}

예시

기본 예시

code_blocks 코드
{{#invoke:random|lotto}}
code
낙서장에서 확인
description 결과
2, 4, 11, 17, 37, 42 + 15

보너스를 추출하지 않는 예시

code_blocks 코드
{{#invoke:random|lotto|||0}}
code
낙서장에서 확인
description 결과
2, 4, 11, 17, 37, 42

0부터 10까지 숫자를 랜덤나열한 예시

code_blocks 코드
{{#invoke:random|lotto|10|10|0|-||false}}
code
낙서장에서 확인
description 결과
10-5-4-9-7-2-6-1-3-8

sample

가중치를 설정할 수 없고 문자열로 구분 가능한 choose입니다.

사용법

파라미터별 설명

{{#invoke:random|sample|텍스트|구분할 문자열}}

파라미터 기본값

{{#invoke:random|sample||,}}


예시

기본 예시

code_blocks 코드
{{#invoke:random|sample|1,2,3,4,5}}
code
낙서장에서 확인
description 결과
스크립트 오류: 함수 "sample"가 존재하지 않습니다.

구분자를 변경하는 예시

code_blocks 코드
{{#invoke:random|sample|1-2-3-4-5|-}}
code
낙서장에서 확인
description 결과
스크립트 오류: 함수 "sample"가 존재하지 않습니다.

특정 분류의 랜덤 게임을 출력하는 예시

code_blocks 코드
{{#invoke:random|sample|{{#dpl:|category=함정 피하기 게임|namespace|format=,%PAGE%//}}|//}}
code
낙서장에서 확인
description 결과
스크립트 오류: 함수 "sample"가 존재하지 않습니다.


local p = {}

function p._rand(m, n, o)
	local seed, key
	
	if type(m) == "table" then
		seed = tonumber(m.seed)
		key = tonumber(m.key)
		m = nil
		n = nil
	elseif type(n) == "table" then
		seed = tonumber(n.seed)
		key = tonumber(n.key)
		m = tonumber(m)
		n = nil
	elseif type(o) == "table" then
		seed = tonumber(o.seed)
		key = tonumber(o.key)
		m = tonumber(m)
		n = tonumber(n)
	else
		m = tonumber(m)
		n = tonumber(n)
	end

    -- seed가 0이면 현재 시간을 seed로 사용
	if (seed or 0) == 0 then
		seed = os.time()
	elseif (key or 0) ~= 0 then
		seed = seed * key
	end
	
	math.randomseed(seed)
	
	if n ~= nil then
		return math.random(m, n)
	elseif m ~= nil then
		return math.random(m)
	else
		return math.random()
	end
end

function p.rand(frame)
	return p._rand(frame.args[1], frame.args[2], frame.args)
end

function p._choose(frame)
	local len = 0
	
	for index, value in ipairs(frame.args) do
		len = index
	end
	
	return frame.args[p._rand(len, frame.args)]
end

function p.choose(frame)
	return p._choose(frame:getParent())
end

-- 테이블을 문자열로 변환
function p.str_join(list, delimiter)
    local len = #list
    if len == 0 then
        return ""
    end
    local string = list[1]
    for i = 2, len do
        string = string .. delimiter .. list[i]
    end
    return string
end

-- 테이블의 일부를 추출
function p.table_slice(arr,start,stop)
    local res = {}
    local n = #arr

    start = start or 1
    stop = stop or n

    -- 음수
    if start < 0 then
        start = n + start + 1
    end
    if stop < 0 then
        stop = n + stop + 1
    end

    -- start보다 stop이 큰 경우
    if stop < start then
        stop = start
    end

    -- 루프
    for i = start, stop, 1 do
        res[#res+1] = arr[i]
    end

    return res

end


-- n개의 숫자를 무작위로 뽑아서 반환
function p._sampling(n, total)
    local numbers = {}
    for i = 1, total do
        numbers[i] = i
    end

    -- 숫자를 무작위로 섞기
    math.randomseed(os.time())
    for i = total, 1, -1 do
        local r = math.random(i)
        numbers[i], numbers[r] = numbers[r], numbers[i]
    end

    -- 처음 n개 숫자 선택
    local sampled = {}
    for i = 1, n do
        table.insert(sampled, numbers[i])
    end

    return sampled
end

-- {{#invoke:random|lotto}}
function p.lotto(frame)
    local n = tonumber(frame.args[1]) or 6
    local total = tonumber(frame.args[2]) or 45
    local bonus = tonumber(frame.args[3]) or 1
    local sep = frame.args[4] or ", "
    local bonusSep = frame.args[5] or " + "
    local sort = frame.args[6] or "true"

    if n and total and n <= total and n > 0 then
        local allNums = p._sampling(n + bonus, total)
        -- 추출한 숫자들 중 n개 추출 및 정렬
        local nums = p.table_slice(allNums, 1, n)
        if sort == "true" then
            table.sort(nums)
        end

        -- bonus만큼 추출
        local bonusNums = p.table_slice(allNums, n + 1, n + bonus)
        if sort == "true" then
            table.sort(bonusNums)
        end

        -- 문자열로 변환
        local result = p.str_join(nums, sep)
        -- 보너스 번호가 있으면 추가
        if bonus > 0 then
            result = result .. bonusSep .. p.str_join(bonusNums, sep)
        end

        return result
    else
        return "{{색깔|Error: 파라미터가 올바르지 않습니다. 1 <= n <= total를 만족해야 합니다.|red}}"
    end
end

return p