Module:games

Hello, you have come here looking for the meaning of the word Module:games. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:games, but we will also tell you about its etymology, its characteristics and you will know how to say Module:games in singular and plural. Everything you need to know about the word Module:games you have here. The definition of the word Module:games will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:games, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

Created for Wiktionary:Christmas Competition 2017. One function powers {{game entry}}, and other functions use data generated by Module:games/data to count points and generate other statistics about the game (see Wiktionary talk:Christmas Competition 2017/game data).


local m_fun = require("Module:fun")
local m_str_utils = require("Module:string utilities")

local concat = table.concat
local insert = table.insert
local invert = require("Module:table").invert
local lower = m_str_utils.lower
local map = m_fun.map
local mapIter = m_fun.mapIter
local remove = table.remove
local sub = m_str_utils.sub
local toNFC = mw.ustring.toNFC
local toNFD = mw.ustring.toNFD

local export = {}

local title = mw.title.getCurrentTitle()
local namespace = title.nsText
local fullpagename = title.fullText

--[[
local langbr = "⟨"
local rangbr = "⟩"
--]]

local function quote(word)
	return "“" .. word .. "”"
end

local function link(word, lang)
	if word:find("%[%[") then
		return word
	else
		if lang then
			return "]"
		else
			return "]"
		end
	end
end

local function italicize(word)
	if word:find("''") then
		return word
	else
		return "''" .. word .. "''"
	end
end

local function tag(word, script)
	return '<span class="' .. script .. '">' .. word .. '</span>'
end

local function add_color(color, text, attribute)
	return '<span style="color: ' .. color .. ';" ' .. (attribute or '') .. '>' .. text .. '</span>'
end

local is_combining = require "Module:Unicode data".is_combining

local find_best_script = require "Module:scripts".findBestScriptWithoutLang

local translit = {
	Hang = "ko-translit",
	ja = { "Hrkt-translit", "tr", "ja" },
}

local non_diacritic_equivalencies = {
	 = "d",  = "o",  = "???",  = "d",  = "h",  = "i",
	 = "n",  = "???",  = "t",  = "s",  = "???",
	 = "l",  = "a",  = "b",  = "c",  = "d",  = "e",
	 = "f",  = "g",  = "h",  = "i",  = "j",  = "k",
	 = "l",  = "m",  = "n",  = "o",  = "p",  = "r",
	 = "s",  = "t",  = "u",  = "v",  = "w",  = "x",
	 = "y",  = "z",  = "a",  = "b",  = "d",  = "e",
	 = "g",  = "h",  = "i",  = "j",  = "k",  = "l",
	 = "m",  = "n",  = "o",  = "p",  = "r",  = "t",
	 = "u",  = "v",  = "w",  = "a",  = "e",  = "h",
	 = "i",  = "j",  = "k",  = "l",  = "m",  = "n",
	 = "o",  = "o",  = "r",  = "s",  = "t",  = "u",
	 = "v",  = "x", --  = "n",  = "o",
	 = "",  = "",  = "",  = "",  = "",  = "",
 -- ...
}

-- Remove all diacritics. Make use of the replacements shown above.
-- Remove spaces and hyphens.
local function regularize(word)
	return (lower(toNFD(word))
		:gsub(
			"+",
			function (non_ASCII_character)
				if is_combining(non_ASCII_character) then
					return ""
				end
				return non_diacritic_equivalencies
			end))
		:gsub(
			"",
			"")
end

-- Allowed parameters:
-- -- numbers
-- -- lang, lang1, lang2, ...
-- -- tr, tr1, tr2, ...
-- -- ignore rules (boolean)
local function get_args(args)
	local words = {}
	local langs, translits, ignore_rules
	
	for arg, value in pairs(args) do
		if type(arg) == "number" then
			words = value
		elseif type(arg) == "string" then
			if arg == "ignore rules" then
				ignore_rules = require("Module:yesno")(value)
			else
				local name, number = arg:match("^(%l+)(%d*)$")
				if not (name == "lang" or name == "tr") then
					error("The parameter |" .. arg .. "= is not used by this template.")
				end
				
				if number == "" then
					number = 1
				else
					number = tonumber(number)
				end
				
				if name == "lang" then
					langs = langs or {}
					langs = langs and error("Two langs with index " .. number .. ".")
						or value and (require("Module:languages").getByCode(value)
						or error("Invalid language code " .. quote(value) .. "."))
				else
					translits = translits or {}
					translits = translits and error("Two translits with index " .. number .. ".")
						or value
				end
			end
		end
	end
	
	return words, langs, translits, ignore_rules
end

local function show_words(previous_word, interposing_words, following_word)
	return link(previous_word) .. " ("
		.. concat(
			map(
				function(word)
					return italicize(link(word))
				end,
				interposing_words),
			", ")
		.. ") "
		.. link(following_word)
end

function export.Christmas_Competition_entry(frame)
	local words, langs, translits, ignore_rules = get_args(frame:getParent().args)
	
	if namespace == "" or namespace == "Reconstruction" or namespace == "Appendix" then
		error("This template is only supposed to be used in the Christmas Competition!")
	end
	
	words.length = #words
	
	if words.length < 3 then
		if namespace == "Template" then
			words = { "Shèngdànjié", "jiellat", "llatino" }
		else
			error("This template wants at least three words.")
		end
	end
	
	local regularized_words = {}
	local nonLatin_i = 0
	local last_interposing_word = (words.length or #words) - 1
	
	for i, word in ipairs(words) do
		-- Check for duplicate interposing words.
		if 1 < i and i < last_interposing_word then
			for j = i + 1, last_interposing_word do
				if word == words then
					error("You used the word " .. quote(word) .. " twice, in parameters " .. i .. " and " .. j .. "!")
				end
			end
		end
		
		local tr
		if word:find("") then -- non-ASCII
			local script = find_best_script(word):getCode()
			if script and not script:find "Lat" then -- non-Latin
				-- ] requires word to be in NFC.
				nonLatin_i = nonLatin_i + 1
				local lang = langs and langs
				if translits and translits then
					tr = translits
				elseif lang then
					tr = lang:transliterate(toNFC(word), require("Module:scripts").getByCode(script))
						or lang:transliterate(toNFC(word))
						or translit
							and require("Module:" .. translit)](word, unpack(translit, 3))
						or error("The " .. lang:getCode()
							.. " transliteration module was unable to generate a transliteration for "
							.. quote(word) .. ".")
				elseif translit then
					local success, result = pcall(require("Module:" .. translit).tr, toNFC(word), script)
					tr = success and result or error("[[Module:"
						.. translit
						.. "]] wasn't able to generate a transliteration for "
						.. quote(word) .. ".")
				else
					error("You need to give the language code for the word "
						.. quote(word)
						.. " in the |lang" .. nonLatin_i .. "= parameter so that the word can be transliterated.")
				end
				
				if tr then
					if i == 1 or i == words.length then
						word = tag(link(word, lang), script) .. " (" .. tr .. ")"
					else
						word = tag(link(word, lang), script) .. " (" .. italicize(tr) .. ")"
					end
					-- word = italicize(tr) .. " " .. langbr .. tag(link(word), script) .. rangbr
				end
			end
		end
		words = word
		regularized_words = regularize(tr or word)
	end
	
	-- Complain if there aren't as many non-Latin-script words as lang parameters.
	if langs then
		if nonLatin_i < #langs then
			error(#langs .. " |lang= parameter"
				.. (#langs == 1 and "" or "s") .. ", but only "
				.. nonLatin_i .. " non-Latin-script word"
				.. (nonLatin_i == 1 and "" or "s") .. "!")
		end
	end
	
	local previous_word = remove(words, 1)
	local last_three = sub(previous_word, -3)
	local following_word = remove(words, #words)
	
	local regularized_previous_word = remove(regularized_words, 1)
	local regularized_last_three = regularized_previous_word:sub(-3)
	local regularized_following_word = remove(regularized_words, #regularized_words)
	
	-- Check interposing words.
	local messages, message_number, message
	for i, word in ipairs(regularized_words) do
		local ending = word:match("^" .. regularized_last_three .. "(.+)$")
		
		-- Rules:
		--	-- Interposing words must start with last three letters of previous word.
		--	-- After these three letters must be three or more additional letters.
		--	-- These additional letters must begin the following word.
		
		-- WARNING! The color-adding will probably not work with transliteration.
		if not ending then
			if ignore_rules then
				message = true
			else
				message = "The interposing word "
						.. quote(word) .. " must start with the last three letters of "
						.. quote(previous_word) .. ", " .. quote(regularized_last_three) .. "."
			end
		elseif #ending < 3 then
			if ignore_rules then
				message = true
			else
				local difference = 3 - #ending
				local agreement = difference == 1 and "" or "s"
				message = "The interposing word "
						.. quote(word) .. " needs " .. difference .. " more letter" .. agreement .. "."
			end
		elseif not regularized_following_word:find("^" .. ending) then
			if ignore_rules then
				message = true
			else
				message = "The last word " .. quote(following_word) .. " must start with "
					.. quote(ending) .. ", the final letters of "
					.. quote(word) .. " after the last three letters of "
					.. quote(previous_word) .. ", " .. quote(last_three) .. ", are removed."
			end
		end
		
		if message then
			if ignore_rules then
				messages = (messages or 0) + 1
			else
				messages = messages or {}
				message_number = message_number or 1
				messages = message
				message_number = message_number + 1
			end
		end
		message = nil
	end
	
	if messages then
		if ignore_rules then
			local plural = messages > 1 and true or false
			return show_words(previous_word, words, following_word) ..
				' <span style="color: red;">Rules broken ' .. messages ..
				' time' .. (plural and "s" or "") .. '!</span>'
		else
			error(concat(messages, " "))
		end
	else
		return show_words(previous_word, words, following_word)
	end
end

local Wonderfool_page = "User:Wonderfool/alternative accounts"
local function get_Wonderfool_names()
	local list = require("Module:pages").get_section(
		mw.title.new(Wonderfool_page):getContent(),
		"List"
	)
	
	local names = {}
	
	for name in list:gmatch("%f|(.-)|") do
		names = true
	end
	
	return names
end

local Autotable = require("Module:auto-subtable")

local function compile_points_per_user(games, dont_merge_Wonderfool)
	local users = Autotable()
	
	local merge_Wonderfool = not dont_merge_Wonderfool
	
	local is_Wonderfool
	if merge_Wonderfool then
		is_Wonderfool = get_Wonderfool_names()
	end
	
	for _, game in ipairs(games) do
		for i, entry in ipairs(game) do
			local user = entry.username
			if merge_Wonderfool then
				user = is_Wonderfool and "Wonderfool" or user
			end
			
			local userdata = users
			
			userdata.points = (userdata.points or 0) + entry.points
		end
	end
	return users
end

local function compare(user_table)
	local function get_compare_value(user)
		return user_table.points
	end
	return function (user1, user2)
		return get_compare_value(user1) > get_compare_value(user2)
	end
end

local function link_username(username)
	if username == "Wonderfool" then
		return "]"
	else
		return "]"
	end
end

local function print_points(users)
	-- Have to remove auto-subtabling; copy in case this causes errors in the
	-- calling function.
	users = require("Module:table").deepcopy(users):un_auto_subtable()
	
	return concat(
		mapIter(
			function(data, user)
				return "* " .. link_username(user) .. ": " .. data.points
			end,
			require("Module:table").sortedPairs(users, compare(users))),
		"\n")
end

local function generate_statistics(games)
	local statistics = Autotable()
	local all = {}
	statistics.all = all
	
	for _, game in ipairs(games) do
		for i, entry in ipairs(game) do
			local user = entry.username
			local userdata = statistics
			local interposing_count = entry.interposing.count
			userdata = (userdata or 0) + 1
			all = (all or 0) + 1
		end
	end
	
	local averages = {}
	for user, interposing_data in pairs(statistics) do
		local total_interposing_words = 0
		local total_entries = 0
		for interposing_count, number_of_times in pairs(interposing_data) do
			total_interposing_words = total_interposing_words + interposing_count * number_of_times
			total_entries = total_entries + number_of_times
		end
		local average = total_interposing_words / total_entries
		averages = math.floor(average * 10 + 0.5 ) / 10
	end
	
	return statistics, averages
end

function print_statistics(statistics, averages)
	local output = {}
	
	for user, data in pairs(statistics) do
		insert(output, "* " .. (user ~= "all" and link_username(user) or "all players"))
		insert(output, "** " .. averages .. " interposing word" .. (averages * 10 ~= 10 and "s" or "") .. " per entry")
		for interposing_count, number_of_times in pairs(data) do
			insert(output, "** " .. interposing_count
				.. " interposing word" .. (interposing_count ~= 1 and "s " or " ")
				.. number_of_times .. " time"
				.. (number_of_times ~= 1 and "s" or ""))
		end
	end
	
	return concat(output, "\n")
end

local month_numbers = invert {
	"January", "February", "March", "April", "May", "June",
	"July", "August", "September", "October", "November", "December"
}

-- Converts a date into a number that will allow the date column to be sorted reliably.
local function make_date_number(date)
	local hour, minute, day_of_month, month, last_two_of_year =
		string.match(date, "^(%d%d):(%d%d), (%d%d?) (%a+) %d%d(%d%d)")
	-- Each part of the date is multiplied by the least power of two greater than
	-- the maximum possible value that that part can have.
	return ((((last_two_of_year - 17) * 2 + month_numbers) * 16 + day_of_month) * 32 + hour) * 64 + minute
end

-- For concatenating virtual interposing word tables produced by mw.loadData.
local function concat_array(array, sep)
	local str = array or ""
	for i = 2, 15 do
		if array then
			str = str .. sep .. array
		else
			break
		end
	end
	return str
end

function export.show_parsed_games(frame)
	local games = mw.loadData("Module:games/data")
	
	local t = {
		'{| class="wikitable sortable"',
		'! game,<br>entry !! username !! date !! day<br>difference !! preceding<br>word !! interposing words !! count !! following<br>word !! points'
	}
	
	local function detect_and_tag(text)
		if not text:find("") then
			return tag(link(text), "Latn")
		end
		return tag(link(text), find_best_script(text):getCode())
	end
	
	for game_number, game in ipairs(games) do
		for entry_number, entry in ipairs(game) do
			insert(
				t,
				('|-\n| data-sort-value="%s" | %d&ndash;%d || %s || data-sort-value="%d" | %s || %s || %s || %s || %d || %s || %d')
					:format(string.format("%02d%02d", game_number, entry_number),
						game_number, entry_number, entry.username,
						make_date_number(entry.date), entry.date:gsub("December", "Dec"):gsub(".+", '<span style="white-space: nowrap;">%1</span>'),
						entry.day_difference and ("%.4f"):format(entry.day_difference) or "&mdash;",
						detect_and_tag(entry.preceding),
						concat_array(map(detect_and_tag, entry.interposing), ", "), entry.interposing.count,
						detect_and_tag(entry.following),
						entry.points))
		end
	end
	
	insert(t, "|}")
	
	return concat(t, "\n")
	-- return require("Module:debug").highlight_dump()
end

function export.show_statistics(frame)
	return print_statistics(generate_statistics(mw.loadData("Module:games/data")))
end
	

function export.print_points(frame)
	return print_points(compile_points_per_user(mw.loadData("Module:games/data")))
end

function export.print_game_data(frame)
	return require("Module:debug").highlight_dump(mw.loadData("Module:games/data"))
end

-- m_fun.logAll(export)

return export