Files
digital-me-history/digital-me-backend/scripts/probe-gapof.mjs
T
admin 0593ff7e62
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
数字我 Digital Me:全量入库(大文件走 Git LFS)
2026-10-10 16:24:43 +08:00

96 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ★★★ gapOf 的 A/B —— 【它裁决几次?它改变几格?】★ 这是两问,不是一问。
// (先例:南朝的 lex 被【读了 98,304 次、裁决了 81,920 次】,而它【改变 0 格】。
// ⇒ 一个被读了八万次的东西,可以什么都没买到。)
//
// ⚠ 本脚本【自己造两份引擎的副本,跑完自己删】—— 不在 src/ 里留残骸。
// ★ 副本是【整个文件复制 + 改一行】,不是重写一遍逻辑:
// 重写 = 复算 = 拿另一把尺子量,而那比不报更坏(本项目铁律)。
//
// A/B ① 把 nearest 排序里的 `gapOf(a) - gapOf(b) ||` 那一级【整个拿掉】—— 其余一个字未动。
// A/B ② 把 20 道六轴闸【全部改写成它等价类的下端 41】—— ★ 逐格【同一道闸】
// (六轴只取得到 40/63/73/79/83 ⇒ (40,63) 之间没有任何 profile)
// ⇒ 开/关一格都不会变,【只有 gapOf 读得出差别】。
import fs from 'node:fs';
import path from 'node:path';
import url from 'node:url';
const HERE = path.dirname(url.fileURLToPath(import.meta.url));
const SRC = path.join(HERE, '..', 'src', 'dynasties.js');
const NOGAP = path.join(HERE, '..', 'src', '_probe_nogap.js');
const GATE41 = path.join(HERE, '..', 'src', '_probe_gate41.js');
const NEEDLE = ' gapOf(a) - gapOf(b) ||';
const base = fs.readFileSync(SRC, 'utf8');
if (!base.includes(NEEDLE)) {
console.error('✗ 在 dynasties.js 里找不到 gapOf 那一级 —— 引擎变了,这个探针过期了。');
console.error(' ⚠ 而【不许改探针去迁就代码】:先弄清楚那一级去哪了。');
process.exit(1);
}
fs.writeFileSync(NOGAP, base.replace(NEEDLE, ' // [PROBE] gapOf 那一级拿掉了'));
// ★ 只改【六轴】的闸;wang/lao 不是 sat 的产物,它们的数是【真的刻度】,一个字都不许动。
fs.writeFileSync(GATE41, base.replace(/gate: \{([^}]*)\}/g, (m, g) =>
'gate: {' + g.replace(/\b(wen|fa|wu|jiao|heng|tan):\s*(4[1-9]|5\d|6[0-3])\b/g, '$1: 41') + '}'));
try {
const { DYNASTIES, computeRank, computeAxes, AXIS_IDS } = await import('../src/dynasties.js');
const { computeRank: rankNoGap } = await import('../src/_probe_nogap.js');
const { computeRank: rankGate41 } = await import('../src/_probe_gate41.js');
const { chushenOf } = await import('../src/chushen.js');
const { SUB_REGISTRY } = await import('../src/talents.js');
const SUBS = SUB_REGISTRY.map((s) => s.id);
const WANGS = [0, 29, 30, 54, 55, 74, 75, 100];
const m = new Map();
for (let b = 0; b < (1 << 16); b++) {
const s = []; for (let i = 0; i < 16; i++) if (b & (1 << i)) s.push(SUBS[i]);
const a = computeAxes(s); const k = AXIS_IDS.map((x) => a[x]).join(',');
m.set(k, (m.get(k) || 0) + 1);
}
const T = [...m].map(([k, w]) => ({ axes: Object.fromEntries(k.split(',').map((v, i) => [AXIS_IDS[i], Number(v)])), w }));
const CFG = {};
for (const d of DYNASTIES) { const x = chushenOf(d.id); CFG[d.id] = x ? [null, ...x.values.map((v) => v.id)] : [null]; }
const N = (n) => n.toLocaleString();
const pad = (s, n) => { s = String(s); let w = 0; for (const c of s) w += c.charCodeAt(0) > 0x2000 ? 2 : 1; return s + ' '.repeat(Math.max(1, n - w)); };
console.log('\n══ A/B ① 把 gapOf 那一级【整个拿掉】:nearest 变几格?(其余一个字未动)');
console.log('══ A/B ② 20 道六轴闸【全换成等价类下端 41】:★ 逐格【同一道闸】,只有 gapOf 读得出差别\n');
console.log(pad('朝', 8) + pad('出身', 10) + '无路者'.padStart(11) + '① 拿掉 gapOf'.padStart(15) + '② 闸全写 41'.padStart(14));
console.log('─'.repeat(60));
let G1 = 0, G2 = 0;
for (const d of DYNASTIES) for (const cs of CFG[d.id]) {
let noRoad = 0, d1 = 0, d2 = 0;
for (const t of T) for (const wang of WANGS) {
const p = { axes: t.axes, wang, chushen: cs };
const a = computeRank(p, d.id);
if (a.channel) continue;
noRoad += t.w;
const b = rankNoGap(p, d.id), c = rankGate41(p, d.id);
// ★ ② 的前提:闸没变 ⇒「一条路都不开」这件事必须逐格不变。变了就说明我改错了闸。
if (c.channel) throw new Error(`★ ② 改写了开/关 —— 那它就不是同一道闸,本探针的前提塌了(${d.id})`);
if ((a.nearest || '-') !== (b.nearest || '-')) d1 += t.w;
if ((a.nearest || '-') !== (c.nearest || '-')) d2 += t.w;
}
if (!noRoad) continue;
G1 += d1; G2 += d2;
console.log(pad(d.name, 8) + pad(cs || '未答', 10) + N(noRoad).padStart(11) + N(d1).padStart(15) + N(d2).padStart(14));
}
console.log('─'.repeat(60));
console.log(pad('总计', 18) + ''.padStart(11) + N(G1).padStart(15) + N(G2).padStart(14));
console.log(`\n★ ①【拿掉 gapOf ⇒ ${N(G1)} 格换一条路当 nearest】—— 这就是「改判决」的代价(要老板拍)。`);
console.log('★★ 而【拿掉它不会让答案变对】:它只是把【一个假装是测量的仲裁】换成【一个自认是编号的仲裁】。');
console.log(`★ ②【20 道闸全写成 41(逐格同一道闸)⇒ ${N(G2)} 格变】—— ★ 注意它【比 ① 小得多】:`);
console.log(' 全表【一起】换写法,缺口一起缩,相对次序大多不动;');
console.log(' ⇒ ★★【真正翻盘的是【单独】换一道闸的写法】—— 见 scripts/probe-liguang-gate.mjs:');
console.log(' 军功的 wu:55 写成 wu:41(同一道闸)⇒ 李广的 nearest 从【辟召】变成【军功】。');
// ★ 李广:renwu.js 双证 subs=[] ⇒ 六轴全 40。《史記》卷109 双证:他的实职就是靠军功挣的。
const li = { axes: computeAxes([]), wang: 0 };
for (const [nm, fn] of [['真引擎', computeRank], ['① 拿掉 gapOf', rankNoGap], ['② 闸全写 41', rankGate41]]) {
const r = fn(li, 'han');
console.log(`\n★ 李广(subs=[] ⇒ 六轴全 40)/汉 ── ${pad(nm, 14)} nearest =【${r.nearest}】 tie = [${(r.nearestTie || []).join('、')}]`);
}
} finally {
// ⚠ 跑完就删:✗ 不许在 src/ 里留下两份引擎的副本 —— 那是下一个人会 import 错的东西。
for (const f of [NOGAP, GATE41]) if (fs.existsSync(f)) fs.unlinkSync(f);
}