// ★★★★★ 2026-07-17 第三刀:【gapOf —— 「排在后面 ≠ 不参选」这一族的第八次】 // // 【机理,先说死,它是算术,不是史学】 // 六轴的取值是 sat() 饱和曲线的产物,【只有五个值】:40 / 63 / 73 / 79 / 83(本刀实测)。 // ⇒ (40,63] 之间【没有任何一个 profile 落得进去】。 // ⇒ 【gate{wu:41} 与 gate{wu:55} 与 gate{wu:63} 是【同一道闸】】—— 开/关逐格相同,零例外。 // ★ 即:55 这个数【作为闸是一个空操作】—— 本文件自己也这么说: // 「因此 gate 的口径是:55 ≈「这条轴上至少点过一项」,70 ≈「至少两项」。」 // ⇒ ★★【它自陈是一个【代号】,不是一个刻度。】 // // 【而它在另一个地方【被当成刻度读了】】 // `gapOf(t) = Math.max(...t.missing.map((m) => m.need - m.got))` // ⇒ 【need − got】。★ need 是一个代号,got 是一个曲线的产物 —— 两者相减【不是一段距离】。 // ⇒ 而 nearest 的第二级就是拿它排的。⇒ 【一个自陈是代号的数,在暗处裁决了「你离哪条路最近」。】 // // 本 census 分三问,逐问都拿引擎自己的产物答: // ① 【同一道闸的那几个数,开/关变几格?】(应为 0 —— 若不为 0,我上面的机理是错的) // ② 【而它们让 nearest 变几格?】 // ③ 【gapOf 裁决的时候,比的是不是同一条轴?】(同 lexCompare 的那一问,实测同轴 0 次) import { DYNASTIES, computeRank, computeAxes, AXIS_IDS } from '../src/dynasties.js'; import { chushenOf } from '../src/chushen.js'; import { SUB_REGISTRY } from '../src/talents.js'; const SUBS = SUB_REGISTRY.map((s) => s.id); const WANGS = [0, 29, 30, 54, 55, 74, 75, 100]; const TUPLES = (() => { const m = new Map(); for (let b = 0; b < (1 << 16); b++) { const subs = []; for (let i = 0; i < 16; i++) if (b & (1 << i)) subs.push(SUBS[i]); const a = computeAxes(subs); m.set(AXIS_IDS.map((x) => a[x]).join(','), (m.get(AXIS_IDS.map((x) => a[x]).join(',')) || 0) + 1); } return [...m].map(([k, w]) => ({ axes: Object.fromEntries(k.split(',').map((v, i) => [AXIS_IDS[i], Number(v)])), w })); })(); const CONFIGS = {}; for (const d of DYNASTIES) { const dim = chushenOf(d.id); CONFIGS[d.id] = dim ? [null, ...dim.values.map((v) => v.id)] : [null]; } const N = (n) => n.toLocaleString(); const pad = (s, n) => { s = String(s); let w = 0; for (const ch of s) w += ch.charCodeAt(0) > 0x2000 ? 2 : 1; return s + ' '.repeat(Math.max(1, n - w)); }; // ★ 六轴的全部可能取值 —— 让引擎自己报,不许我手写 const VALS = {}; for (const a of AXIS_IDS) VALS[a] = [...new Set(TUPLES.map((t) => t.axes[a]))].sort((x, y) => x - y); console.log('══ ① 六轴的取值:sat() 曲线只给得出这几个数 ══'); for (const a of AXIS_IDS) console.log(` ${pad(a, 6)} ${VALS[a].join(' ')}`); // 一道闸 need=d 的【等价类】:所有让「开/关」逐格相同的整数 n const classOf = (axis, d) => { const vs = VALS[axis]; const passes = (n) => vs.filter((v) => v >= n).join(','); const me = passes(d); const out = []; for (let n = 1; n <= 100; n++) if (passes(n) === me) out.push(n); return out; }; console.log('\n══ ② 每一道六轴闸的【等价类】—— 类里的任何一个数,是【同一道闸】 ══'); console.log(pad('闸', 34) + pad('等价类(这些数【是同一道闸】)', 34) + '类的大小'); console.log('─'.repeat(84)); const GATES = []; for (const d of DYNASTIES) for (const c of d.channels) for (const [k, need] of Object.entries(c.gate || {})) { if (k === 'wang' || k === 'lao') continue; // wang 是 0–100 的自由值,不是 sat 的产物 ⇒ 它的数是真的 const cls = classOf(k, need); GATES.push({ d, c, k, need, cls }); console.log(pad(`${d.id}/${c.id} gate{${k}:${need}}`, 34) + pad(`${cls[0]}–${cls[cls.length - 1]}`, 34) + cls.length); } // ── 跑:把每一道闸换成它等价类里的每一个端点,看【开/关】与【nearest】各变几格 console.log('\n══ ③ 换成等价类里的另一个数:【开/关】变几格?【nearest】变几格? ══'); console.log(pad('闸 → 换成', 40) + '开/关变'.padStart(10) + 'nearest 变'.padStart(12) + ' ★'); console.log('─'.repeat(72)); const scan = (dynId, cs) => { const out = []; for (const t of TUPLES) for (const wang of WANGS) { const r = computeRank({ axes: t.axes, wang, chushen: cs }, dynId); // 【开/关】= 哪几条路对你开着(引擎自己的 kai + blocked) const gates = r.kai.map((k) => k.channelId).sort().join(',') + '#' + r.blocked.map((b) => b.channel).sort().join(','); out.push({ w: t.w, gates, near: r.nearest || '-' }); } return out; }; const BASE = {}; for (const d of DYNASTIES) for (const cs of CONFIGS[d.id]) BASE[`${d.id}|${cs}`] = scan(d.id, cs); let deadGate = 0, movedNear = 0; for (const g of GATES) { for (const alt of [g.cls[0], g.cls[g.cls.length - 1]]) { if (alt === g.need) continue; const old = g.c.gate[g.k]; g.c.gate[g.k] = alt; let dg = 0, dn = 0; for (const cs of CONFIGS[g.d.id]) { const b = BASE[`${g.d.id}|${cs}`], now = scan(g.d.id, cs); for (let i = 0; i < b.length; i++) { if (b[i].gates !== now[i].gates) dg += b[i].w; if (b[i].near !== now[i].near) dn += b[i].w; } } g.c.gate[g.k] = old; if (dg === 0) deadGate++; if (dn > 0) movedNear += dn; console.log(pad(`${g.d.id}/${g.c.id} {${g.k}:${g.need}→${alt}}`, 40) + N(dg).padStart(10) + N(dn).padStart(12) + ' ' + (dg === 0 ? '★ 同一道闸(0 格)' : '⚠ 不是同一道闸!') + (dn > 0 ? ' ★★ 而 nearest 变了' : '')); } } console.log(`\n★★★【${deadGate} 处:换个数,开/关一格都不动 —— 它作为闸是空操作】`); console.log(`★★★【而 nearest 一共变了 ${N(movedNear)} 格 —— 那个空操作在暗处裁决了「你离哪条路最近」】`); // ── ④ gapOf 裁决的时候,比的是不是同一条轴? console.log('\n══ ④ 【无路者】那一支:nearest 是谁判的?gapOf 比的是不是同一条轴? ══'); const gapOf = (ms) => (ms.length ? Math.max(...ms.map((m) => m.need - m.got)) : 0); const worstAxis = (ms) => { let b = null; for (const m of ms) if (!b || m.need - m.got > b.need - b.got) b = m; return b; }; for (const d of DYNASTIES) for (const cs of CONFIGS[d.id]) { const S = { noRoad: 0, byCount: 0, byGap: 0, byIdx: 0, gapSameAxis: 0, gapCrossAxis: 0 }; const pairs = new Map(); for (const t of TUPLES) for (const wang of WANGS) { const r = computeRank({ axes: t.axes, wang, chushen: cs }, d.id); if (r.channel) continue; S.noRoad += t.w; if (!r.nearest) continue; // 复算这一支的三级(★ 与 computeRank 的 sort 逐字同源),只为回答「是哪一级判的」 const dd = DYNASTIES.find((x) => x.id === d.id); const rows = []; dd.channels.forEach((c, idx) => { const val = (k) => (k === 'wang' ? wang : t.axes[k]); const ms = Object.entries(c.gate || {}).filter(([k, n]) => val(k) < n).map(([k, n]) => ({ axis: k, need: n, got: Math.round(val(k)) })); rows.push({ name: c.name, ms, idx }); }); const pool = rows.filter((x) => r.blocked.some((b) => b.channel === x.name) && !r.blocked.find((b) => b.channel === x.name).byChushen); if (pool.length < 2) continue; const win = pool.find((x) => x.name === r.nearest); if (!win) continue; const rivals = pool.filter((x) => x !== win); if (rivals.every((x) => x.ms.length > win.ms.length)) { S.byCount += t.w; continue; } const same = rivals.filter((x) => x.ms.length === win.ms.length); if (same.every((x) => gapOf(x.ms) > gapOf(win.ms))) { S.byGap += t.w; for (const x of same) { const a = worstAxis(win.ms), b = worstAxis(x.ms); if (a && b) { if (a.axis === b.axis) S.gapSameAxis += t.w; else { S.gapCrossAxis += t.w; const k = `${a.axis}(差${a.need - a.got}) vs ${b.axis}(差${b.need - b.got})`; pairs.set(k, (pairs.get(k) || 0) + t.w); } } } continue; } if (same.some((x) => gapOf(x.ms) === gapOf(win.ms))) S.byIdx += t.w; } if (!S.noRoad) continue; console.log(`\n── ${d.name}(chushen=${cs || '未答'})一条路都不开:${N(S.noRoad)} 格`); console.log(` nearest 由【差几条】判:${N(S.byCount)} 由【gapOf 缺口】判:${N(S.byGap)} 由【本表的编号】判:${N(S.byIdx)}`); if (S.byGap) console.log(` ★ gapOf 裁决时:【同轴 ${N(S.gapSameAxis)} 次】/【跨轴 ${N(S.gapCrossAxis)} 次】`); for (const [k, v] of [...pairs].sort((a, b) => b[1] - a[1]).slice(0, 5)) console.log(` ${pad(k, 40)} ${N(v)}`); }