数字我 Digital Me:全量入库(大文件走 Git LFS)
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s

This commit is contained in:
2026-10-10 16:24:43 +08:00
commit 0593ff7e62
1893 changed files with 361723 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
// ★★★★★ 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)}`);
}