Modul:games/data

A Wikiszótárból, a nyitott szótárból

A modult a Modul:games/data/doc lapon tudod dokumentálni

local fun = require "Module:fun"

local function matches_to_array(text, pattern)
	if not text then
		return nil
	end
	local t = {}
	local i = 0
	for match in text:gmatch(pattern) do
		i = i + 1
		t[i] = match
	end
	return t
end

local function split(text, char)
	if not text then
		return nil
	end
	if #char ~= 1 then
		error(char .. " is not a single character.")
	end
	return matches_to_array(text, "[^" .. char .. "]+")
end

local function grab_games(page)
	local games = {}
	local i = 0
	local j, _, equals
	
	repeat
		i = i + 1
		_, j, equals, games[i] = page:find("(===*)%s*Game " .. i .. "[^=]*%s*%1\n(.-)\n*==", j)
		
		if not j then -- match to end of page
			_, j, equals, games[i] = page:find("(===*)%s*Game " .. i .. "[^=]*%s*%1(.+)\n*$", j)
		end
		
		if j then
			j = j - #equals - 1
		end
	until not j
	
	if not games[1] then
		error("No games found!")
	end
	
	return games
end

local days_in_month = {
	January = 31, February = 28, March = 31, April = 30, May = 31, June = 30,
	July = 31, August = 31, September = 30, October = 31, November = 30, December = 31,
}

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

local function month_and_day_to_day_in_year(month, day)
	local day_in_year = 0
	
	for _, month_name in ipairs(months) do
		if month_name == month then
			break
		end
		
		day_in_year = day_in_year + days_in_month[month_name]
	end
	
	return day_in_year + day
end

local memo = {}
setmetatable(
	memo,
	{
		__index = function(self, key)
			local val = {}
			self[key] = val
			return val
		end
	})

-- Memoize.
local function get_day_in_year(month, day)
	local day_in_year = memo[month][day]
	if not day_in_year then
		day_in_year = month_and_day_to_day_in_year(month, day)
		memo[month][day] = day_in_year
	end
	return day_in_year
end

-- Change this if game goes into January.
local minutes_in_day = 24 * 60
local start_date = get_day_in_year("December", 1)
local function get_time_in_days(date)
	local hour, minute, day, month, last_two_of_year =
		date:match("(%d%d):(%d%d), (%d+) (%a+) %d%d(%d%d)")
	
	return 365 * (tonumber(last_two_of_year) - 17)
		+ get_day_in_year(month, tonumber(day)) - start_date
		+ tonumber(hour) / 24
		+ tonumber(minute) / minutes_in_day
end

local function round(decimals)
	local power = 10 ^ decimals
	return function(number)
		return math.floor(number * power) / power
	end
end

local round4 = round(4)
local function get_day_difference(date1, date2)
	return round4(math.abs(get_time_in_days(date1) - get_time_in_days(date2)))
end

local function parse_games(games)
	local parsed_games = {}
	
	local function word_param_filter(word)
		return not word:find("^lang%d*=") and not word:find("^tr%d*=")
	end
	
	for i, game in ipairs(games) do
		local parsed_game = {}
		parsed_games[i] = parsed_game
		local j = 0
		local to_be_ignored, prev_date
		for game_entry, first_character in game:gmatch("\n%*%s+(([%[{])[^\n]+)") do
			local interposing_words
			if first_character == "{" then
				if game_entry:find("ignore rules=", 1, true) then
					to_be_ignored = true
				else
					interposing_words = split(game_entry:match("{{game entry|([^}]+)}}"), "|")
					-- Remove |lang=, |langN=, |tr=, |trN=.
					interposing_words = fun.filter(
						word_param_filter,
						interposing_words)
				end
			else
				local wordlist = game_entry:match("%b[]%s+%b()%s+%b[]")
				
				if wordlist:find("{{", 1, true) then
					local words_by_position = {}
					local _, endpos, word
					
					-- Grab any words in a link template.
					while true do
						_, endpos, word = wordlist:find("{{[lm]|[^|]+|([^|]+)[^}]*}", endpos)
						if not endpos then break end
						words_by_position[endpos] = word
					end
					
					-- Grab bare links.
					endpos = 1
					while true do
						_, endpos, word = wordlist:find("%[%[([^%]]+)%]%]", endpos)
						if not endpos then break end
						words_by_position[endpos] = word
					end
					
					interposing_words = require("Module:table").compressSparseArray(words_by_position)
				else
					-- Grab bare links.
					interposing_words = matches_to_array(wordlist, "%[%[([^%]]+)%]%]")
				end
			end
			
			if interposing_words then
				local preceding = table.remove(interposing_words, 1)
				local length = #interposing_words
				local following = table.remove(interposing_words, length)
				interposing_words.count = length - 1
				
				-- Change this if game goes into January.
				local date = game_entry:match("%d%d:%d%d, %d%d? %a+ %d%d%d%d")
				local day_difference
				
				if not date then
					mw.log("No date found in the game entry " .. game_entry .. ".")
				elseif prev_date then
					day_difference = get_day_difference(date, prev_date)
				end
				
				j = j + 1
				
				prev_date = date
				
				parsed_game[j] = {
					preceding = preceding,
					following = following,
					interposing = interposing_words,
					username = game_entry:match("User:([^%]|]+)")
						or mw.log("No username found in the game entry " .. game_entry .. "."),
					date = date,
					day_difference = day_difference,
				}
			elseif not to_be_ignored then
				mw.log("The game entry " .. game_entry .. " could not be parsed!")
			end
		end
	end
	
	return parsed_games
end

--[[
local Wonderfool_page = "User:AryamanA/Wonderfool"
local function get_Wonderfool_names()
	local list = mw.title.new(Wonderfool_page):getContent():match("==List==\n*(.-)\n*==")
	
	local names = {}
	
	for name in list:gmatch("{{user|([^}]+)}}") do
		names[name] = true
	end
	
	return names
end
--]]

local function count_points(games)
	local users = {}
	
	--[[
	local conditional_logObject
	if fullpagename == "Wiktionary:Christmas Competition 2017" then
		function conditional_logObject() end
	else
		function conditional_logObject(...)
			return mw.logObject(...)
		end
	end
	--]]
	
	for _, game in ipairs(games) do
		local prev
		for i, entry in ipairs(game) do
			local user = entry.username
			-- user = is_Wonderfool[user] and "Wonderfool" or user
			
			-- 10 points for each successful extension of the chain.
			local points = 10
			
			-- 5 points for each additional interposing word.
			points = points + (entry.interposing.count - 1) * 5
			
			-- 25 points if last extension to chain was 3 days or more ago.
			local day_difference = entry.day_difference
			if day_difference and day_difference > 3 then
				-- conditional_logObject{ prev, entry, difference = day_difference }
				points = points + 25
			end
			
			-- 10 points to the last user to extend each chain.
			if not game[i + 1] then
				points = points + 10
			end
			
			entry.points = points
			
			-- prev = entry
		end
	end
	
	return games
end

return count_points(parse_games(grab_games(mw.title.new("Wiktionary:Christmas Competition 2017"):getContent())))