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 }