置顶公告:【置顶】关于临时开启评论区所有功能的公告(2022.10.22) | 【置顶】关于本站Widget恢复使用的公告
  • 你好~!欢迎来到萌娘百科镜像站!如需查看或编辑,请联系本站管理员注册账号。
  • 本镜像站和其他萌娘百科的镜像站无关,请注意分别。

Module:Sandbox/Amahikari Hakuryuu/Random

猛汉♂百科,万男皆可猛的百科全书!转载请标注来源页面的网页链接,并声明引自猛汉百科。内容不可商用。
跳到导航 跳到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

这个模块包含了可以使用随机数的函数。它能输出随机数,从列表中随机选择一个项目,对列表随机重新排序。随机重新排序列表可以有序输出,也可以用来输出各种有徐和无序列表。可用函数参见下文。

Number

number函數能夠產生随机数.

{{#invoke:Sandbox/Amahikari Hakuryuu/Random|number|m|n|same=yes}}

The arguments m and n may be omitted, but if specified must be convertible to integers.

  • With no arguments, returns a real number in the range <math>[0,1)</math>.
  • With one argument, returns an integer in the range <math>[1,m]</math>. m must be positive.
  • With two arguments, returns an integer in the range <math>[m,n]</math>. m and n can be either positive or negative. If m is greater than n, returns an integer in the range <math>[n,m]</math> instead.
  • If the |same= parameter is set to "yes", "y", "true", or "1", the same random number is returned for each module call on a given page.

本模組所採用的機率分布均勻分佈(有給參數的則是離散型均勻分佈,未給參數的則是連續型均勻分布)。

注意:使用Module:Random的函數所產生的隨機數不夠隨機

Examples (refresh)

  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|number}} → 0.40126456013008
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|100}} → 80
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|-100|-50}} → -93
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|100|same=yes}} → 75
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|number|100|same=yes}} → 75

The documentation for this function is partly taken from the Scribunto Lua reference manual, which is in turn based on the Lua 5.1 Reference Manual, available under the MIT License.

Date

date函数可以输出随机文档。

{{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|timestamp1|timestamp2|format=date format|same=yes}}
  • If no timestamp arguments are specified, the module outputs a random date in the current year.
  • If timestamp1 and timestamp2 are specified, the module outputs a random date between the two timestamps. timestamp1 must be earlier than timestamp2.
  • If only timestamp1is specified, the module outputs a random date between the Unix epoch (1 Jan 1970) and the timestamp. timestamp1 must not be earlier than 1 Jan 1970.
  • Formatting can be specified with the |format= parameter. The default formatting is "hh:mm, DD Month YYYY (UTC)" (the same as the default Wikipedia timestamp).
  • The timestamps and the |format= parameter accept values compatible with the #time parser function. Please see the #time documentation for the full range of possible input values and formatting options.
  • If the |same= parameter is set to "yes", "y", "true", or "1", the same date is returned for each module call on a given page.

Examples (refresh)

  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date}} → 22:51, 27 3月 2024 (UTC)
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|format=F j}} → 3月 16
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|1 Jan 1980|31 Dec 1999}} → 06:29, 17 1月 1985 (UTC)
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|1st January 1500|1st January 3000|format=g:i a, l d M Y}} → 8:10 am, 星期六 07 8月 1920
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|1970/06/01}} → 03:23, 10 2月 1970 (UTC)
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|same=yes}} → 07:56, 01 10月 2024 (UTC)
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|date|same=yes}} → 07:56, 01 10月 2024 (UTC)

Item

item可以输出随机的物品列表

{{#invoke:Sandbox/Amahikari Hakuryuu/Random|item|list item 1|list item 2|list item 3|...|same=yes}}

If the |same= parameter is set to "yes", "y", "true", or "1", the same item is returned for each module call on a given page.

Example (refresh)

  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|item|egg|beans|sausage|bacon|spam}} → bacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|item|egg|beans|sausage|bacon|spam|same=yes}} → bacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|item|egg|beans|sausage|bacon|spam|same=yes}} → bacon

List

list可以随机输出一个物品列表。

{{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|list item 1|list item 2|list item 3|...|sep=separator|limit=number of items to display|same=yes}}

Named parameters

  • |sep= or |separator= - an optional separator for the list items. Some values are special; see the table below.
  • |limit= - the maximum number of list items to display. The lowest possible is 0 and the highest possible is the length of the list.
  • |same= - if this is set to "yes", "y", "true", or "1", the list order is the same for each module call on a given page.
Possible separator values
Code Output
dot ⧼dot-separator⧽
pipe |
comma 、​
tpt-languages ⧼tpt-languages-separator⧽
space a space
any other value other values are used without modification

You cannot input spaces directly to the |sep= parameter due to limitations in MediaWiki's template syntax. However, it is possible to work around this by using HTML entities. You can use &#32; to represent a normal space, and &nbsp; to represent a non-breaking space.

Examples (refresh)

  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam}} → sausagespameggbaconbeans
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|sep=dot}} → egg⧼dot-separator⧽spam⧼dot-separator⧽beans⧼dot-separator⧽sausage⧼dot-separator⧽bacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|sep=space}} → spam beans egg sausage bacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|sep=;&#32;}} → sausage; bacon; spam; egg; beans
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|sep=foo}} → sausagefoobaconfoobeansfoospamfooegg
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|limit=3}} → eggspambacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|same=yes}} → eggspambeanssausagebacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|list|egg|beans|sausage|bacon|spam|same=yes}} → eggspambeanssausagebacon

Text list

The text_list function outputs a list in a random order, text-style. In other words, it is like the list function, but with a different separator before the last item.

{{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|list item 1|list item 2|list item 3|...|sep=separator|conj=conjunction|limit=number of items to display|same=yes}}

The separator can be specified with either the |sep= or |separator= parameters; its default value is "、​". The conjunction can be specified with either the |conj= or |conjunction= parameters; its default value is " and ". The separator and the conjunction can be specified with the same values as the separator in the list function.

The maximum number of list items to display can be set with the |limit= parameter. The lowest possible is 0 and the highest possible is the length of the list.

If the |same= parameter is set to "yes", "y", "true", or "1", the list order is the same for each module call on a given page.

Examples (refresh)

  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|egg|beans|sausage|bacon|spam}} → spam、​egg、​sausage、​bacon和beans
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|egg|beans|sausage|bacon|spam|sep=;&#32;}} → bacon; sausage; egg; spam和beans
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|egg|beans|sausage|bacon|spam|sep=;&#32;|conj=&#32;or&#32;}} → beans; bacon; spam; sausage or egg
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|egg|beans|sausage|bacon|spam|limit=3}} → sausage、​bacon和egg
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|egg|beans|sausage|bacon|spam|same=yes}} → egg、​spam、​beans、​sausage和bacon
  • {{#invoke:Sandbox/Amahikari Hakuryuu/Random|text_list|egg|beans|sausage|bacon|spam|same=yes}} → egg、​spam、​beans、​sausage和bacon

HTML lists

If you wish to output an HTML list in a random order, you can choose between five different functions: bulleted_list, unbulleted_list, horizontal_list, ordered_list, and horizontal_ordered_list. These functions all use Module:List.

Function name Produces Example code Example output (refresh)
bulleted_list Bulleted lists {{#invoke:Sandbox/Amahikari Hakuryuu/Random|bulleted_list|egg|sausage|spam}}
  • spam
  • sausage
  • egg
unbulleted_list Unbulleted lists {{#invoke:Sandbox/Amahikari Hakuryuu/Random|unbulleted_list|egg|sausage|spam}}
  • egg
  • spam
  • sausage
horizontal_list Horizontal bulleted lists {{#invoke:Sandbox/Amahikari Hakuryuu/Random|horizontal_list|egg|sausage|spam}}
  • spam
  • egg
  • sausage
ordered_list Ordered lists (numbered lists and alphabetical lists) {{#invoke:Sandbox/Amahikari Hakuryuu/Random|ordered_list|egg|sausage|spam}}
  1. sausage
  2. spam
  3. egg
horizontal_ordered_list Horizontal ordered lists {{#invoke:Sandbox/Amahikari Hakuryuu/Random|horizontal_ordered_list|egg|sausage|spam}}
  1. spam
  2. sausage
  3. egg
Basic usage
{{#invoke:Sandbox/Amahikari Hakuryuu/Random|function|list item 1|list item 2|list item 3|...|limit=number of items to display|same=yes}}
All parameters

Template:Pre2

The maximum number of list items to display can be set with the |limit= parameter. The lowest possible is 0 and the highest possible is the length of the list.

If the |same= parameter is set to "yes", "y", "true", or "1", the list order is the same for each module call on a given page.

Please see Module:List for a full explanation of the other parameters.

-- This module contains a number of functions that make use of random numbers.

local cfg = {}

--------------------------------------------------------------------------------------
-- 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
--------------------------------------------------------------------------------------

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
--------------------------------------------------------------------------------------

local function raiseError(msg)
	-- This helps to generate a wikitext error. It is the calling function's responsibility as to how to include it in the output.
	return mw.ustring.format('<b class="error">[[Module:Random]] error: %s.</b>', msg)
end

--------------------------------------------------------------------------------------
-- random number function
--------------------------------------------------------------------------------------

local function getBigRandom(l, u)
	-- Gets a random integer between l and u, and is not limited to RAND_MAX.
	local r = 0
	local n = 2^math.random(30) -- Any power of 2.
	local limit = math.ceil(53 / (math.log(n) / math.log(2)))
	for i = 1, limit do
		r = r + math.random(0, n - 1) / (n^i)
	end
	return math.floor(r * (u - l + 1)) + l
end

function l.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.
	if first then
		if second then
			if first > second then -- Second number cannot be less than the first, or it causes an error.
				first, second = second, first
			end
			return getBigRandom(first, second)
		else
			return getBigRandom(1, first)
		end
	else
		return math.random()
	end
end

--------------------------------------------------------------------------------------
-- Date function
--------------------------------------------------------------------------------------

function l.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.
	local lang = mw.language.getContentLanguage()

	local function getDate(format, ts)
		local success, date = pcall(lang.formatDate, lang, format, ts)
		if success then
			return date
		end
	end

	local function getUnixTimestamp(ts)
		local unixts = getDate('U', ts)
		if unixts then
			return tonumber(unixts)
		end
	end

	local t1 = args[1]
	local t2 = args[2]
	
	-- Find the start timestamp and the end timestamp.
	local startTimestamp, endTimestamp
	if not t1 then
		-- Find the first and last second in the current year.
		local currentYear = tonumber(getDate('Y'))
		local currentYearStartUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear)))
		local currentYearEndUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear + 1))) - 1
		startTimestamp = '@' .. tostring(currentYearStartUnix) -- @ is used to denote Unix timestamps with lang:formatDate.
		endTimestamp = '@' .. tostring(currentYearEndUnix)
	elseif t1 and not t2 then
		startTimestamp = '@0' -- the Unix epoch, 1 January 1970
		endTimestamp = t1
	elseif t1 and t2 then
		startTimestamp = t1
		endTimestamp = t2
	end

	-- Get Unix timestamps and return errors for bad input (or for bugs in the underlying PHP library, of which there are unfortunately a few)
	local startTimestampUnix = getUnixTimestamp(startTimestamp)
	local endTimestampUnix = getUnixTimestamp(endTimestamp)
	if not startTimestampUnix then
		return raiseError('"' .. tostring(startTimestamp) .. '" was not recognised as a valid timestamp')
	elseif not endTimestampUnix then
		return raiseError('"' .. tostring(endTimestamp) .. '" was not recognised as a valid timestamp')
	elseif startTimestampUnix > endTimestampUnix then
		return raiseError('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.
	local randomTimestamp = getBigRandom(startTimestampUnix, endTimestampUnix)
	local dateFormat = args.format or 'H:i, d F Y (T)'
	local result = getDate(dateFormat, '@' .. tostring(randomTimestamp))
	if result then
		return result
	else
		return raiseError('"' .. dateFormat .. '" is not a valid date format')
	end
end

--------------------------------------------------------------------------------------
-- List functions
--------------------------------------------------------------------------------------

local function 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.
	-- 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
		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

local function removeBlanks(t)
	-- Removes blank entries from an array so that it can be used with ipairs.
	local ret = {}
	for k, v in pairs(t) do
		if type(k) == 'number' then
			table.insert(ret, k)
		end
	end
	table.sort(ret)
	for i, v in ipairs(ret) do
		ret[i] = t[v]
	end
	return ret
end

local function makeSeparator(sep)
	if sep == 'space' then
		-- 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.
		local mwseparators = {'dot', 'pipe', 'comma', 'tpt-languages'}
		for _, mwsep in ipairs(mwseparators) do
			if sep == mwsep then
				return mw.message.new( sep .. '-separator' ):plain()
			end
		end
		return sep
	end
end

local function makeRandomList(args)
	local list = removeBlanks(args)
	list = randomizeArray(list, tonumber(args.limit))
	return list
end

function l.item(args)
	-- Returns a random item from a numbered list.
	local list = removeBlanks(args)
	local len = #list
	if len >= 1 then
		return list[math.random(len)]
	end
end

function l.list(args)
	-- Randomizes a list and concatenates the result with a separator.
	local list = makeRandomList(args)
	local sep = makeSeparator(args.sep or args.separator)
	return table.concat(list, sep)
end

function l.text_list(args)
	-- Randomizes a list and concatenates the result, text-style. Accepts separator and conjunction arguments.
	local list = makeRandomList(args)
	local sep = makeSeparator(args.sep or args.separator)
	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

--------------------------------------------------------------------------------------
-- HTML list function
--------------------------------------------------------------------------------------

function l.html_list(args, listType)
	-- Randomizes a list and turns it into an HTML list. Uses [[Module:List]].
	listType = listType or 'bulleted'
	local listArgs = makeRandomList(args) -- Arguments for [[Module:List]].
	for k, v in pairs(args) do
		if type(k) == 'string' then
			listArgs[k] = v
		end
	end
	return makeList(listType, listArgs)
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(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))
		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
--------------------------------------------------------------------------------------

local function makeWrapper(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.
	return function (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.
		local origArgs
		if frame == mw.getCurrentFrame() then
			origArgs = frame:getParent().args
			for k, v in pairs(frame.args) do
				origArgs = frame.args
				break
			end
		else
			origArgs = frame
		end
		-- Trim whitespace and remove blank arguments.
		local args = {}
		for k, v in pairs(origArgs) do
			if type(v) == 'string' then
				v = mw.text.trim(v)
			end
			if v ~= '' then
				args[k] = v
			end
		end
		return p.main(funcName, args, listType)
	end
end

-- Process arguments for HTML list functions.
local htmlListFuncs = {
	bulleted_list           = 'bulleted',
	unbulleted_list         = 'unbulleted',
	horizontal_list         = 'horizontal',
	ordered_list            = 'ordered',
	horizontal_ordered_list = 'horizontal_ordered'
}
for funcName, listType in pairs(htmlListFuncs) do
	p[funcName] = makeWrapper('html_list', listType)
end

-- Process arguments for other functions.
local otherFuncs = {'number', 'date', 'item', 'list', 'text_list'}
for _, funcName in ipairs(otherFuncs) do
	p[funcName] = makeWrapper(funcName)
end

return p