Побитовые операции над перечислениями Java; RE: Шахматы Е.Г. - PullRequest
1 голос
/ 08 февраля 2010

Если бы я хранил массив в 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;
        }
    }
}

Ясно, что мне нужно только одно или другое (операция и или инициализированные значения). Также было бы здорово, если бы я мог использовать тип enum в его собственном определении, но я не могу. Так что строки вроде:

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

Нет.

Какой у меня был вопрос? Есть ли лучший способ, который я скучаю. Также я могу разобрать int порядкового числа в определенное значение перечисления, избегая всего этого оператора case?

Ответы [ 4 ]

3 голосов
/ 08 февраля 2010

В примере Card в руководстве по Sun на Enum с они представляют колоду карт в виде двух Enum с - Rank и Suit. Это изоморфно вашей проблеме. Смотри http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html.

Обратите внимание, что вы можете дополнить Enum любыми дополнительными значениями, которые вам нравятся, определив соответствующий конструктор, поэтому вы не будете привязаны к порядковым значениям.

2 голосов
/ 08 февраля 2010

Не имеет ли смысла определять класс для шахматной фигуры?

Тогда вы можете вставить два перечисления в нем. Представь себе это.

1 голос
/ 08 февраля 2010

Просто модельное предложение ...

Вероятно, я бы начал с объекта ChessPiece, у которого был абстрактный метод canMoveTo (). Это будет отменено пешкой, слоном, королем, ... Белый / Черный является атрибутом фигуры.

Итак, из вашего кода он всегда следует одному и тому же шаблону piece.canMoveTo (x1, y1); или piece.move (x1, y1);

Всегда думайте о том, чтобы попросить ваш объект сделать что-то, а не воздействовать на атрибуты вашего объекта извне (из другого объекта).

Что касается проблемы enum, я не буду беспокоиться об оптимизации решения, пока у вас не закодировано отличное решение общего назначения, и вы не обнаружите, что оно недостаточно быстрое / маленькое / крутое для удовлетворения ваших требований. Может оказаться, что использование перечислений даже не вписывается в вашу окончательную модель. Я бы даже оставил битовые операции ненадолго.

EDIT:

Я слышал некоторые довольно веские аргументы, утверждающие, что использование sub-int для Java несколько замедляет все. Например, используя байтовые массивы или битовые поля. Если они вам абсолютно необходимы для пространства, хорошо, но не используйте их, потому что вы думаете, что они сделают ваш код быстрее - они просто испортят кэширование и оптимизируют подпрограммы.

Например, объявление переменной "byte b;" по-прежнему занимает целое число в оперативной памяти, но вызывает дополнительную операцию маскирования и дополнительные проверки каждый раз, когда вы получаете к нему доступ. Я не уверен, применимо ли то же самое к битовым операциям, но то, что вы пытаетесь сделать, на самом деле кажется мне преждевременной оптимизацией - одно из самых больших зол программирования.

1 голос
/ 08 февраля 2010

Почему вы настаиваете на использовании Enums? Это явно не правильный инструмент.

У меня был бы интерфейс Token, и он был бы реализован в классе с его цветом и типом (тип и цвет - это два различных перечисления). У вас может даже быть несколько реализаций для разных типов частей, так что вы можете поместить непосредственно в класс его поведение при перемещении ....

...