diff --git a/frontend/src/app/game/game/agreement.ts b/frontend/src/app/game/game/agreement.ts index bed62c3..fefa458 100644 --- a/frontend/src/app/game/game/agreement.ts +++ b/frontend/src/app/game/game/agreement.ts @@ -1,49 +1,25 @@ import {Vote} from "../model"; - -interface VotedValue { - card: number; - totalVotes: number; +export function calculateAgreement(votes: Array): 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): 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): Map { - const countedVotedValues = new Map(); - 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, 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) - .reduce((acc, val) => acc + val, 0) / (arr.length - (usePopulation ? 0 : 1)) - ); -}