96 lines
6.2 KiB
JavaScript
96 lines
6.2 KiB
JavaScript
// ★★★ 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);
|
||
}
|