计算机专业学生数独项目redo功能故障修复求助
修复数独项目Redo功能的常见思路与方案
Hey there! 作为开发过数独类项目的过来人,我太懂这种undo正常但redo卡壳的憋屈感了😉 结合你描述的Bug场景——修改Case时存旧值到历史支持undo,但首次redo出问题——大概率是你对undo/redo的双栈逻辑处理有漏洞,下面给你拆解问题、落地修复方案:
先分析你可能踩的坑
你提到修改Case时会把旧Case存入历史记录,这说明undo的基础逻辑是对的,但redo失效通常逃不开这两个核心问题:
- 没有分离Undo和Redo的存储栈:如果只用一个栈同时存undo和redo记录,undo后没有把当前状态单独存入redo栈,导致redo时无有效记录可取;
- 状态存储用了浅拷贝:如果存到历史栈里的Case只是当前对象的引用(浅拷贝),后续修改当前Case会同时篡改栈里的历史记录,redo时拿到的是已经被修改过的无效状态;
- 首次Undo后未正确维护Redo栈:第一次执行undo时,忘记把当前的Case状态推入redo栈,导致redo栈为空,自然无法执行首次redo。
落地修复的具体步骤
1. 改用双栈结构(核心!)
必须分开维护undoStack和redoStack,明确两个栈的职责:
undoStack:存储所有可以被撤销的历史Case状态;redoStack:存储所有可以被重做的历史Case状态。
对应的操作逻辑应该是这样:
- 修改Case时:
- 先把当前完整的Case状态深拷贝后推入
undoStack; - 执行修改操作;
- 清空
redoStack(因为新操作会让之前的redo记录全部失效,这一点很容易忘!)
- 先把当前完整的Case状态深拷贝后推入
- 执行Undo时:
- 先判断
undoStack是否为空,不为空则把当前Case状态深拷贝后推入redoStack; - 从
undoStack弹出最后一个状态,恢复为当前Case;
- 先判断
- 执行Redo时:
- 先判断
redoStack是否为空,不为空则把当前Case状态深拷贝后推入undoStack; - 从
redoStack弹出最后一个状态,恢复为当前Case。
- 先判断
2. 确保状态是深拷贝
这是很多人忽略的细节:如果你的Case是一个对象或复杂数据结构(比如数组、字典),直接存引用会导致历史记录被后续修改污染。举个例子:
- 错误做法:
undoStack.append(current_case)(存引用,修改current_case会同步改栈里的内容) - 正确做法:用深拷贝工具,比如Python的
copy.deepcopy(),Java的clone()(要实现深克隆),C++的拷贝构造函数等。
3. 给首次Redo加日志排查
如果只有首次redo失效,建议在undo和redo操作前后打印两个栈的长度,比如:
// 执行undo前打印 System.out.println("Undo前: undo栈长度=" + undoStack.size() + ", redo栈长度=" + redoStack.size()); // 执行undo后打印 System.out.println("Undo后: undo栈长度=" + undoStack.size() + ", redo栈长度=" + redoStack.size());
看看首次undo后redo栈有没有新增元素——如果没有,说明你在undo时漏了把当前状态推入redo栈,补上这个步骤就能解决问题。
伪代码示例(Python版)
import copy # 初始化双栈和初始数独状态 undo_stack = [] redo_stack = [] current_case = [[0 for _ in range(9)] for _ in range(9)] # 9x9空数独 def update_case(row, col, value): global current_case # 深拷贝当前状态到undo栈 undo_stack.append(copy.deepcopy(current_case)) # 执行修改 current_case[row][col] = value # 新操作后清空redo栈 redo_stack.clear() def undo(): global current_case if undo_stack: # 把当前状态存到redo栈 redo_stack.append(copy.deepcopy(current_case)) # 恢复undo栈的最后状态 current_case = undo_stack.pop() def redo(): global current_case if redo_stack: # 把当前状态存到undo栈 undo_stack.append(copy.deepcopy(current_case)) # 恢复redo栈的最后状态 current_case = redo_stack.pop()
按照这个逻辑调整后,你的redo功能应该就能正常工作了,尤其是首次redo的问题会得到解决。
内容的提问来源于stack exchange,提问作者Nemtecl
相关产品推荐
相关产品推荐

