【发布时间】:2020-06-29 00:54:01
【问题描述】:
我正在尝试从头开始制作国际象棋游戏,并在过去几个月中取得了重大进展。但是,我最近遇到了一个我无法弄清楚如何解决的问题。
代码(更新)
由于源代码太大,这里不能发,我觉得最好留下我的GitHub账号的链接,在那里可以找到:https://github.com/lbragile/chessCAMO
描述
国际象棋
包含相关的游戏标志和转弯跟踪,并保留棋盘位置堆栈以允许玩家撤消移动。
一块
包含作品的:
- 正方形 ([0,63])
- 移动信息(用于易位和初始兵移动)
- 类型
- 颜色
Piece Type 类
包括:
- 典当
- 骑士
- 主教
- 鲁克
- 女王
- 国王
- 空(用于空白方块)
这些继承自基类(Piece)
问题
通过这种设置,Chess 和 Piece 是独立的类(一个不是从另一个派生的)。 但是,为了跟踪堆栈中的棋盘位置,Chess 类使用了成员变量:
stack<vector<Piece*>> board_positions;
这实际上让我可以撤消该位置,甚至可以在之后进行移动。但是,在通过我的测试用例运行我的算法后,我注意到它在涉及检查、双重检查、将死和僵局标志的情况下失败了。当我检查我的 GUI 时,这一点得到了证实。例如, 进行导致检查的动作,然后“撤消”该动作,并再次重复该动作。由于未存储前一个位置的检查标志,因此失败。
这导致了一个明显的结论,即我必须在每次移动时存储整个 Chess 对象,以便获得棋盘表示和相应的必要标志。我只是不知道如何在 Chess 类中拥有一个可以将 Chess 对象存储在堆栈中的成员变量。主要原因是 Chess 本身包含 Piece 对象,这些对象是多态(虚函数),并且两个类是独立的。
任何关于如何进行的建议或有用的提示将不胜感激。
编辑#1
我使用提供的建议更新了代码。但是,我目前的问题是板 flags 似乎没有在堆栈上更新。这似乎源于~Chess()。我认为它实际上并没有破坏对象指针,而是简单地弹出它们。我尝试使用std::move() 在if 语句的pushInfo() 函数中将makeMove(int src, int dest, istream &in) 中的资源从temp_chess 移动并删除析构函数中的game_info 指针,但这似乎并不能解决问题。
编辑#2
请参阅下面的答案,我使用Chess 对象的序列化/反序列化解决了这个问题。
【问题讨论】:
-
您只需要创建另一个将位置和标志保存在一起的类或结构。然后当堆栈弹出位置和标志将回滚。
-
@Slava 感谢您的快速回复!如果我理解正确,假设我有一个 GAME 类,它的成员变量将是
stack<vector<Piece*>> board_positions和stack<vector<bool>> board_flags。那么公共成员函数将操纵这些(而不是在国际象棋中 - 对于board_positions)?如果是这样,我认为 GAME 也将与 Chess 和 Piece 课程完全分开? -
不,必须并行向量是个坏主意。我的意思是
struct board { std::vector<Piece*> positions; std::vector<bool> flags; };,然后是std::stack<board> board_stack; -
@lbragile
Chess & operator =(const Chess & object) = default;。不,您需要实际执行此操作。您可以使用copy / swap 轻松做到这一点。另外,您需要关注rule of 3。您所做的是实现了这三个函数中的两个,并希望缺少用户定义的赋值运算符不会让您感到困惑。 -
赏金与否 - 如果问题对未来的读者有任何价值,您应该创建minimal reproducible example 并将其放入实际问题中。