Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ranking System v1 #960

Closed
wants to merge 11 commits into from
82 changes: 22 additions & 60 deletions src/calculateRank.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
// https://stackoverflow.com/a/5263759/10629172
function normalcdf(mean, sigma, to) {
var z = (to - mean) / Math.sqrt(2 * sigma * sigma);
var t = 1 / (1 + 0.3275911 * Math.abs(z));
var a1 = 0.254829592;
var a2 = -0.284496736;
var a3 = 1.421413741;
var a4 = -1.453152027;
var a5 = 1.061405429;
var erf =
1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-z * z);
var sign = 1;
if (z < 0) {
sign = -1;
}
return (1 / 2) * (1 + sign * erf);
function expsf(lambda, x) {
return Math.exp(-lambda * x);
}

function calculateRank({
Expand All @@ -25,65 +11,41 @@ function calculateRank({
issues,
stargazers,
}) {
const COMMITS_OFFSET = 1.65;
const CONTRIBS_OFFSET = 1.65;
const ISSUES_OFFSET = 1;
const STARS_OFFSET = 0.75;
const PRS_OFFSET = 0.5;
const FOLLOWERS_OFFSET = 0.45;
const REPO_OFFSET = 1;

const ALL_OFFSETS =
CONTRIBS_OFFSET +
ISSUES_OFFSET +
STARS_OFFSET +
PRS_OFFSET +
FOLLOWERS_OFFSET +
REPO_OFFSET;
// value of statistics should be equal to 1 / <average number per user> (see https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments_and_median)
const COMMITS_LAMBDA = 1 / 10000;
const CONTRIBS_LAMBDA = 1 / 1000;
const ISSUES_LAMBDA = 1 / 100;
const STARS_LAMBDA = 1 / 400;
const PRS_LAMBDA = 1 / 300;
const FOLLOWERS_LAMBDA = 1 / 100;
const REPO_LAMBDA = 1 / 20;

const RANK_S_VALUE = 1;
const RANK_DOUBLE_A_VALUE = 25;
const RANK_A2_VALUE = 45;
const RANK_A3_VALUE = 60;
const RANK_B_VALUE = 100;

const TOTAL_VALUES =
RANK_S_VALUE + RANK_A2_VALUE + RANK_A3_VALUE + RANK_B_VALUE;

// prettier-ignore
const score = (
totalCommits * COMMITS_OFFSET +
contributions * CONTRIBS_OFFSET +
issues * ISSUES_OFFSET +
stargazers * STARS_OFFSET +
prs * PRS_OFFSET +
followers * FOLLOWERS_OFFSET +
totalRepos * REPO_OFFSET
) / 100;

const normalizedScore = normalcdf(score, TOTAL_VALUES, ALL_OFFSETS) * 100;
const normalizedScore = 700 / (
1 / expsf(COMMITS_LAMBDA, totalCommits) +
1 / expsf(CONTRIBS_LAMBDA, contributions) +
1 / expsf(ISSUES_LAMBDA, issues) +
1 / expsf(STARS_LAMBDA, stargazers) +
1 / expsf(PRS_LAMBDA, prs) +
1 / expsf(FOLLOWERS_LAMBDA, followers) +
1 / expsf(REPO_LAMBDA, totalRepos))

let level = "";

if (normalizedScore < RANK_S_VALUE) {
level = "S+";
}
if (
normalizedScore >= RANK_S_VALUE &&
normalizedScore < RANK_DOUBLE_A_VALUE
) {
} else if (normalizedScore < RANK_DOUBLE_A_VALUE) {
level = "S";
}
if (
normalizedScore >= RANK_DOUBLE_A_VALUE &&
normalizedScore < RANK_A2_VALUE
) {
} else if (normalizedScore < RANK_A2_VALUE) {
level = "A++";
}
if (normalizedScore >= RANK_A2_VALUE && normalizedScore < RANK_A3_VALUE) {
} else if (normalizedScore < RANK_A3_VALUE) {
level = "A+";
}
if (normalizedScore >= RANK_A3_VALUE && normalizedScore < RANK_B_VALUE) {
} else {
level = "B+";
}

Expand Down
30 changes: 29 additions & 1 deletion tests/calculateRank.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,34 @@ describe("Test calculateRank", () => {
prs: 300,
issues: 200,
}),
).toStrictEqual({ level: "A+", score: 49.16605417270399 });
).toStrictEqual({ level: "A++", score: 37.035320318128086 });
});

it("new user gets B+ rank", () => {
expect(
calculateRank({
totalCommits: 0,
totalRepos: 0,
followers: 0,
contributions: 0,
stargazers: 0,
prs: 0,
issues: 0,
}),
).toStrictEqual({ level: "B+", score: 100 });
});

it("Linus Torvalds gets S+ rank", () => {
expect(
calculateRank({
totalCommits: 2700,
totalRepos: 2,
followers: 132000,
contributions: 2700,
stargazers: 109100,
prs: 71,
issues: 2,
}),
).toStrictEqual({ level: "S+", score: 0 });
});
});