Jump to content

Module:Random

Permanently protected module
From Wikipedia, the free encyclopedia

-- This module contains a number of functions that make use of random numbers.localcfg={}---------------------------------------------------------------------------------------- Configuration---------------------------------------------------------------------------------------- Set this to true if your wiki has a traffic rate of less than one edit every two minutes or so.-- This will prevent the same "random" number being generated many times in a row until a new edit is made-- to the wiki. This setting is only relevant if the |same= parameter is set.cfg.lowTraffic=false-- 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--------------------------------------------------------------------------------------localp={}-- For functions available from other Lua modules.locall={}-- For functions not available from other Lua modules, but that need to be accessed using table keys.localyesno=require('Module:Yesno')localmakeList=require('Module:List').makeList---------------------------------------------------------------------------------------- Helper functions--------------------------------------------------------------------------------------localfunctionraiseError(msg)-- This helps to generate a wikitext error. It is the calling function's responsibility as to how to include it in the output.returnmw.ustring.format('<b class="error">[[Module:Random]] error: %s.</b>',msg)end---------------------------------------------------------------------------------------- random number function--------------------------------------------------------------------------------------localfunctiongetBigRandom(l,u)-- Gets a random integer between l and u, and is not limited to RAND_MAX.localr=0localn=2^math.random(30)-- Any power of 2.locallimit=math.ceil(53/(math.log(n)/math.log(2)))fori=1,limitdor=r+math.random(0,n-1)/(n^i)endreturnmath.floor(r*(u-l+1))+lendfunctionl.number(args)-- Gets a random number.first=tonumber(args[1])second=tonumber(args[2])-- This needs to use if statements as math.random won't accept explicit nil values as arguments.iffirstthenifsecondtheniffirst>secondthen-- Second number cannot be less than the first, or it causes an error.first,second=second,firstendreturngetBigRandom(first,second)elsereturngetBigRandom(1,first)endelsereturnmath.random()endend---------------------------------------------------------------------------------------- Date function--------------------------------------------------------------------------------------functionl.date(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.-- With two arguments specified, it outputs a random date between the timestamps.-- With one argument specified, the date is a random date between the unix epoch (1 Jan 1970) and the timestamp.-- 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.locallang=mw.language.getContentLanguage()localfunctiongetDate(format,ts)localsuccess,date=pcall(lang.formatDate,lang,format,ts)ifsuccessthenreturndateendendlocalfunctiongetUnixTimestamp(ts)localunixts=getDate('U',ts)ifunixtsthenreturntonumber(unixts)endendlocalt1=args[1]localt2=args[2]-- Find the start timestamp and the end timestamp.localstartTimestamp,endTimestampifnott1then-- Find the first and last second in the current year.localcurrentYear=tonumber(getDate('Y'))localcurrentYearStartUnix=tonumber(getUnixTimestamp('1 Jan '..tostring(currentYear)))localcurrentYearEndUnix=tonumber(getUnixTimestamp('1 Jan '..tostring(currentYear+1)))-1startTimestamp='@'..tostring(currentYearStartUnix)-- @ is used to denote Unix timestamps with lang:formatDate.endTimestamp='@'..tostring(currentYearEndUnix)elseift1andnott2thenstartTimestamp='@0'-- the Unix epoch, 1 January 1970endTimestamp=t1elseift1andt2thenstartTimestamp=t1endTimestamp=t2end-- Get Unix timestamps and return errors for bad input (or for bugs in the underlying PHP library, of which there are unfortunately a few)localstartTimestampUnix=getUnixTimestamp(startTimestamp)localendTimestampUnix=getUnixTimestamp(endTimestamp)ifnotstartTimestampUnixthenreturnraiseError('"'..tostring(startTimestamp)..'" was not recognised as a valid timestamp')elseifnotendTimestampUnixthenreturnraiseError('"'..tostring(endTimestamp)..'" was not recognised as a valid timestamp')elseifstartTimestampUnix>endTimestampUnixthenreturnraiseError('the start date must not be later than the end date (start date: "'..startTimestamp..'", end date: "'..endTimestamp..'")')end-- Get a random number between the two Unix timestamps and return it using the specified format.localrandomTimestamp=getBigRandom(startTimestampUnix,endTimestampUnix)localdateFormat=args.formator'H:i, d F Y (T)'localresult=getDate(dateFormat,'@'..tostring(randomTimestamp))ifresultthenreturnresultelsereturnraiseError('"'..dateFormat..'" is not a valid date format')endend---------------------------------------------------------------------------------------- List functions--------------------------------------------------------------------------------------localfunctionrandomizeArray(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.-- The lowest possible value is 0, and the highest possible is the length of the array.locallen=#tfori=len,2,-1dolocalr=math.random(i)t[i],t[r]=t[r],t[i]endiflimitandlimit<lenthenlocalret={}fori,vinipairs(t)doifi>limitthenbreakendret[i]=vendreturnretelsereturntendendlocalfunctionremoveBlanks(t)-- Removes blank entries from an array so that it can be used with ipairs.localret={}fork,vinpairs(t)doiftype(k)=='number'thentable.insert(ret,k)endendtable.sort(ret)fori,vinipairs(ret)doret[i]=t[v]endreturnretendlocalfunctionmakeSeparator(sep)ifsep=='space'then-- Include an easy way to use spaces as separators.return' 'elseifsep=='newline'then-- Ditto for newlinesreturn'\n'elseiftype(sep)=='string'then-- If the separator is a recognised MediaWiki separator, use that. Otherwise use the value of sep if it is a string.localmwseparators={'dot','pipe','comma','tpt-languages'}for_,mwsepinipairs(mwseparators)doifsep==mwsepthenreturnmw.message.new(sep..'-separator'):plain()endendreturnsependendlocalfunctionmakeRandomList(args)locallist=removeBlanks(args)list=randomizeArray(list,tonumber(args.limit))returnlistendfunctionl.item(args)-- Returns a random item from a numbered list.locallist=removeBlanks(args)locallen=#listiflen>=1thenreturnlist[math.random(len)]endendfunctionl.list(args)-- Randomizes a list and concatenates the result with a separator.locallist=makeRandomList(args)localsep=makeSeparator(args.seporargs.separator)returntable.concat(list,sep)endfunctionl.text_list(args)-- Randomizes a list and concatenates the result, text-style. Accepts separator and conjunction arguments.locallist=makeRandomList(args)localsep=makeSeparator(args.seporargs.separator)localconj=makeSeparator(args.conjorargs.conjunction)returnmw.text.listToText(list,sep,conj)endfunctionl.array(args)-- Returns a Lua array, randomized. For use from other Lua modules.returnrandomizeArray(args.t,args.limit)end---------------------------------------------------------------------------------------- HTML list function--------------------------------------------------------------------------------------functionl.html_list(args,listType)-- Randomizes a list and turns it into an HTML list. Uses [[Module:List]].listType=listTypeor'bulleted'locallistArgs=makeRandomList(args)-- Arguments for [[Module:List]].fork,vinpairs(args)doiftype(k)=='string'thenlistArgs[k]=vendendreturnmakeList(listType,listArgs)end---------------------------------------------------------------------------------------- The main function. Called from other Lua modules.--------------------------------------------------------------------------------------functionp.main(funcName,args,listType)-- Sets the seed for the random number generator and passes control over to the other functions.localsame=yesno(args.same)ifnotsamethen-- 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))elseifnotcfg.lowTrafficthen-- 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.localstats=mw.site.statslocalviews=stats.viewsor0-- This is not always available, so we need a backup.localseed=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(seed)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))endendiftype(args)~='table'thenerror('the second argument to p.main must be a table')endreturnl[funcName](args,listType)end---------------------------------------------------------------------------------------- Process arguments from #invoke--------------------------------------------------------------------------------------localfunctionmakeWrapper(funcName,listType)-- This function provides a wrapper for argument-processing from #invoke.-- listType is only used with p.html_list, and is nil the rest of the time.returnfunction(frame)-- If called via #invoke, use the args passed into the invoking template, or the args passed to #invoke if any exist.-- Otherwise assume args are being passed directly in from the debug console or from another Lua module.localorigArgsifframe==mw.getCurrentFrame()thenorigArgs=frame:getParent().argsfork,vinpairs(frame.args)doorigArgs=frame.argsbreakendelseorigArgs=frameend-- Trim whitespace and remove blank arguments.localargs={}fork,vinpairs(origArgs)doiftype(v)=='string'thenv=mw.text.trim(v)endifv~=''thenargs[k]=vendendreturnp.main(funcName,args,listType)endend-- Process arguments for HTML list functions.localhtmlListFuncs={bulleted_list='bulleted',unbulleted_list='unbulleted',horizontal_list='horizontal',ordered_list='ordered',horizontal_ordered_list='horizontal_ordered'}forfuncName,listTypeinpairs(htmlListFuncs)dop[funcName]=makeWrapper('html_list',listType)end-- Process arguments for other functions.localotherFuncs={'number','date','item','list','text_list'}for_,funcNameinipairs(otherFuncs)dop[funcName]=makeWrapper(funcName)endreturnp
close