Files
digital-me-history/digital-me-backend/scripts/census-zelu.mjs
T
admin 0593ff7e62
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
数字我 Digital Me:全量入库(大文件走 Git LFS)
2026-10-10 16:24:43 +08:00

78 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ★ 第二刀的验收读数:【打平的那些 case,tier 和 ceiling 真的都一样吗?】
// 老板逐字:「⚠ 验证我这个判断:穷举里,打平的那些 case,tier 和 ceiling 真的都一样吗?
// 有没有「tier 一样但 ceiling 不一样」的?那种不是打平,那种引擎有理由(位阶即杠杆)。
// 跑出来,别信我。」
// ⚠ 读数全部出自引擎自己的 r.kai(产物),不是复算。
import { DYNASTIES, computeRank, computeAxes } from '../src/dynasties.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];
// 每一条【开着但没走】的路,按 (tier 关系, ceiling 关系) × lostAt 交叉列表
const X = {}; // key: `${tierRel}|${ceilRel}` → { lostAt: n }
const bump = (tr, cr, lostAt) => {
const k = `${tr}|${cr}`;
(X[k] || (X[k] = {}))[lostAt] = ((X[k] || {})[lostAt] || 0) + 1;
};
// zelu.options 的自检
let optBad = 0, optN = 0, optTierDiff = 0, optCeilDiff = 0;
// 引擎的排序器是不是一个自洽的全序:ranked[i] 必须真的赢 ranked[j] (i<j)
let sortViol = 0;
// 「tier 一样 && ceiling 一样」的总条次,按 lostAt 分
const SAME = {};
let totalNotWalked = 0;
const t0 = Date.now();
for (let m = 0; m < (1 << 16); m++) {
const subs = []; for (let i = 0; i < 16; i++) if (m & (1 << i)) subs.push(SUBS[i]);
const axes = computeAxes(subs);
for (const wang of WANGS) for (const d of DYNASTIES) {
const r = computeRank({ axes, wang }, d.id);
if (!r.channel) continue;
const walked = r.kai.find((k) => k.walked);
for (const k of r.kai) {
if (k.walked) continue;
totalNotWalked++;
const tr = k.tier === walked.tier ? '=' : k.tier < walked.tier ? '<' : '>';
const cr = k.ceiling === walked.ceiling ? '=' : k.ceiling < walked.ceiling ? '<' : '>';
bump(tr, cr, k.lostAt);
if (tr === '=' && cr === '=') SAME[k.lostAt] = (SAME[k.lostAt] || 0) + 1;
}
// zelu.tie:里面的每一条,tier 与 ceiling 必须与走的那条【全部相同】
const opts = (r.zelu.tie || []).map((t) => t.channelId);
if (opts.length > 1) {
optN++;
for (const id of opts) {
const k = r.kai.find((x) => x.channelId === id);
if (!k) { optBad++; continue; }
if (k.tier !== walked.tier) optTierDiff++;
if (k.ceiling !== walked.ceiling) optCeilDiff++;
}
}
// 排序自洽性:kai 的次序就是 ranked 的次序
for (let i = 0; i < r.kai.length; i++)
for (let j = i + 1; j < r.kai.length; j++)
if (r.kai[j].tier > r.kai[i].tier ||
(r.kai[j].tier === r.kai[i].tier && r.kai[j].ceiling > r.kai[i].ceiling)) sortViol++;
}
}
const secs = ((Date.now() - t0) / 1000).toFixed(0);
const N = (n) => n.toLocaleString();
console.log(`\n══ 【开着但没走】的路:(tier, ceiling) × 输在哪一级 ── ${N(totalNotWalked)} 条次 / ${secs}s ══\n`);
console.log('tier ceiling │ ' + ['ceiling', 'tier', 'lex', 'idx', 'unsorted'].map((s) => s.padStart(10)).join('') + ' 合计');
console.log('─'.repeat(78));
for (const key of Object.keys(X).sort()) {
const [tr, cr] = key.split('|');
const row = X[key];
const tot = Object.values(row).reduce((a, b) => a + b, 0);
console.log(` ${tr} ${cr} │ ` +
['ceiling', 'tier', 'lex', 'idx', 'unsorted'].map((s) => N(row[s] || 0).padStart(10)).join('') +
' ' + N(tot).padStart(10));
}
console.log('\n★ 【tier 一样 && ceiling 一样】的条次,按输在哪一级分:');
const sameTot = Object.values(SAME).reduce((a, b) => a + b, 0);
for (const k of Object.keys(SAME)) console.log(` ${k.padEnd(10)} ${N(SAME[k]).padStart(11)} (${(SAME[k] / sameTot * 100).toFixed(1)}% of ${N(sameTot)})`);
console.log(`\n★ zelu.options:${N(optN)} 格有 >1 个选项;` +
`其中 tier 不同 ${N(optTierDiff)} 次、ceiling 不同 ${N(optCeilDiff)} 次、kai 里找不到 ${N(optBad)} 次`);
console.log(`★ 排序自洽性(kai 次序里出现「后面的 tier/ceiling 反而更高」):${N(sortViol)} 次`);