我有一个国际象棋变种引擎,可以玩自杀象棋和失败者象棋以及普通象棋。随着时间的推移,我可能会添加更多变种到我的引擎中。该引擎完全采用C++实现,并正确使用OOP。我的问题与这样一个变种引擎的设计有关。
最初,该项目只是一个自杀象棋引擎,而后我逐渐添加了其他变种。为了添加新的变种,我首先尝试了在C++中使用多态性。例如,一个
但是后来我想到可以使用C++模板和模板特化来分离不同变量的逻辑,最大限度地重用代码。这也很合理,因为在这种情况下动态链接实际上并不是必要的,一旦选择了游戏类型,您基本上会一直坚持到游戏结束。C++模板特化正好提供了这个功能-静态多态性。模板参数可以是
最初,该项目只是一个自杀象棋引擎,而后我逐渐添加了其他变种。为了添加新的变种,我首先尝试了在C++中使用多态性。例如,一个
MoveGenerator
抽象类有两个子类SuicideMoveGenerator
和NormalMoveGenerator
,根据用户选择的游戏类型,工厂将实例化正确的子类。但我发现这样做速度要慢得多——显然因为实例化包含虚函数的类并在紧密循环中调用虚函数都是相当低效的。但是后来我想到可以使用C++模板和模板特化来分离不同变量的逻辑,最大限度地重用代码。这也很合理,因为在这种情况下动态链接实际上并不是必要的,一旦选择了游戏类型,您基本上会一直坚持到游戏结束。C++模板特化正好提供了这个功能-静态多态性。模板参数可以是
SUICIDE
、LOSERS
或NORMAL
。enum GameType { LOSERS, NORMAL, SUICIDE };
当用户选择游戏类型后,将实例化适当的游戏对象,并从那里调用的所有内容都将被适当地模板化。例如,如果用户选择自杀象棋:
ComputerPlayer<SUICIDE>
对象被实例化,这种实例化基本上与整个控制流静态地关联在一起。在 ComputerPlayer<SUICIDE>
中的函数将使用 MoveGenerator<SUICIDE>
,Board<SUICIDE>
等,而相应的 NORMAL
则会适当地工作。
总的来说,这让我在开始时实例化正确的模板化专用类,而不需要任何其他的 if
条件,整个过程都能完美地运行。最好的是,根本没有性能损失!
然而,这种方法的主要缺点是使用模板会使代码变得有点难以阅读。此外,如果未正确处理模板特化,则可能导致重大错误。
我想知道其他变体引擎作者通常如何分离逻辑(并实现代码的良好重用)?我发现C++模板编程非常适合,但如果有更好的方法,我很乐意尝试。特别是,我查看了H G Muller博士的Fairymax引擎,但它使用配置文件来定义游戏规则。我不想这样做,因为我的许多变体具有不同的扩展名,通过将其泛化到配置文件级别,引擎可能不会变得强大。另一个流行的引擎Sjeng到处都是if条件语句,我个人觉得这不是一个好的设计。任何新的设计见解都将非常有用。