Java枚举的按位运算; RE:国际象棋E.G

时间:2010-02-08 20:36:33

标签: java enums bit-manipulation chess

如果我在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;
        }
    }
}

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

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

出去了。

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

4 个答案:

答案 0 :(得分:3)

Card上的Sun教程中的Enum示例中,它们代表一副牌为两个Enum s - RankSuit。这与你的问题是同构的。请参阅http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

请注意,您可以通过定义适当的构造函数来增加Enum您想要的任何额外值,因此您也不会受序数值的约束。

答案 1 :(得分:2)

为棋子定义一个课程是不是有意义?

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

答案 2 :(得分:1)

为什么你坚持使用枚举?它显然不是合适的工具。

我会有一个Token接口,并在类中实现它的颜色和类型(类型和颜色是两个不同的枚举)。你甚至可以为不同类型的作品设置多个实现,这样你就可以直接在课堂上运用它的运动行为....

答案 3 :(得分:1)

只是建模建议......

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

所以从你的代码中,它总是遵循相同的模式,piece.canMoveTo(x1,y1);或piece.move(x1,y1);

总是考虑让你的对象做某事 - 而不是从外部(来自另一个对象)操作对象的属性。

至于枚举问题,我不会担心优化解决方案,直到你有一个很好的通用解决方案编码,你发现它不是快/小/酷足以满足你的要求。事实证明,使用枚举甚至不适合您的最终模型。我甚至会稍微留下按位操作。

编辑:

我听过一些非常强大的论据,说明为Java的sub-int减慢了一切。例如,使用字节数组或位域。如果你绝对需要它们的空间,很好,但不要使用它们,因为你认为它们会让你的代码更快 - 它们只是搞乱缓存和优化例程。

例如,声明变量“byte b;”仍然占用ram中的整个int,但每次访问时都会强制执行额外的屏蔽操作和其他验证。我不确定同样的事情是否适用于位操作,但是你想要做的事情真的让我觉得过早优化 - 一个最大的编程邪恶。