001 package core;
002
003 import java.util.*;
004
005 import rules.GameState;
006 import rules.NoneSquare;
007
008 /**
009 * A Piece represents a state of the board. Individual pieces are subclasses of
010 * Piece, overriding various methods to determine their name and how they move.
011 *
012 * Pieces are immutable.
013 *
014 * One special case is Empty, for non-piece squares.
015 *
016 * @specfield state : int //Useful for castling/en passant
017 * @specfield color : Color //Who the owner is
018 * @specfield name : String //Name of this piece type
019 * @derivedfield moves(GameState) : Set<Move> //Possible moves from a position
020 */
021 public abstract class Piece
022 {
023 /* The color of this piece */
024 protected Color color;
025
026 /* This isn't actually the last move; it is
027 * 0 before a piece moves
028 * (the last move) if the piece was just a pawn pushed by 2 squares
029 * 1 otherwise
030 * So castling can only be done if both have lastMove 0;
031 * en passant if the opposing pawn's lastMove is the current move.
032 * and it is in the right spot
033 */
034 private int lastMove;
035
036 // AF:
037 // state = lastMove
038 // color = color
039 // name = getName() (short) or pieceString() (long)
040 //
041 // RI:
042 // color != null
043 // color == NONE for Empty and != NONE otherwise
044
045 /**
046 * @returns a single-character name of this piece
047 */
048 protected abstract String getName();
049
050 /**
051 * @returns a human readable string for the piece.
052 */
053 abstract public String pieceString();
054
055 private void checkRep()
056 {
057 assert (color != null);
058 if (this instanceof NoneSquare)
059 {
060 assert (color == Color.NONE);
061 } else
062 {
063 assert (color != Color.NONE);
064 }
065 }
066
067 /**
068 * @returns valid moves for this piece.
069 * @requires g, here != null
070 */
071 public abstract Collection<Move> moveCandidates(GameState g, Position here);
072
073
074 /**
075 * Constructs a new piece.
076 *
077 * @param color
078 * of the piece
079 * @param lastMove
080 * of the piece (0 means it hasn't moved)
081 * @requires color not null, last move valid
082 */
083 public Piece(Color color, int lastMove)
084 {
085 this.color = color;
086 this.lastMove = lastMove;
087 checkRep();
088 }
089
090 /**
091 * @returns the last time this piece moved
092 */
093 public int getLastMove()
094 {
095 return lastMove;
096 }
097
098 /**
099 * @returns the color of this piece
100 */
101 public Color getColor()
102 {
103 return color;
104 }
105
106 /**
107 * @returns the short 1-character name of this piece, in lower case for
108 * black and upper case for white.
109 */
110 public String toString()
111 {
112 if (getColor() == Color.WHITE)
113 return getName().toUpperCase();
114 else
115 return getName().toLowerCase();
116 }
117
118 /**
119 * Apply the modifications to a move map for a move onto this
120 * square completes.
121 *
122 * Used to implement powerups; others can safely do nothing.
123 */
124 public void postMove(GameState gs, Map<Position, Piece> move,
125 Position here) {
126 }
127
128 /**
129 * This should be unique for different pieces or different
130 * colors.
131 */
132 abstract public int hashCode();
133 }