Module:Random: Difference between revisions

Content deleted Content added
add function to get random dates; and add support for random numbers over 2^32-1 (using an algorithm supplied by User:Anomie)
allow newline separators
 
(10 intermediate revisions by 2 users not shown)
Line 1:
-- This module contains a number of functions that make use of random numbers.
 
local pcfg = {}
 
--------------------------------------------------------------------------------------
local makeList = require('Module:List').makeList
-- Configuration
--------------------------------------------------------------------------------------
 
-- Set thethis seedto fortrue theif randomyour numberwiki tohas thea currenttraffic numberrate of editsless madethan toone edit every two minutes or Wikipediaso.
-- This will prevent the same "random" number being generated many times in a row until a new edit is made
-- The English Wikipedia gets dozens of edits each minute, so this is as close to a random seed
-- asto wethe havewiki. OnThis smallersetting wikisis thisonly willrelevant produceif the |same= numberparameter ifis the edit count has not changed,set.
cfg.lowTraffic = false
-- so please use it with caution.
 
math.randomseed(mw.site.stats.edits)
-- If cfg.lowTraffic is set to true, and the |same= parameter is set, this value is used for the refresh rate of the random seed.
-- This is the number of seconds until the seed is changed. Getting this right is tricky. If you set it too high, the same number
-- will be returned many times in a row. If you set it too low, you may get different random numbers appearing on the same page,
-- particularly for pages that take many seconds to process.
cfg.seedRefreshRate = 60
 
--------------------------------------------------------------------------------------
-- End configuration
-- Error helper function
--------------------------------------------------------------------------------------
 
local p = {} -- For functions available from other Lua modules.
local l = {} -- For functions not available from other Lua modules, but that need to be accessed using table keys.
 
local yesno = require('Module:Yesno')
local makeList = require('Module:List').makeList
 
--------------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------------
 
Line 24 ⟶ 41:
--------------------------------------------------------------------------------------
 
local function bigRandomgetBigRandom(l, u)
-- Gets a random integer between l and u, and is not limited to RAND_MAX (which here we assume is 2^31-1).
local r = 0
local r = math.random() + math.random() / 2147483648
local n = return 2^math.floorrandom(r * (u30) -- lAny +power 1))of + l2.
local rlimit = math.randomceil()53 +/ (math.randomlog(n) / 2147483648math.log(2)))
for i = #t1, 2, -1limit do
r = r + math.random(0, n - 1) / (n^i)
end
return math.floor(r * (u - l + 1)) + l
end
 
function pl._numbernumber(args)
-- ReturnsGets a random number.
first = tonumber(args[1])
second = tonumber(args[2])
Line 40 ⟶ 62:
first, second = second, first
end
return bigRandomgetBigRandom(first, second)
else
return bigRandomgetBigRandom(1, first)
end
else
Line 53 ⟶ 75:
--------------------------------------------------------------------------------------
 
function pl._datedate(args)
-- This function gets random dates, and takes timestamps as positional arguments.
-- With no arguments specified, it outputs a random date in the current year.
Line 60 ⟶ 82:
-- The output can be formatted using the "format" argument, which works in the same way as the #time parser function.
-- The default format is the standard Wikipedia timestamp.
local lang = mw.language.getContentLanguage()
 
Line 109 ⟶ 130:
 
-- Get a random number between the two Unix timestamps and return it using the specified format.
local randomTimestamp = bigRandomgetBigRandom(startTimestampUnix, endTimestampUnix)
local dateFormat = args.format or 'H:i, d F Y (T)'
local result = getDate(dateFormat, '@' .. tostring(randomTimestamp))
Line 123 ⟶ 144:
--------------------------------------------------------------------------------------
 
local function p.randomizeArray(t, limit)
-- Randomizes an array. It works by iterating through the list backwards, each time swapping the entry
-- "i" with a random entry. Courtesy of Xinhuan at http://forums.wowace.com/showthread.php?p=279756
-- If the limit parameter is set, the array is shortened to that many elements after being randomized.
for i = #t, 2, -1 do
-- The lowest possible value is 0, and the highest possible is the length of the array.
local len = #t
for i = len, 2, -1 do
local r = math.random(i)
t[i], t[r] = t[r], t[i]
end
if limit and limit < len then
return t
local ret = {}
for i, v in ipairs(t) do
if i > limit then
break
end
ret[i] = v
end
return ret
else
return t
end
end
 
Line 137 ⟶ 172:
local ret = {}
for k, v in pairs(t) do
if type(k) == 'number' then -- Make sure we have no non-string portal names.
table.insert(ret, k)
end
Line 152 ⟶ 187:
-- Include an easy way to use spaces as separators.
return ' '
elseif sep == 'newline' then
-- Ditto for newlines
return '\n'
elseif type(sep) == 'string' then
-- If the separator is a recognised MediaWiki separator, use that. Otherwise use the value of sep if it is a string.
Line 166 ⟶ 204:
local function makeRandomList(args)
local list = removeBlanks(args)
list = p.randomizeArray(list, tonumber(args.limit))
return list
end
 
function pl._itemitem(args)
-- Returns a random item from a numbered list.
local list = removeBlanks(args)
iflocal #listlen >= 1 then#list
if len >= 1 then
return list[math.random(#listlen)]
end
end
 
function pl._listlist(args)
-- Randomizes a list and concatenates the result with a separator.
local list = makeRandomList(args)
Line 185 ⟶ 224:
end
 
function pl._text_listtext_list(args)
-- Randomizes a list and concatenates the result, text-style. Accepts separator and conjunction arguments.
local list = makeRandomList(args)
Line 191 ⟶ 230:
local conj = makeSeparator(args.conj or args.conjunction)
return mw.text.listToText(list, sep, conj)
end
 
function l.array(args)
-- Returns a Lua array, randomized. For use from other Lua modules.
return randomizeArray(args.t, args.limit)
end
 
Line 197 ⟶ 241:
--------------------------------------------------------------------------------------
 
function pl.html_list(args, listType)
-- Randomizes a list and turns it into an HTML list. Uses [[Module:List]].
listType = listType or 'bulleted'
Line 209 ⟶ 253:
end
 
--------------------------------------------------------------------------------------
-- The main function. Called from other Lua modules.
--------------------------------------------------------------------------------------
 
function p.main(funcName, args, listType)
-- Sets the seed for the random number generator and passes control over to the other functions.
local same = yesno(args.same)
if not same then
-- Generates a different number every time the module is called, even from the same page.
-- This is because of the variability of os.clock (the time in seconds that the Lua script has been running for).
math.randomseed(mw.site.stats.edits + mw.site.stats.pages + os.time() + math.floor(os.clock() * 1000000000))
else
if not cfg.lowTraffic then
-- Make the seed as random as possible without using anything time-based. This means that the same random number
-- will be generated for the same input from the same page - necessary behaviour for some wikicode templates that
-- assume bad pseudo-random-number generation.
local stats = mw.site.stats
local views = stats.views or 0 -- This is not always available, so we need a backup.
local seed = views + stats.pages + stats.articles + stats.files + stats.edits + stats.users + stats.activeUsers + stats.admins -- Make this as random as possible without using os.time() or os.clock()
math.randomseed(mw.site.stats.editsseed)
else
-- Make the random seed change every n seconds, where n is set by cfg.seedRefreshRate.
-- This is useful for low-traffic wikis where new edits may not happen very often.
math.randomseed(math.floor(os.time() / cfg.seedRefreshRate))
end
end
if type(args) ~= 'table' then
error('the second argument to p.main must be a table')
end
return l[funcName](args, listType)
end
--------------------------------------------------------------------------------------
-- Process arguments from #invoke
Line 239 ⟶ 315:
end
end
return p[funcName].main(funcName, args, listType)
end
end
Line 258 ⟶ 334:
local otherFuncs = {'number', 'date', 'item', 'list', 'text_list'}
for _, funcName in ipairs(otherFuncs) do
p[funcName] = makeWrapper('_' .. funcName)
end