File size: 1,977 Bytes
b324c71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
"""
Re-scores a Business Strength Archetype submission on the server, so what we
store never depends on numbers the browser sent. Mirrors lib/bsa/score.ts; the
question bank comes from questions.json, built by scripts/bsa/build_content.py.
"""

import json
import math
from pathlib import Path

_DATA = json.loads((Path(__file__).resolve().parent / "questions.json").read_text(encoding="utf-8"))
ORDER: list[str] = _DATA["order"]
STAGES: list[str] = _DATA["stages"]
AGES: list[str] = _DATA["ages"]
QUESTIONS: dict[int, dict] = {q["id"]: q for q in _DATA["questions"]}


def percentages(raw: dict[str, int]) -> dict[str, int]:
    """Whole percentages that add up to 100 (largest remainder method)."""
    total = sum(raw.values()) or 1
    exact = [raw[d] / total * 100 for d in ORDER]
    pct = [math.floor(e) for e in exact]
    order = sorted(range(len(ORDER)), key=lambda i: (-(exact[i] - pct[i]), i))
    for i in order[: 100 - sum(pct)]:
        pct[i] += 1
    return dict(zip(ORDER, pct))


def score(answers: dict[int, str]) -> dict:
    """answers: question id → strength picked. Raises ValueError if any answer is impossible."""
    if set(answers) != set(QUESTIONS):
        raise ValueError(f"Expected answers to all {len(QUESTIONS)} questions.")
    raw = {d: 0 for d in ORDER}
    fit = {d: 0 for d in ORDER}
    for qid, dim in answers.items():
        q = QUESTIONS[qid]
        if dim not in q["dims"]:
            raise ValueError(f"Question {qid} has no option for {dim}.")
        raw[dim] += 1
        if dim == q["naturalFit"]:
            fit[dim] += 1
    ranked = sorted(ORDER, key=lambda d: (-raw[d], -fit[d], ORDER.index(d)))
    primary, secondary = ranked[0], ranked[1]
    pair = sorted([primary, secondary], key=ORDER.index)
    return {
        "raw": raw,
        "pct": percentages(raw),
        "primary": primary,
        "secondary": secondary,
        "lowest": [ranked[6], ranked[5]],
        "blendKey": f"{pair[0]}-{pair[1]}",
    }