001 package antichess; 002 003 004 005 /** 006 * TextPlayer implements the GamePlayer interface. TextPlayer 007 * is for use with the TextUI. The TextPlayer implements thet TextGamePlayer 008 * interface which extends the GamePlayer interface, so it properly implements the methods 009 * required of a GamePlayer. The TextGamePlayer interface supports methods that the TextUI 010 * will call in order to fit the specifications for the TextUI. 011 * 012 * 013 * @author nlharr 014 * 015 * 016 * @specfield clock //GameClock that store the timer for this TextPlayer 017 * @specfield playerType //Player of this TextPlayer 018 * @specfield currentMove //ChessMove that the TextPlayer is caching that the controller can access 019 * @specfield controller //GameController 020 */ 021 022 023 public class TextPlayer implements TextGamePlayer{ 024 private AntichessBoard board; 025 private GameClock clock; 026 private Player playerType; 027 private ChessMove moveForController; 028 private GameController controller; 029 030 // Abstraction Function 031 //clock = clock 032 //playerType = playerType 033 //controller = controller 034 //currentMove = moveForController 035 036 //Representation Invariants 037 //clock != null 038 //playerType != Player.NONE 039 040 041 private void checkRep(){ 042 if (clock == null) throw new RuntimeException("Clock is null"); 043 if (playerType.equals(Player.NONE)) throw new RuntimeException("PlayerType is none"); 044 } 045 046 047 /** 048 * Creates a new TextAIPlayer 049 * currentMove = null 050 * clock = clock 051 * playerType = playerType 052 * board = board 053 */ 054 public TextPlayer(AntichessBoard board, GameClock clock, 055 Player playerType){ 056 this.board = board; 057 this.clock = clock; 058 this.playerType = playerType; 059 this.moveForController = null; 060 checkRep(); 061 } 062 063 064 /** 065 * @see GamePlayer 066 * @return false; 067 */ 068 public boolean automaticallyTimed() { 069 return false; 070 } 071 072 /** 073 * @see GamePlayer 074 * @modifies controller, currentMove 075 * @effects controller = controller, currentMove = null; 076 * @return currentMove (the value before it is made null) 077 */ 078 public synchronized ChessMove getMove(GameController controller) { 079 080 this.controller = controller; 081 ChessMove tempMove = moveForController; 082 moveForController = null; 083 return tempMove; 084 } 085 086 public void gameEnded() { 087 088 } 089 090 /** 091 * @see GamePlayer 092 * @return playerType 093 */ 094 public Player getPlayerType() { 095 return playerType; 096 } 097 098 099 //converts a letter to a column number 100 private static int letterToInt(String letter){ 101 if (letter.equals("a")){ 102 return 0; 103 } else if (letter.equals("b")){ 104 return 1; 105 } else if (letter.equals("c")){ 106 return 2; 107 } else if (letter.equals("d")){ 108 return 3; 109 } else if (letter.equals("e")){ 110 return 4; 111 } else if (letter.equals("f")){ 112 return 5; 113 } else if (letter.equals("g")){ 114 return 6; 115 } else if (letter.equals("h")){ 116 return 7; 117 } else { 118 throw new NumberFormatException("invalid letter"); 119 } 120 } 121 122 /** 123 * Converts a string 'move' to the move specified by the 124 * @return a ChessMove that the string 'move' represents 125 * @throws NumberFormatException, IllegalArgumentException if the format of the move does not match 126 * the given specifications 127 */ 128 public static ChessMove stringToMove(String move, AntichessBoard board) throws NumberFormatException, IllegalArgumentException{ 129 if (move.length() != 5){ 130 throw new IllegalArgumentException("String is improper length"); 131 } 132 int startRow = Integer.valueOf(move.substring(1, 2))-1; 133 int endRow = Integer.valueOf(move.substring(4, 5))-1; 134 int startColumn = letterToInt(move.substring(0,1)); 135 int endColumn = letterToInt(move.substring(3,4)); 136 if (board.getPieceAt(startRow, startColumn)==null){ 137 throw new IllegalArgumentException("No piece at that row"); 138 } 139 return board.createMove(board.getPieceAt(startRow, startColumn), endRow, endColumn); 140 141 } 142 143 144 /** 145 * 146 * @modifies currentMove, clock 147 * @effects if moveString represents a valid move currentMove = move represented by moveString 148 * if moveString represents a valid move the timer in clock for this TextPlayer is decremented 149 * by time 150 * Once this happens it notifies the controller that is has a move 151 * and prints moveString to stdout. 152 * 153 * Prints "Illegal move" to stdout if moveString does not represent a valid 154 * move. 155 * @return false if the move represented by moveString is illegal 156 * or the format of moveString is invalid 157 * false if the board says it is a different players move 158 * true else 159 * 160 * @throws RuntimeException if the TextPlayer has not had a move requested 161 */ 162 163 public synchronized boolean doMove(String moveString, long time){ 164 //checks if it is the proper players turn 165 if (!board.getPlayer().equals(this.getPlayerType())){ 166 return false; 167 } 168 169 //converts the string to a move and checks if it's legal 170 ChessMove move; 171 try{ 172 move = stringToMove(moveString, board); 173 } 174 catch (Exception ex){ 175 System.out.println("Illegal move"); 176 return false; 177 } 178 if (!board.isMoveLegal(move)){ 179 System.out.println("Illegal move"); 180 return false; 181 } 182 183 184 //notifies the controller that we have a move 185 if (this.controller == null){ 186 throw new RuntimeException("Controller is null"); 187 } 188 if (clock.hasPlayer(playerType)){ 189 clock.setTime(clock.getTime(playerType)-time, playerType); 190 } 191 192 System.out.println(moveString); 193 moveForController = move; 194 controller.notifyControllerHasMove(); 195 return true; 196 } 197 198 199 /** 200 * Prints 'Human turn' to stdout 201 */ 202 public void getPossibleMove(){ 203 System.out.println("Human turn"); 204 } 205 206 207 /** 208 * Prints 'Please specify human move' to stdout 209 * @return false 210 */ 211 public boolean doPossibleMove(){ 212 System.out.println("Please specify human move"); 213 return false; 214 } 215 216 217 218 }