// Code by Dicint const util = require('util'); const _ = require('lodash'); function getEloWinProbability(ra, rb) { return 1.0 / (1 + Math.pow(10, (rb - ra) / 400.0)); } // 传入具体某个人的情况 function getContestantSeed(contestantIndex, allContestants) { let seed = 1; let rating = allContestants[contestantIndex].currentRating; for (let i = 0; i < allContestants.length; i++) { if (contestantIndex != i) { seed += getEloWinProbability(allContestants[i].currentRating, rating); } } return seed; } function getRatingSeed(rating, allContestants) { return 1 + _.sum(allContestants.map(c => getEloWinProbability(c.currentRating, rating))); } function getAverageRank(contestant, allContestants) { const realRank = allContestants[contestant].rank; const expectedRank = getContestantSeed(contestant, allContestants); const average = Math.sqrt(realRank * expectedRank); return average; } function getRatingToRank(contestantIndex, allContestants) { let averageRank = getAverageRank(contestantIndex, allContestants); let left = 1;// contestant.getPrevRating() - 2 * minDelta; let right = 8000;// contestant.getPrevRating() + 2 * maxDelta; while (right - left > 1) { const mid = (left + right) / 2; const seed = getRatingSeed(mid, allContestants); if (seed < averageRank) { right = mid; } else { left = mid; } } return left; } function calculateDeltas(allContestants) { let deltas = []; const numberOfContestants = allContestants.length; for (let i = 0; i < allContestants.length; i++) { const expR = getRatingToRank(i, allContestants); deltas[i] = ((expR - allContestants[i].currentRating) / 2); } // Total sum should not be more than zero. const deltaSum = _.sum(deltas); const inc = -deltaSum / numberOfContestants - 1; deltas = deltas.map(d => d + inc); // Sum of top-4*sqrt should be adjusted to zero. const zeroSumCount = Math.min(Math.trunc(4 * Math.round(Math.sqrt(numberOfContestants))), numberOfContestants); const deltaSum2 = _.sum(deltas.slice(0, zeroSumCount)); const inc2 = Math.min(Math.max(-deltaSum2 / zeroSumCount, -10), 0); deltas = deltas.map(d => d + inc2); return deltas; } module.exports = function(allContestants) { const deltas = calculateDeltas(allContestants); return allContestants.map((contestant, i) => ({ user: contestant.user, rank: contestant.rank, currentRating: contestant.currentRating + deltas[i] })); }