Choosing a movement strategy based on the type of chess piece

Posted on

Problem

PawnMovementKingMovement are of type Movement. This is implementation of strategy pattern. Basing on actual value of PieceType I want to choose proper strategy. How to avoid long if/else statements or switch?

    PieceType pieceType;
    if(this.board.getPieceAt(from) != null) {
        pieceType = this.board.getPieceAt(from).getType();
    } else {
        throw new InvalidMoveException();
    }

    if (pieceType == PieceType.PAWN) {
        contextMovement.setContext(new PawnMovement());
    } else if (pieceType == PieceType.ROOK) {
        contextMovement.setContext(new RookMovement());
    } else if (pieceType == PieceType.KNIGHT) {
        contextMovement.setContext(new KnightMovement());
    } else if (pieceType == PieceType.BISHOP) {
        contextMovement.setContext(new BishopMovement());
    } else if (pieceType == PieceType.QUEEN) {
        contextMovement.setContext(new QueenMovement());
    } else if (pieceType == PieceType.KING) {
        contextMovement.setContext(new KingMovement());
    }
    return contextMovement.executeMovement(from, to, board);

Solution

The complexity of approach is too high, it can be reduced to the following:

PieceType pieceType = getPieceType();
contextMovement.setContext(pieceType.getMovement());
return contextMovement.executeMovement(from, to, board);

The PieceType enum (probably call it Piece?) can be extended with:

public enum Piece {

  PAWN() {
    @Override
    public Movement getMovement() { 
      return new PawnMovement();
    }
  }, ... // other elements;

  public abstract Movement getMovement();

}

Obviously the information carried by PieceType is tightly coupled to the possible movement. This is not due to your coding, it’s due to the modelled domain.

In a somewhat common case I came with a solution that reflects the coupling of domain artifacts in code. I hooked up the functionality to the enum:

enum Strategy {
    SQUARE() {
        public int perform(int arg) {
            return arg * arg;
        }
    },
    TRIPLE() {
        public int perform(int arg) {
            return 3 * arg;
        }
    };
    abstract public int perform(int arg);
}

Elsewhere in your code you just hand the instrumented enum value around and all functionality is at hand.

int performWith(Strategy s, int i) {
    ...
    return s.perform(i);
}

Some suggestions:

  • Have each piece implement the type of movement it makes. This means each piece inherits from Movement class so you can just call something like piece.getMovementContext()

  • Store the movement for each piece in an EnumMap and do a look up of the movement depending on the piece.

Leave a Reply

Your email address will not be published. Required fields are marked *