数字我 Digital Me:全量入库(大文件走 Git LFS)
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
This commit is contained in:
@@ -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)}`);
|
||||
}
|
||||
Reference in New Issue
Block a user