1

如果我在 C 中保留一个表示棋盘的数组,我可能会用大致如下所示的枚举项填充它:

enum CHESSPIECE {
  none  = 0,
  pawn, knight, bishop, rook, queen, king,
  type_mask = 7,
  white = 8,
  white_pawn, white_knight, white_bishop, white_rook, white_queen, white_king,
  black = 16,
  black_pawn, black_kight, black_bishop, black_rook, black_queen, black_king,
  color_mask = 24
} chessPiece;

因此允许看起来像这样的逻辑:

if (board[i][j] & color_mask == currentColor)
{
  impossibleMove = true; // or some-such
}

在 Java 中,我只是发现不支持对枚举的按位 & 操作,此外,相当棒的 EnumSet 并不容易应用,因为一块不能是黑白的,车不能是国王的。

所以我的想法是这样的:

public enum ChessPieceId {
    None            (null, null),
    Pawn            (null, null),
    Knight          (null, null),
    Bishop          (null, null),
    Rook            (null, null),
    Queen           (null, null),
    King            (null, null),
    Type_Mask       (null, null),
    White           (null, null),
    White_Pawn      (ChessPieceId.White, ChessPieceId.Pawn),
    White_Knight    (ChessPieceId.White, ChessPieceId.Knight),
    White_Bishop    (ChessPieceId.White, ChessPieceId.Bishop),
    White_Rook      (ChessPieceId.White, ChessPieceId.Rook),
    White_Queen     (ChessPieceId.White, ChessPieceId.Queen),
    White_King      (ChessPieceId.White, ChessPieceId.King),
    SkipA           (null, null),
    Black           (null, null),
    Black_Pawn      (ChessPieceId.Black, ChessPieceId.Pawn),
    Black_Knight    (ChessPieceId.Black, ChessPieceId.Knight),
    Black_Bishop    (ChessPieceId.Black, ChessPieceId.Bishop),
    Black_Rook      (ChessPieceId.Black, ChessPieceId.Rook),
    Black_Queen     (ChessPieceId.Black, ChessPieceId.Queen),
    Black_King      (ChessPieceId.Black, ChessPieceId.King),
    SkipB           (null, null),
    Color_Mask      (null, null);

    private final ChessPieceId color;
    private final ChessPieceId type;

    ChessPieceId(ChessPieceId pColor, ChessPieceId pType){
        this.color = pColor;
        this.type = pType;
    }

    ChessPieceId color() { return color; }
    ChessPieceId type() { return type; }

    // & operator should be built in. I considered an EnumSet but...
    ChessPieceId and(ChessPieceId pSecond) {
        switch(ChessPieceId.this.ordinal() & pSecond.ordinal()) {
        case 0: //None.ordinal() etc. [if only Java were smarter]
            return None;
        case 1:  return Pawn;
        case 2:  return Knight;
        case 3:  return Bishop;
        case 4:  return Rook;
        case 5:  return Queen;
        case 6:  return King;
        case 7:  return Type_Mask;
        case 8:  return White;
        case 9:  return White_Pawn;
        case 10: return White_Knight;
        case 11: return White_Rook;
        case 12: return White_Bishop;
        case 13: return White_Queen;
        case 14: return White_King;
        //case 15: return SkipA;
        case 16: return Black;
        case 17: return Black_Pawn;
        case 18: return Black_Knight;
        case 19: return Black_Rook;
        case 20: return Black_Bishop;
        case 21: return Black_Queen;
        case 22: return Black_King;
        //case 23: return SkipB;
        case 24: return Color_Mask;
        default:
            return None;
        }
    }
}

显然我只需要一个或另一个(and 操作,或初始化值)。如果我可以在它自己的定义中使用枚举类型,那肯定会很棒,但我不能。所以像这样的行:

    Bishop          (null, ChessPieceId.Bishop),
    ...
    White           (ChessPieceId.White, null),

出局。

我的问题是什么?有没有更好的方法,我错过了。我也可以将序数的 int 解析为枚举定义的值,避免整个 case 语句吗?

4

4 回答 4

3

CardSun 教程中关于Enums 的示例中,它们将一副纸牌表示为两个Enums -RankSuit。这与您的问题同构。请参阅http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

请注意,您可以Enum通过定义适当的构造函数来增加您喜欢的任何额外值,因此您也不会被绑定到序数值。

于 2010-02-08T20:40:42.857 回答
2

为棋子定义一个类不是很有意义吗?

然后你可以在其中粘贴两个枚举。想象一下。

于 2010-02-08T20:41:12.723 回答
1

为什么你坚持使用 Enums?这显然不是合适的工具。

我将有一个 Token 接口,并让它在一个具有颜色和类型的类中实现(类型和颜色是两个不同的枚举)。您甚至可以对不同类型的片段有多种实现,这样您就可以将它的运动行为直接放入类本身......

于 2010-02-08T20:42:22.540 回答
1

只是一个建模建议...

我可能会从具有抽象 canMoveTo() 方法的 ChessPiece 对象开始。它将被典当,主教,国王覆盖......白/黑是这件作品的一个属性。

因此,从您的代码中,它始终遵循相同的模式,piece.canMoveTo(x1,y1); 或piece.move(x1,y1);

始终考虑要求您的对象做某事-而不是从外部(来自另一个对象)对您的对象的属性进行操作。

至于枚举问题,我不会担心优化解决方案,直到您编写了一个很棒的通用解决方案,并且您发现它不够快/小/酷,无法满足您的要求。事实证明,使用枚举甚至不适合您的最终模型。我什至会暂时放弃按位运算。

编辑:

我听说过一些非常有力的论据,指出为 Java 使用 sub-int 会大大降低一切。例如,使用字节数组或位域。如果您绝对需要它们来腾出空间,那很好,但不要使用它们,因为您认为它们会使您的代码更快——它们只会弄乱缓存和优化例程。

例如,声明一个变量“byte b;” 仍然在 ram 中占用整个 int,但每次访问它时都会强制执行额外的屏蔽操作和额外的验证。我不确定同样的事情是否适用于位操作,但你正在尝试做的事情对我来说真的感觉像是过早的优化——这是最大的编程弊端之一。

于 2010-02-08T20:47:12.570 回答