我有一个基础类
class piece;
和包含派生对象的数组
piece* board[8][8];
优势,通过虚拟功能进行清洁设计。缺点,如果我必须在板上找到一块或比较一件我必须恢复到动态铸造(或typeid)。它很丑陋,在收集数百万请求时可能会很糟糕。
另一方面,如果我创建一个单件类的数组,它有一个用于识别碎片的类型字段,我没有这个问题(它应该更快)但我必须做出超级难看的开关声明。我想,由于件数是有限的,我不认为自己制造了那么多开关,这可能最终是一个更好的选择,您怎么看?
这是为了好玩(所以没有位板)。
编辑1
阅读一些答案,我认为仅使用类型字段进行运算符重载(==,!= ...)可以带来两个词中最好的。
boost :: variant看起来也很有趣。
答案 0 :(得分:5)
或者,如果您的课程集是有限的 - 即您知道该数字,请使用变体和访问者。例如,boost::variant<king, queen, bishop, knight ...>
并且电路板由这种类型的2D阵列组成。现在要查询,你可以使用访客......
答案 1 :(得分:3)
我会选择类层次结构。
要查找某件作品,您可以为每件作品保留一份分页列表。所以你知道在哪里寻找每一种类型。
为了进行比较,您也可以依赖虚拟方法。
另一种方法是使用组件架构(如此处所描述的:http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/),但我认为对于国际象棋游戏来说太过分了,你可以清楚地知道这些类型并知道这些类型不会很快改变: )。
答案 2 :(得分:1)
我会选择层次结构,如果我想知道类型(为什么?)有一个标识类型的虚方法。
答案 3 :(得分:1)
我从未写过国际象棋程序,但我猜最常见的操作是:
此外,其中一些棋子具有“状态”(一个国王只有在之前没有移动的情况下才可以城堡,如果另一个棋子移动了两个方格,则棋子可以通过,只适用于一种棋子)
所有这些都是我的阶级层级。 (假设您不需要位板性能)
另一方面,您不太可能需要添加新的片段类型,或者您将能够在分离中重复使用其中一种片段类型。即可扩展性和模块性不是真正的问题。因此,如果您发现算法的某些重要部分应该分散在多个类中 - 请使用switch语句。只需添加一个抽象方法tp Piece
类,它返回一个PieceType
枚举并打开它。
答案 4 :(得分:1)
你不能同时担心性能和代码的乐趣:)
考虑使用“nibbleboard”(或至少是byteboard)而不是bitboard,其中每个半字节代表一个片段类型。每个半字节也是在该片段类型上操作的单例对象表中的索引。
class Empty : public Piece {};
class Rook : public Piece {};
...
const int wrook = 1;
...
const int bpawn = 12;
Piece* Operator[13] = {new Empty(), new Rook(), ..., new Pawn()};
byte table[64] = {
wrook, wbishop, wknight, wking, wqueen, wknight, wbishop, wrook,
wpawn, wpawn, wpawn, wpawn, wpawn, wpawn, wpawn, wpawn,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
bpawn, bpawn, bpawn, bpawn, bpawn, bpawn, bpawn, bpawn,
brook, bbishop, bknight, bking, bqueen, bknight, bbishop, brook};
// Given some position and some operation DoSomething we would have this:
Operator[table[position]]->DoSomething(table, position, <other parameters>);
// Possible return value of DoSomething might be new table
答案 5 :(得分:-1)
“超级丑陋的开关语句”是正确的技术。这并不难看。它被称为函数式编程。
继承完全是错误的技术。每个部件以不同的方式移动,具有不同的图形和其他属性。没有什么共同之处。棋子不是抽象的。它们是离散对象的具体集合。
你必须通过统一来创造共同点:创造所谓的总和类型。 在Ocaml:
type shape = Pawn | Rook | Knight | Bishop | Queen | King
type color = Black | White
type piece = shape * color
type pos = { row:int; col:int }
let check_white_move piece board from to = match piece with
| Pawn -> on_board to && (from.row = 2 && to.row = 4 or to.row = from.row + 1)
| ....
在C ++中没有正确的和类型,你可以使用:
enum shape { pawn, rook, knight, bishop, queen, king};
..
bool check_white_move (..) { switch piece {
case pawn: ...
它更笨拙。抱怨C和C ++委员会。但要使用正确的概念。求和类型(有区别的联合,变体)是 统一离散的一组具体类型的方法。类和继承用于表示抽象并提供其实现。
国际象棋没有任何摘要。这都是关于组合的。这不是不同技术的优点和缺点的问题:它是关于使用正确的技术。
[BTW:是的,你可以尝试使用boost变体虽然我不能推荐它用于这个应用程序,因为这些部分没有相关的数据,枚举是完美的]