Module:majority judgement

La documentation pour ce module peut être créée à Module:majority judgement/Documentation

local p = {}

local GRADES_LABELS = { "À Rejeter", "Insuffisant", "Passable", "Assez Bien", "Bien", "Très Bien" }
local COLORS = { "black", "red", "yellow", "yellowgreen", "ForestGreen", "DarkGreen" }

local function initVotes(nbCandidates)
	local votes = {}
	for i=1,nbCandidates do
		votes[i] = {0, 0, 0, 0, 0, 0}
	end
	return votes
end

local function parseVotes(nbVoters, nbCandidates, args)
	local voters = {}
	local votes = initVotes(nbCandidates)
	
	for i=0,nbVoters-1 do
	  table.insert(voters, mw.text.trim(args[i * (nbCandidates + 1) + 1]))
	  for j=1,nbCandidates do
	  	local vote = tonumber(args[i * (nbCandidates + 1) + j + 1])
	  	if vote == -1 then
	  		vote = 0
	  	end
	  	vote = vote + 1
	  	votes[j][vote] = votes[j][vote] + 1
	  end
	end
	
	return voters, votes
end

local function userLink(user)
	return mw.ustring.format("[[User:%s|%s]]", user, user)
end

local function generateVotersList(nbVoters, voters)
	local message = nbVoters .. " personnes ont voté : "
	
	for i, v in ipairs(voters) do
		message = message .. userLink(v) .. ((i < nbVoters) and ", " or ".\n")
	end
	
	return message
end

local function generateResultTableHeader(label)
	local message = mw.ustring.format([[
	{| class="wikitable" style="text-align: center
	|+ Votes en %s
	! Choix
	! À Rejeter
	! Insuffisant
	! Passable
	! Assez Bien
	! Bien
	! Très Bien
	]], label)
	return message
end

local function generateAbsoluteValueVotes(nbCandidates, nbVoters, votes)
	local message = generateResultTableHeader("valeur absolue")
	
	for i=1,nbCandidates do
    	message = message .. "|-\n|Choix " .. i
    	for j=1,6 do
    		local vote = votes[i][j]
    		message = message .. "||" .. vote
    	end
    	message = message .. "\n"
	end
	
	message = message .. "|}\n"
	
	return message
end

local function formatPercentage(value)
	return mw.ustring.format("%.2f%%", value)
end

local function generatePercentageVotes(nbCandidates, nbVoters, votes)
	local message = generateResultTableHeader("pourcentage")
	
	for i=1,nbCandidates do
    	message = message .. mw.ustring.format("|-\n|Choix %d", i)
    	for j=1,6 do
    		local vote = votes[i][j]
    		message = message .. "||" .. formatPercentage(vote / nbVoters * 100)
    	end
    	message = message .. "\n"
	end
	
	message = message .. "|}\n"
	
	return message
end

local function generateHistogram(nbCandidates, nbVoters, votes)
	local message = [[
	{|
	|+ '''Histogramme des votes'''
	|-
	| &nbsp;&nbsp;&nbsp;
	|
	{| cellpadding=0 width=500 border=0 cellspacing=0
	|-
	| width=49% | &nbsp;
	| width=2% style=\"text-align: center\" | ↓
	| width=49% | Point médian
	|}
	]]

	for i=1,nbCandidates do
    	message = message .. mw.ustring.format([[
    	|-
    	| Choix %d
    	|
    	{| cellpadding=0 width=500 border=0 cellspacing=0
    	|-
    	]], i)
    
    	for j=1,6 do
	    	if votes[i][j] ~= 0 then
	    		message = message .. 
	    		mw.ustring.format('| bgcolor="%s" width="%s" |&nbsp;\n', COLORS[j], formatPercentage(votes[i][j] / nbVoters * 100))
	    	end
	    end
    	message = message .. "|}\n"
	end

	message = message .. "|}\n"
	return message
end

local function generateCondensedVotes(nbCandidates, nbVoters, votes)
	local message = generateAbsoluteValueVotes(nbCandidates, nbVoters, votes)
	message = message .. generatePercentageVotes(nbCandidates, nbVoters, votes)
	message = message .. generateHistogram(nbCandidates, nbVoters, votes)
	return message
end

local function computeMajorityGrades(nbCandidates, nbVoters, votes)
	local median = nbVoters / 2
	local grades = {}
	for i = 1,nbCandidates do
		local sum = 0
		local grade = -1
		for j, vote in ipairs(votes[i]) do
			sum = sum + vote
			if sum >= median then
				grade = j - 1
				break
			end
		end
		table.insert(grades, grade)
	end
	return grades
end

local function searchWinners(grades)
	local maxGrade = -1
	local maxCandidates = {}
	for i,mention in ipairs(grades) do
		if mention > maxGrade then
			maxGrade = mention
			maxCandidates = {}
		end
		if mention == maxGrade then
			table.insert(maxCandidates, i)	
		end
	end
	return maxGrade, maxCandidates
end

local function computeGroupsTable(candidates, votes, lowerGrade, higherGrade)
	local message =  "{| class=\"wikitable\" style=\"text-align: center\"\n"
	message = message .. "|+\n"
	message = message .. "!Choix !! Votes pour des<br>mentions<br>inférieures !! Votes pour des<br>mentions<br>supérieures\n"
	
	local tmp = {}
	for i, candidate in ipairs(candidates) do
		local tmp2 = {0, 0}
		for j=1,lowerGrade do
			tmp2[1] = tmp2[1] + votes[candidate][j]
		end
		for j=higherGrade+2,5 do
			tmp2[2] = tmp2[2] + votes[candidate][j]
		end
		
		message = message .. "|-\n"
		message = message .. "| Choix " .. candidate .."||" .. tmp2[1] .. "||" .. tmp2[2] .. "\n"
		tmp[candidate] = tmp2
	end
	
	return tmp, message .. "|}\n"
end

--[[
Encodage des résultats :
 -1 = non répondu, considéré comme à rejeter
 0 = à rejeter
 1 = insuffisant
 2 = passable
 3 = assez bien
 4 = bien
 5 = très bien
]]--
function p.judge(frame)
	local args = frame:getParent().args
	local nbCandidates = tonumber(args['nb_candidats'])
	local nbVoters = tonumber(args['nb_votants'])
	local voters, votes = parseVotes(nbVoters, nbCandidates, args)
	
	local message = "=== Affichage condensé des votes ===\n"
	message = message .. generateVotersList(nbVoters, voters)
	message = message .. generateCondensedVotes(nbCandidates, nbVoters, votes)

	-- Calcul du meilleur choix
	local grades = computeMajorityGrades(nbCandidates, nbVoters, votes)
	local maxGrade, maxCandidates = searchWinners(grades)

	--- Affichage des résultats
	message = message .. "=== Résultats ===\n"
	local nbWinners = #maxCandidates
	if nbWinners == 1 then
		return message .. "Le choix " .. maxCandidates[1] .. " remporte le vote en ayant obtenu la mention " .. GRADES_LABELS[maxGrade + 1] ..".\n"
	elseif nbWinners > 1 then
		message = message .. "Plusieurs candidats ont obtenu la même mention majoritaire (" .. GRADES_LABELS[maxGrade + 1] .. ") : "
		for i,candidate in ipairs(maxCandidates) do
			message = message .. candidate .. ((i < nbWinners) and ", " or ".\n")
		end
	else
		return "ERREUR"	
	end
	
	-- Départage
	local groups, tabular = computeGroupsTable(maxCandidates, votes, maxGrade, maxGrade)
	message = message .. tabular
	
	local maxi = -1
	for candidate, group in pairs(groups) do
		local q = group[1]
		if q < maxi then
			maxi = q
		end
		local p = group[2]
	end
	
	return message
end

return p