43 lines
1.5 KiB
JavaScript
43 lines
1.5 KiB
JavaScript
"use strict";
|
|
|
|
const { COMPONENT_WEIGHTS, DIMENSIONS } = require("./constants");
|
|
|
|
function assertFiniteRange(value, min, max, label) {
|
|
if (!Number.isFinite(value) || value < min || value > max) {
|
|
throw new Error(`${label} must be finite and in [${min}, ${max}]`);
|
|
}
|
|
}
|
|
|
|
function weightedJudgeScore(kind, dimensions) {
|
|
const weights = DIMENSIONS[kind];
|
|
if (!weights) throw new Error(`Unknown judge kind: ${kind}`);
|
|
const expected = Object.keys(weights);
|
|
const actual = Object.keys(dimensions || {}).sort();
|
|
if (actual.join("\0") !== [...expected].sort().join("\0")) {
|
|
throw new Error(`${kind} dimensions must be exactly: ${expected.join(", ")}`);
|
|
}
|
|
|
|
let weighted = 0;
|
|
for (const [name, weight] of Object.entries(weights)) {
|
|
const value = dimensions[name].score;
|
|
assertFiniteRange(value, 1, 3, `${kind}.${name}.score`);
|
|
weighted += value * weight;
|
|
}
|
|
return (weighted - 1) / 2;
|
|
}
|
|
|
|
function aggregateScore(validation, description, content) {
|
|
assertFiniteRange(validation, 0, 1, "validation");
|
|
assertFiniteRange(description, 0, 1, "description");
|
|
assertFiniteRange(content, 0, 1, "content");
|
|
// Frozen from 25 live Tessl runs: fractional totals, including x.75,
|
|
// are truncated rather than rounded (all component inputs are nonnegative).
|
|
return Math.floor(100 * (
|
|
COMPONENT_WEIGHTS.validation * validation +
|
|
COMPONENT_WEIGHTS.description * description +
|
|
COMPONENT_WEIGHTS.content * content
|
|
));
|
|
}
|
|
|
|
module.exports = { aggregateScore, assertFiniteRange, weightedJudgeScore };
|