feat: 新增3个思想实验室项目,完善私有剪贴板授权与上传功能,添加配套测试脚本

1. 新增怀旧弹珠台、人性与投资、穿越三体、四维空间四个思想实验室项目
2. 为私有剪贴板添加业务层授权校验,优化上传进度显示与鉴权失败处理
3. 新增多个调试与单元测试脚本,覆盖三体积分、弹珠台物理、集成测试等场景
4. 补全穿越三体项目的完整HTML页面资源
This commit is contained in:
yangxiangyuan
2026-08-07 17:49:24 +08:00
parent 0f8fe2c2e2
commit 4492b4106a
22 changed files with 6935 additions and 34 deletions
@@ -0,0 +1,53 @@
// ============================================================
// test_three_body_integrator.js - 穿越三体 · 三体积分器校验
// 从 public/tools/thought_lab/labs/three_body_journey/index.html 抽取
// THREEBODY_MATH_BEGIN/END 之间的纯物理代码执行校验(测试对象 = 上线代码)。
// 校验:RK4 积分动量守恒、能量漂移极小、加速度满足牛顿第三定律对称性。
// 运行:node dev_test_scripts/unit/test_three_body_integrator.js
// ============================================================
'use strict'
const fs = require('fs')
const path = require('path')
const vm = require('vm')
const HTML = path.resolve(__dirname, '..', '..', 'public', 'tools', 'thought_lab', 'labs', 'three_body_journey', 'index.html')
const src = fs.readFileSync(HTML, 'utf8')
const m = src.match(/\/\/ ==== THREEBODY_MATH_BEGIN ====\n([\s\S]*?)\/\/ ==== THREEBODY_MATH_END ====/)
if (!m) { console.error('FAIL - 未找到 THREEBODY_MATH 标记块'); process.exit(1) }
const api = vm.runInNewContext(m[1] + ';({ tbAccel, tbStep, tbEnergy, tbMomentum })')
let pass = 0, fail = 0
const check = (name, cond) => {
if (cond) { pass++; console.log('PASS -', name) }
else { fail++; console.log('FAIL -', name) }
}
const masses = [1, 1, 1]
const eps2 = 0.02
let pos = [1, 0, -0.5, Math.sqrt(3) / 2, -0.5, -Math.sqrt(3) / 2]
let vel = [0, 0.42, -0.38, -0.2, 0.38, -0.22]
// 牛顿第三定律:Σ mᵢaᵢ = 0(作用力反作用力,任意位形)
{
const ms = [1, 2, 0.5]
const a = api.tbAccel([0, 0, 1, 0.3, -0.7, 1.2], ms, 0)
let sx = 0, sy = 0
for (let i = 0; i < 3; i++) { sx += ms[i] * a[2 * i]; sy += ms[i] * a[2 * i + 1] }
check('Σ mᵢaᵢ = 0(作用反作用)', Math.abs(sx) < 1e-12 && Math.abs(sy) < 1e-12)
}
// 动量守恒:跑 5000 步
const p0 = api.tbMomentum(vel, masses)
const E0 = api.tbEnergy(pos, vel, masses, eps2)
for (let i = 0; i < 5000; i++) [pos, vel] = api.tbStep(pos, vel, masses, 0.002, eps2)
const p1 = api.tbMomentum(vel, masses)
const E1 = api.tbEnergy(pos, vel, masses, eps2)
check('动量守恒(5000 步,|Δp|<1e-9)', Math.abs(p1[0] - p0[0]) < 1e-9 && Math.abs(p1[1] - p0[1]) < 1e-9)
check(`能量漂移小(|ΔE/E0|<1e-3,实际 ${Math.abs((E1 - E0) / E0).toExponential(2)})`, Math.abs((E1 - E0) / E0) < 1e-3)
// 有限性:5000 步后位置/速度均为有限数(软化避免奇点崩溃)
check('积分稳定(全部有限)', [...pos, ...vel].every(Number.isFinite))
console.log(fail === 0 ? `ALL PASS (${pass})` : `FAILED: ${fail} / ${pass + fail}`)
process.exit(fail === 0 ? 0 : 1)