File size: 3,923 Bytes
99f41dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fcf639
 
 
 
 
99f41dc
4fcf639
 
 
 
 
99f41dc
 
 
 
4fcf639
99f41dc
 
 
 
 
 
 
 
 
 
 
 
 
4fcf639
 
99f41dc
 
 
 
 
 
 
 
4fcf639
99f41dc
 
 
 
 
4fcf639
 
 
 
 
 
 
 
 
 
 
 
 
99f41dc
4fcf639
 
 
99f41dc
4fcf639
 
99f41dc
 
 
 
 
 
 
4fcf639
 
99f41dc
 
 
 
 
 
 
 
 
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* compute.js — VADUGWI "Read the Room" scoring.
   Pure, deterministic, no DOM. Sets window.RTR_COMPUTE in browser;
   exports for Node when run under a module loader / test harness. */
(function (root) {
  'use strict';

  // Maps a raw slider answer (-6..+6) to an internal 0..255 value (128 = neutral).
  // Ported from rtr_logic.js: extremes saturate, the center band is compressed so
  // a "0" reads as mild-positive-of-neutral (153), matching the original instrument.
  var SCALE_MAP = {
    '-6': 0, '-5': 0, '-4': 51, '-3': 102, '-2': 128, '-1': 140,
    '0': 153, '1': 166, '2': 179, '3': 204, '4': 230, '5': 255, '6': 255
  };

  var CATS = ['V', 'A', 'D', 'U', 'G', 'W', 'I'];

  function clamp(v) {
    return Math.round(Math.max(0, Math.min(255, v)));
  }

  function meanOf(arr) {
    var s = 0;
    for (var i = 0; i < arr.length; i++) s += arr[i];
    return s / arr.length;
  }

  // All-neutral pool: every probe is a projective scene with an expected-neutral
  // center. There are no NEG/POS tiers anymore, so a dimension is simply how the
  // user COLORS those neutral scenes — the per-cat mean of their internal values.
  // Arousal is the exception: it reads how much neutral scenes MOVE the user
  // (reactivity = mean absolute deviation of raw answers from "doesn't affect me").
  function computeProfile(probes, answers) {
    var byCat = {};
    var i;
    for (i = 0; i < CATS.length; i++) {
      byCat[CATS[i]] = { raw: [], internal: [] };
    }

    var deviations = [];

    for (i = 0; i < probes.length; i++) {
      var p = probes[i];
      var raw = answers[i];
      if (raw === null || raw === undefined) continue;        // unanswered: skip
      if (!byCat[p.cat]) continue;                            // unknown cat: skip
      var internal = SCALE_MAP[String(raw)];
      byCat[p.cat].raw.push(raw);
      byCat[p.cat].internal.push(internal);

      // Every probe is neutral (expected center), so the deviation IS the rating:
      // how strongly / which way the user colored a scene that was meant to be blank.
      deviations.push({
        i: i,
        id: p.id,
        cat: p.cat,
        tier: p.tier,
        text: p.text,
        answer: raw,
        internal: internal,
        dev: raw                                              // signed projective reaction
      });
    }

    deviations.sort(function (a, b) { return Math.abs(b.dev) - Math.abs(a.dev); });

    // Per-dimension projective bias: mean of internal values over that cat's
    // answered probes. Default 128 (true neutral) when none answered.
    function catMean(cat, dflt) {
      var bucket = byCat[cat].internal;
      if (!bucket.length) return dflt;
      return clamp(meanOf(bucket));
    }

    var V = catMean('V', 128);
    var D = catMean('D', 128);
    var G = catMean('G', 128);
    var W = catMean('W', 128);
    var I = catMean('I', 128);

    // U keeps its 0-based axis meaning (Urgency starts at 0/neutral), but is now
    // driven purely by the per-cat mean of the answered U probes; 0 when none.
    var U = catMean('U', 0);

    // A (Arousal) = reactivity = mean ABS deviation of raw answers, mapped 0..255.
    // How much do neutral scenes move you, regardless of which way.
    var aVals = byCat.A.raw, absSum = 0;
    for (i = 0; i < aVals.length; i++) absSum += Math.abs(aVals[i]);
    var avgAbs = aVals.length ? absSum / aVals.length : 0;
    var A = clamp((avgAbs / 6) * 255);

    return {
      V: V, A: A, D: D, U: U, G: G, W: W, I: I,
      byCat: byCat,
      deviations: deviations
    };
  }

  var api = { SCALE_MAP: SCALE_MAP, computeProfile: computeProfile };

  if (typeof window !== 'undefined') window.RTR_COMPUTE = api;
  if (typeof module !== 'undefined' && module.exports) module.exports = api;
  if (typeof root !== 'undefined' && root && !root.RTR_COMPUTE) root.RTR_COMPUTE = api;
})(typeof globalThis !== 'undefined' ? globalThis : this);