初始提交:三玩法 Web 原型与设计文档

- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试
- 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本
- 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试
- 产品文档、UI 设计规范、各玩法 GDD / HANDOFF
- 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
This commit is contained in:
cabinw
2026-09-16 14:30:59 +08:00
commit 8026e4628d
169 changed files with 22162 additions and 0 deletions
@@ -0,0 +1,51 @@
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { MemoryStore, Progress, STORAGE_KEY } from '../src/progress';
const ids = ['1-1', '1-2', '1-3'];
test('线性解锁与首个未通关', () => {
const p = new Progress(new MemoryStore());
assert.equal(p.isUnlocked(ids, 0), true);
assert.equal(p.isUnlocked(ids, 1), false);
assert.equal(p.firstUncleared(ids), '1-1');
p.markCleared('1-1');
assert.equal(p.isUnlocked(ids, 1), true);
assert.equal(p.isUnlocked(ids, 2), false);
assert.equal(p.firstUncleared(ids), '1-2');
p.markCleared('1-2');
p.markCleared('1-3');
assert.equal(p.firstUncleared(ids), '1-3');
});
test('存档落在本玩法的桶里并可恢复', () => {
const store = new MemoryStore();
const p = new Progress(store);
p.markCleared('1-1');
p.setCurrent('1-2');
p.setPrefs({ sound: false });
assert.ok(store.get(STORAGE_KEY));
const q = new Progress(store);
assert.equal(q.isCleared('1-1'), true);
assert.equal(q.currentId, '1-2');
assert.equal(q.prefs.sound, false);
assert.equal(q.prefs.haptics, true);
q.resetAll();
assert.equal(new Progress(store).clearedCount(), 0);
});
test('跨包链式解锁:2-1 要先过 1-10', () => {
const chained = ['1-1', '1-2', '2-1', '2-2'];
const p = new Progress(new MemoryStore());
assert.equal(p.isUnlocked(chained, 2), false);
p.markCleared('1-1');
p.markCleared('1-2');
assert.equal(p.isUnlocked(chained, 2), true);
assert.equal(p.isUnlocked(chained, 3), false);
});
test('损坏的存档不炸', () => {
const store = new MemoryStore();
store.set(STORAGE_KEY, '{not json');
assert.doesNotThrow(() => new Progress(store));
});