HarmonyOS7应用《拼棋派对》实战:24点的撤销、提示与回合结算
上一篇完成了两张牌的合并。真实答题中,玩家还会算错一步、改变思路、使用提示,或者完成一轮后重新开始。这些操作决定24点是否适合持续练习。
这一篇从一次具体撤销开始:把48除以2得到24之后,点击撤销,页面应该回到48与2,并恢复刚才的选牌和除法状态。只恢复数字数组还不够,等待执行的操作也属于历史。
本文目录
撤销记录需要保存什么
项目中的历史模型位于 Index.ets:
interface TwentyFourHistoryState {
slots: TwentyFourSlot[];
selected: number;
operator: string;
}
牌槽保存数值、表达式与可用状态,selected 保存左操作数,operator 保存待执行运算。三者一起描述一次操作前的局面。
例如“选择48、选择除号、选择2”的最后一步执行前,快照包含48和2、已选中的48,以及除号。撤销到这个时间点,玩家就可以直接重新选择右操作数。
pushTwentyFourHistory 先克隆牌槽,再序列化快照;单人模式将历史限制在12项以内:
const state: TwentyFourHistoryState = {
slots: cloneTwentyFourSlots(slots),
selected,
operator
};
const encoded = JSON.stringify(state);
this.single24History = [...this.single24History, encoded].slice(-12);
这是原函数中的单人分支节选。克隆避免后续修改影响旧快照,序列化进一步固定了历史内容,限制长度则避免连续操作导致数组无界增长。
项目也允许未选运算符时交换牌位,因此历史不仅包含运算,还包含换位。讲撤销时需要覆盖所有会改变牌局的动作。
恢复数据与刷新牌面
单人撤销的完整处理如下:
private undoSingle24(): void {
if (this.single24History.length === 0) {
this.notice = '暂无可撤销步骤';
return;
}
const last = this.single24History[this.single24History.length - 1];
const state = JSON.parse(last) as TwentyFourHistoryState;
this.single24Slots = cloneTwentyFourSlots(state.slots);
this.refreshTwentyFourSlotsSnapshot('single', 'A', this.single24Slots);
this.single24Selected = state.selected;
this.single24PendingOp = state.operator;
this.single24History = this.single24History.slice(0, this.single24History.length - 1);
this.twentyFourRenderVersion += 1;
this.notice = '已撤销一步';
}
先处理空历史,再恢复牌槽和操作状态,移除已经使用的快照,并刷新显示。refreshTwentyFourSlotsSnapshot 会同步各牌显示字段和表达式,保证恢复后的数字、牌面文字与可用数量一致。
得到24→撤销恢复48与2→再次得到24→提交。撤销时,左操作数和除法高亮一起恢复。
当前点击流程在尝试计算前保存历史,因此除零失败也可能留下未改变局面的快照。如果后续希望撤销只覆盖有效改动,可以在计算成功后提交历史,同时为换位保留单独的入栈位置。这个改进涉及事件顺序,应配合除零与连续撤销验证。
提示次数属于整轮训练
提示读取当前题目的 hint 与 solution:
private showSingle24Hint(): void {
const question = this.currentSingle24Question();
if (this.single24Hints <= 0) {
this.notice = `参考:${question.solution}`;
return;
}
this.single24Hints -= 1;
this.notice = `${question.hint} · 剩余${this.single24Hints}`;
}
新一轮开始时有3次提示。进入下一题不会重新补充次数,提示预算属于整轮训练。
次数耗尽后,当前实现会显示参考解法。因此“剩余0”表示步骤提示已经用完,而不是按钮彻底失效。这种规则需要让界面文案与实际行为一致,避免读者按代码误写成“提示耗尽后禁止使用”。
展开屏中,数字牌与工具分区排列。点击提示后,表达式区显示题目思路,提示数减少到2。
提示可以告诉玩家如何拆解题目,例如两个7先做49,再减1。它保留思考空间,又能在困难时给出下一步方向。
提交后怎样进入下一题
单人训练每轮5题。答对后增加分数,若尚未到第五题,就更新轮次并加载新题:
const nextRound = this.single24Round + 1;
this.single24Round = nextRound;
this.loadSingle24Question(nextRound);
this.notice = `正确,进入第 ${this.single24Round}/5 题`;
加载新题时,重新创建牌槽、清空选择和运算符,并把撤销历史设为空。这样上一题的操作不会被撤销进新题。
计时、累计答对数与剩余提示保持整轮含义。把所有状态都放到“加载题目”里重置,会让用户每题重新得到3次提示,也会丢失累计成绩。
新题已经刷新,答对数仍然保存为1。
完成一轮再重新开始
第五题答对后,finishSingle24 停止训练计时与游戏音乐,清理选中状态,生成战绩。结果记录包含难度、5题成绩和用时。
五题依次答对,累计成绩推进到5分;训练结束后点击再来,题号、得分和提示预算恢复为新一轮状态。
重新开始则通过 restartSingle24 统一恢复轮次1、得分0、提示3和用时0,并载入第一题。清空当前题与重新开始整轮是两个操作:清空只恢复当前题数字,保留整轮成绩和题号;结束后的重开才重置整轮。
| 操作 | 牌面与历史 | 轮次与成绩 | 提示预算 |
|---|---|---|---|
| 撤销 | 恢复上一步 | 保持 | 保持 |
| 清空本题 | 恢复当前题、清空历史 | 保持 | 保持 |
| 答对下一题 | 新题、清空历史 | 轮次推进、分数增加 | 保持 |
| 再来一轮 | 第一题、清空历史 | 回到1、得分0 | 恢复3 |
在模拟器里,先检查撤销能否回到完整操作状态,再检查跨题后的历史是否清空,最后走完5题查看结果与重开。这样验证的是同一个状态模型在不同阶段是否仍然一致。
后续扩展双人模式时,历史、选择和提示类状态需要明确归属。下一篇会继续区分双方独立牌局与共同题号,防止一个人的操作影响另一个人。
相关源码:pages/Index.ets 的 pushTwentyFourHistory、undoSingle24、showSingle24Hint、loadSingle24Question、restartSingle24 与 finishSingle24。
更多推荐


所有评论(0)