Skip to content

Commit

Permalink
feat: improve agreement algorithm (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
philmtd authored Nov 22, 2023
1 parent fd2a7fa commit ec9e4eb
Showing 1 changed file with 14 additions and 38 deletions.
52 changes: 14 additions & 38 deletions frontend/src/app/game/game/agreement.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,25 @@
import {Vote} from "../model";


interface VotedValue {
card: number;
totalVotes: number;
export function calculateAgreement(votes: Array<Vote>): number | null {
const votedNumbers = votes.filter(vote => vote.voted && isVoteNumerical(vote));
return calculateAgreementInternal(votedNumbers.map(v => v.vote as number))
}

export function calculateAgreement(votes: Array<Vote>): number | null {
const totalVotes = votes.filter(vote => vote.voted && isVoteNumerical(vote)).length;
const votedValues = countVotedValues(votes);
if (votedValues.size === 0) {
function calculateAgreementInternal(numbers: number[]): number | null {
if (numbers.length === 0) {
return null;
} else if (votedValues.size === 1) {
return 100;
}

const voteRatios = [...votedValues.entries()].map(entry => entry[1]/totalVotes);
const voteRationsStandardDeviation = standardDeviation(voteRatios, true);

return Math.round(Math.min(voteRationsStandardDeviation, 0.6) / (1 - 0.6) * 100);
const consensus: number = numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
const deviationsFromConsensus: number[] = numbers.map(num => Math.abs(num - consensus));
const averageDeviation: number = deviationsFromConsensus.reduce((sum, deviation) => sum + deviation, 0) / deviationsFromConsensus.length;
const votedValueRange: number = Math.max(...numbers) - Math.min(...numbers);
const minMaxDeviationPercentage: number = 10;
const maxDeviationScalingFactor: number = 5;
const maxDeviationPercentage: number = Math.max(minMaxDeviationPercentage, 70 - (votedValueRange / maxDeviationScalingFactor));
const maxDeviation: number = (maxDeviationPercentage / 100) * consensus;
return Math.max(0, (1 - averageDeviation / maxDeviation) * 100);
}

export function isVoteNumerical(v: Vote): boolean {
return v.vote != undefined && typeof v.vote == "number" && v.vote >= 0;
}

function countVotedValues(votes: Array<Vote>): Map<number, number> {
const countedVotedValues = new Map<number, number>();
votes.forEach(v => {
if (v.voted && isVoteNumerical(v)) {
const numericalVote = v.vote as number;
if (!countedVotedValues.has(numericalVote)) {
countedVotedValues.set(numericalVote, 0);
}
countedVotedValues.set(numericalVote, countedVotedValues.get(numericalVote)! + 1);
}
});
return countedVotedValues;
}

function standardDeviation(arr: Array<number>, usePopulation = false): number {
const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length;
return Math.sqrt(
arr
.reduce((acc, val) => acc.concat((val - mean) ** 2), [] as Array<number>)
.reduce((acc, val) => acc + val, 0) / (arr.length - (usePopulation ? 0 : 1))
);
}

0 comments on commit ec9e4eb

Please sign in to comment.