Files
huajishe-tts/docs/dev-log/07-bugfixes-round-1.md
Claude 24822d0d6a docs(dev-log): add chronological development log
Per user request: split the development process into per-topic docs under
docs/dev-log/. Each entry follows the same structure:
  What was asked → Problems → How solved

Files:
- README.md            index
- 01-initial-scope-and-design.md
- 02-ui-primitives-api-design.md
- 03-monorepo-scaffold.md
- 04-ui-primitive-impl.md
- 05-drag-and-drop.md
- 06-three-games.md
- 07-bugfixes-round-1.md
- lessons-learned.md   all gotchas consolidated
- decisions.md         locked decisions with dates

Total: 1071 lines across 10 files.
2026-08-17 16:49:09 +08:00

3.9 KiB
Raw Permalink Blame History

07 · Bug 修复 · 第一轮

做什么

用户手动验证 3 个游戏后报告 2 个 bug

  1. WarUI 上看不到第二个玩家的牌堆;翻牌逻辑也有问题
  2. DragTest:在已经拖到桌的牌上继续拖会重复加;拖走之后拖不回手牌

遇到什么问题

Bug 1War 看不到 P1 牌堆

根因4 个 zone 都设了 owner='0' / owner='1'Board 的 owner 过滤逻辑让对方的私有 zone 完全隐藏。

Bug 2War 翻牌"啥也没看到"

根因:原 flip move 一次完成翻+收pile 永远只显示 0 张。牌翻出来立刻被赢家收走,玩家看不到"对比"。

Bug 3DragTest 桌→桌重复加卡

根因 Immer 陷阱

const fromArr = G[fromKey];  // 假设 fromKey === toKey
const toArr = G[toKey];
G[fromKey] = fromArr.filter(...);   // 改了 G[fromKey](也是 G[toKey]
G[toKey] = [...toArr, ...moved];    // toArr 是修改前的旧引用!

fromKey === toKey 时,toArr 仍指向过滤前的原数组,所以 [...toArr, ...moved] 把已经"过滤掉"的牌又加回来。

具体场景:桌子有 [2♠],拖 2♠ 又到桌:

  • fromArr = toArr = [2♠]
  • moved = [2♠]
  • G.table = [2♠].filter(!idSet.has) = []
  • G.table = [...[2♠], 2♠] = [2♠, 2♠] 重复

Bug 4DragTest 拖不回手牌

根因hand zone 没配 dropMove,所以 drop 处理器什么都不做。

怎么解决

修复 1去掉 War zone 的 owner

ui: {
  zones: [
    { id: 'p0-deck', type: 'pile', position: { x: 100, y: 50 }, faceDown: true, collection: 'p0Deck' },
    { id: 'p1-deck', type: 'pile', position: { x: 700, y: 50 }, faceDown: true, collection: 'p1Deck' },
    // 关键pile 用 type='discard',渲染时强制 face-up
    { id: 'p0-pile', type: 'discard', position: { x: 300, y: 300 }, collection: 'p0Pile' },
    { id: 'p1-pile', type: 'discard', position: { x: 500, y: 300 }, collection: 'p1Pile' },
  ],
  actions: [
    { label: '翻牌', move: 'flip' },
    { label: '收牌', move: 'collect' },
  ],
}

修复 2拆 flip → flip + collect

moves: {
  flip: ({ G }) => {
    if (G.winner || !G.p0Deck.length || !G.p1Deck.length) return;
    // 翻牌到 pile记录 lastWinner但不收
    G.p0Pile.push(p0CardId);
    G.p1Pile.push(p1CardId);
    G.lastWinner = ...;
  },
  collect: ({ G }) => {
    // 按 lastWinner 把 pile 收给赢家
    if (G.lastWinner === '0') G.p0Deck = [...G.p0Deck, ...shuffle([...G.p0Pile, ...G.p1Pile])];
    G.p0Pile = [];
    G.p1Pile = [];
    G.lastWinner = null;
  },
}

UI 上两个按钮:翻牌 → 收牌 → 翻牌 ... 循环。

修复 3transferCards 同 zone 直接 return

moves: {
  transferCards: ({ G }, cardIds, fromZoneId, toZoneId) => {
    if (fromZoneId === toZoneId) return;  // no-op
    // ... 原有逻辑
  },
}

修复 4hand zone 加 dropMove

{
  id: 'hand',
  type: 'hand',
  position: { x: 250, y: 500 },
  owner: 'self',
  collection: 'hand',
  layout: { fan: 0, spacing: 70 },
  dropMove: 'transferCards',  // ← 新增
  dropArgs: (cardIds, fromZoneId, toZoneId) => [cardIds, fromZoneId, toZoneId],
},

验证

Playwright 端到端:

  • War 翻牌4 张牌在桌上可见 → 翻牌 → pile 各 1 张 face-upK♠ / 8♦→ 收牌 → p0 deck 25→27
  • DragTest 桌→桌:拖 2♠ 到桌hand=4, table=1→ 拖 2♠ 又到桌(仍然 hand=4, table=1不重复
  • DragTest 桌→手:拖 2♠ 回手牌hand=5, table=0

成果

  • Commit e9a7737 fix(war,drag-test): public piles, two-button UX, same-zone no-op

关联