// ★★★ 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); }