diff --git a/src/main/java/fr/mieuxvoter/mj/DeliberatorInterface.java b/src/main/java/fr/mieuxvoter/mj/DeliberatorInterface.java index 4131fa3..25e0a64 100644 --- a/src/main/java/fr/mieuxvoter/mj/DeliberatorInterface.java +++ b/src/main/java/fr/mieuxvoter/mj/DeliberatorInterface.java @@ -3,16 +3,18 @@ package fr.mieuxvoter.mj; /** * A Deliberator takes in a poll's Tally, - * that is the amount of judgments of each grade received by each Proposal, - * and outputs that poll's Result, - * that is the final rank of each Proposal. + * which holds the amount of judgments of each grade received by each Proposal, + * and outputs that poll's Result, that is the final rank of each Proposal. + * * Ranks start at 1 ("best"), and increment towards "worst". * Two proposal may share the same rank, in extreme equality cases. * * This is the main API of this library. * * See MajorityJudgmentDeliberator for an implementation. - * One could implement other deliberators, such as CentralJudgment or UsualJudgment. + * One could implement other deliberators, such as: + * - CentralJudgmentDeliberator + * - UsualJudgmentDeliberator */ public interface DeliberatorInterface { diff --git a/src/main/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberator.java b/src/main/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberator.java index 53bfa83..97641e8 100644 --- a/src/main/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberator.java +++ b/src/main/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberator.java @@ -18,11 +18,10 @@ import java.util.Comparator; * * https://en.wikipedia.org/wiki/Majority_judgment * https://fr.wikipedia.org/wiki/Jugement_majoritaire - * - * Should this class be "final" ? */ -public class MajorityJudgmentDeliberator implements DeliberatorInterface { +final public class MajorityJudgmentDeliberator implements DeliberatorInterface { + @Override public ResultInterface deliberate(TallyInterface tally) { ProposalTallyInterface[] tallies = tally.getProposalsTallies(); BigInteger amountOfJudges = tally.getAmountOfJudges(); @@ -41,7 +40,7 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface { proposalResults[proposalIndex] = proposalResult; } - // II. Sort Proposals by score + // II. Sort Proposals by score (lexicographical inverse) ProposalResult[] proposalResultsSorted = proposalResults.clone(); assert(proposalResultsSorted[0].hashCode() == proposalResults[0].hashCode()); // we need a shallow clone Arrays.sort(proposalResultsSorted, new Comparator() { @@ -70,11 +69,21 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface { return result; } - public String computeScore(ProposalTallyInterface tally, BigInteger amountOfJudges) { + protected String computeScore(ProposalTallyInterface tally, BigInteger amountOfJudges) { return computeScore(tally, amountOfJudges, true, false); } - public String computeScore( + /** + * A higher score means a better rank. + * Assumes that grades' tallies are provided from "worst" grade to "best" grade. + * + * @param tally Holds the tallies of each Grade for a single Proposal + * @param amountOfJudges + * @param favorContestation + * @param onlyNumbers Do not use separation characters, match `^[0-9]+$` + * @return + */ + protected String computeScore( ProposalTallyInterface tally, BigInteger amountOfJudges, Boolean favorContestation, @@ -82,8 +91,8 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface { ) { ProposalTallyAnalysis analysis = new ProposalTallyAnalysis(); int amountOfGrades = tally.getTally().length; - int digitsForGrade = ("" + amountOfGrades).length(); - int digitsForGroup = ("" + amountOfJudges).length() + 1; + int digitsForGrade = countDigits(amountOfGrades); + int digitsForGroup = countDigits(amountOfJudges) + 1; ProposalTallyInterface currentTally = tally.duplicate(); @@ -107,6 +116,7 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface { score += String.format( "%0"+digitsForGroup+"d", + // We offset by amountOfJudges to keep a lexicographical order (no negatives) // amountOfJudges + secondMedianGroupSize * secondMedianGroupSign amountOfJudges.add( analysis.getSecondMedianGroupSize().multiply( @@ -121,4 +131,12 @@ public class MajorityJudgmentDeliberator implements DeliberatorInterface { return score; } + protected int countDigits(int number) { + return ("" + number).length(); + } + + protected int countDigits(BigInteger number) { + return ("" + number).length(); + } + } diff --git a/src/main/java/fr/mieuxvoter/mj/ProposalResultInterface.java b/src/main/java/fr/mieuxvoter/mj/ProposalResultInterface.java index 692ac61..ff0e6ab 100644 --- a/src/main/java/fr/mieuxvoter/mj/ProposalResultInterface.java +++ b/src/main/java/fr/mieuxvoter/mj/ProposalResultInterface.java @@ -2,20 +2,21 @@ package fr.mieuxvoter.mj; public interface ProposalResultInterface { - + /** * Rank starts at 1 ("best" proposal), and goes upwards. * Multiple Proposals may receive the same rank, - * in the extreme case where they received the exact same judgments. + * in the extreme case where they received the exact same judgments, + * or judgment repartition in normalized tallies. */ public Integer getRank(); /** * This score was used to compute the rank. * It is made of integer characters, with zeroes for padding. - * Reverse lexicographical order: "higher" is "better". + * Inverse lexicographical order: "higher" is "better". * You're probably never going to need this, but it's here anyway. */ public String getScore(); - + }