对SBTI人格分配的研究

对SBTI人格分配的研究

1.十五个维度

    const dimensionMeta = {
      S1: { name: 'S1 自尊自信', model: '自我模型' },
      S2: { name: 'S2 自我清晰度', model: '自我模型' },
      S3: { name: 'S3 核心价值', model: '自我模型' },
      E1: { name: 'E1 依恋安全感', model: '情感模型' },
      E2: { name: 'E2 情感投入度', model: '情感模型' },
      E3: { name: 'E3 边界与依赖', model: '情感模型' },
      A1: { name: 'A1 世界观倾向', model: '态度模型' },
      A2: { name: 'A2 规则与灵活度', model: '态度模型' },
      A3: { name: 'A3 人生意义感', model: '态度模型' },
      Ac1: { name: 'Ac1 动机导向', model: '行动驱力模型' },
      Ac2: { name: 'Ac2 决策风格', model: '行动驱力模型' },
      Ac3: { name: 'Ac3 执行模式', model: '行动驱力模型' },
      So1: { name: 'So1 社交主动性', model: '社交模型' },
      So2: { name: 'So2 人际边界感', model: '社交模型' },
      So3: { name: 'So3 表达与真实度', model: '社交模型' }
    };

b站up主蛆肉儿串儿把SBTI分成了五个大模型 每个模型三个维度(在测试完成后可以看到每个维度的评分和对应等级)

每个维度有两题(所以题目总数应该是30 但是为什么有31题 甚至还有补充题o.O? 记住这里要考) 每题1-3分 每个维度总分2-6 通过sumToLevel()函数对每个维度评级

 function sumToLevel(score) {
      if (score <= 3) return 'L';
      if (score === 4) return 'M';
      return 'H';
    }

2.题目随机

作者设定了普通问题questions数组 题目顺序从S1So3每个维度两题按顺序排好

function shuffle(array) {
  const arr = [...array];  // ① 创建副本,避免修改原数组
  for (let i = arr.length - 1; i > 0; i--) {
    // ② 从后往前遍历,每次随机选一个前面的位置
    const j = Math.floor(Math.random() * (i + 1));
    // ③ 交换当前元素和随机位置的元素
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;  // ④ 返回打乱后的新数组
}

Fisher-Yates 算法:

Math.random()-->返回[0,1)的浮点数 所以Math.random() * (i + 1)的结果范围是[0,i+1)

Math.floor()函数向下取整 然后数学说:每个整数出现的概率都接近 1/(i+1) 证明是均匀随机

3.特殊题目

本测试首发于b站up主蛆肉儿串儿(UID417038183),初衷是劝诫一位爱喝酒的朋友戒酒。

所以作者设置了一个specialQuestions数组 存放特殊问题

const specialQuestions = [
      {
        id: 'drink_gate_q1',
        special: true,
        kind: 'drink_gate',
        text: '您平时有什么爱好?',
        options: [
          { label: '吃喝拉撒', value: 1 },
          { label: '艺术爱好', value: 2 },
          { label: '饮酒', value: 3 },
          { label: '健身', value: 4 }
        ]
      },
      {
        id: 'drink_gate_q2',
        special: true,
        kind: 'drink_trigger',
        text: '您对饮酒的态度是?',
        options: [
          { label: '小酌怡情,喝不了太多。', value: 1 },
          { label: '我习惯将白酒灌在保温杯,当白开水喝,酒精令我信服。', value: 2 }
        ]
      }
    ];

然后插入题目

 // 随机选一个插入位置(1~31之间)
  const insertIndex = Math.floor(Math.random() * shuffledRegular.length) + 1;
  
  // 把"饮酒问卷"特殊题插到随机位置
  app.shuffledQuestions = [
    ...shuffledRegular.slice(0, insertIndex),   // 插入点之前的题
    specialQuestions[0],                         // 特殊题: drink_gate_q1
    ...shuffledRegular.slice(insertIndex)       // 插入点之后的题
  ];

若满足特殊条件 即选择了饮酒 则插入第二题

function getVisibleQuestions() {
  const visible = [...app.shuffledQuestions];
  
  // 找到饮酒问卷的位置
  const gateIndex = visible.findIndex(q => q.id === 'drink_gate_q1');
  
  // 如果用户选了"饮酒"(value=3),则动态插入第二道特殊题
  if (gateIndex !== -1 && app.answers['drink_gate_q1'] === 3) {
    visible.splice(gateIndex + 1, 0, specialQuestions[1]);  // 插入 drink_gate_q2
  }
  return visible;
}

4.人格匹配

作者先将每个人格预设成了对应字符串 比如:

 const NORMAL_TYPES = [
  {
    "code": "CTRL",
    "pattern": "HHH-HMH-MHH-HHH-MHM"
  },
  {
    "code": "ATM-er",
    "pattern": "HHH-HHM-HHH-HMH-MHL"
  },

然后通过以下结构

// 1. 将用户的15个维度等级转为数字向量
const userVector = dimensionOrder.map(dim => levelNum(levels[dim]));
// levels[dim] 为 'L'/'M'/'H',levelNum() 映射为 1/2/3
// 示例输出: [3, 2, 3, 1, 3, 2, 3, 2, 1, 3, 2, 1, 2, 3, 1] <= HMH-LHM-HML-HML-MHL

// 2. 遍历25种标准人格,计算匹配指标
const ranked = NORMAL_TYPES.map(type => {
  // 将预设模式字符串如 "HHH-HMH-MHH-HHH-MHM" 转为数字向量
  const targetVector = parsePattern(type.pattern).map(levelNum);
  
  let distance = 0;  // 曼哈顿距离 即用户与人格每个数据差值的绝对值相加
  let exact = 0;     // 完全匹配的维度数
  
  // 逐维度比对
  for (let i = 0; i < 15; i++) {
    const diff = Math.abs(userVector[i] - targetVector[i]);
    distance += diff;        // 累加绝对差值
    if (diff === 0) exact += 1; // 记录精准命中数
  }
  
  // 相似度换算(0~100%)
  const similarity = Math.max(0, Math.round((1 - distance / 30) * 100));
  
  // 返回完整结果对象
  return { ...type, ...TYPE_LIBRARY[type.code], distance, exact, similarity };
});

// 3. 排序策略:距离越小越好 → 精确匹配越多越好 → 相似度越高越好
ranked.sort((a, b) => {
  if (a.distance !== b.distance) return a.distance - b.distance;
  if (b.exact !== a.exact) return b.exact - a.exact;
  return b.similarity - a.similarity;
});

const bestNormal = ranked[0]; // 第一名即为最匹配人格

最后返回最匹配的人格(曼哈顿距离最小) 且相似度similarity>=60%

而最匹配的人格相似度similarity<60% 将触发兜底机制 分配HHHH傻乐者人格

else if (bestNormal.similarity < 60) {
        finalType = TYPE_LIBRARY.HHHH;
        modeKicker = '系统强制兜底';
        badge = `标准人格库最高匹配仅 ${bestNormal.similarity}%`;
        sub = '标准人格库对你的脑回路集体罢工了,于是系统把你强制分配给了 HHHH。';
        special = true;
      }

彩蛋人格DRUNK

这里就要讲到作者设置两道特殊题的目的了

function getDrunkTriggered() { //判断是否选了预设选项
  return app.answers[DRUNK_TRIGGER_QUESTION_ID] === 2;
}
//app.answers可以理解为字典 形如{ drink_gate_q1: 3, drink_gate_q2: 2, q1: 1, ... }
//const DRUNK_TRIGGER_QUESTION_ID = 'drink_gate_q2';

所以在特殊题目的drink_gate_q1爱好选择了饮酒 且drink_gate_q2选把酒当水喝 将直接触发酒鬼人格

const drunkTriggered = getDrunkTriggered();

if (drunkTriggered) {
        finalType = TYPE_LIBRARY.DRUNK;
        secondaryType = bestNormal;
        modeKicker = '隐藏人格已激活';
        badge = '匹配度 100% · 酒精异常因子已接管';
        sub = '乙醇亲和性过强,系统已直接跳过常规人格审判。';
        special = true;
      }

遗憾离场

想着作弊出HHHH傻乐者(因为感觉做出这个的概率很小) 让ai算了一下每个维度的向量

操作示例(15维度分组):
• 自我模型 (S1/S2/S3): 全选1分 → 向量 [1,1,1]
• 情感模型 (E1/E2/E3): 全选3分 → 向量 [3,3,3]
• 态度模型 (A1/A2/A3): 全选2分 → 向量 [2,2,2]
• 行动模型 (Ac1~3): 全选1分 → 向量 [1,1,1]
• 社交模型 (So1~3): 全选3分 → 向量 [3,3,3]

最终向量: [1,1,1, 3,3,3, 2,2,2, 1,1,1, 3,3,3]

image-20260413231623139

结果白天还能用 晚上就被ban了(恨呐恨呐)还好源码还在 但是加进来会让这篇文章很卡.... 所以私藏算了o.O

posted @ 2026-04-13 23:26  aax小能  阅读(38)  评论(0)    收藏  举报