package model; import model.Board.TileColor; import model.comPlayer.HumanPlayer; import model.comPlayer.Player; import model.playerModel.PlayerModel; import org.apache.log4j.Logger; import view.BoardPanel; import view.HighScoreDialog; import view.MainFrame; import view.ScorePanel; public class Referee implements Runnable { public static final String COM_TURN = "Waiting for the computer's move."; public static final String GAME_OVER = "Game over!"; public static final Logger LOGGER = Logger.getLogger(Referee.class .getName()); public static final String PLAYER_TURN = "Waiting for the player's move."; public static boolean[] getBoardState(Board brd) { boolean[] boardState = new boolean[(Board.NUM_COLS * Board.NUM_ROWS * (Board.TileColor .values().length - 1))]; int i = 0; for (int r = 0; r < Board.NUM_ROWS; r++) { for (int c = 0; c < Board.NUM_COLS; c++) { boardState[i] = (brd.getTile(r, c) == TileColor.BLUE); boardState[i + 1] = (brd.getTile(r, c) == TileColor.GREEN); boardState[i + 2] = (brd.getTile(r, c) == TileColor.RED); boardState[i + 3] = (brd.getTile(r, c) == TileColor.YELLOW); i += 4; } } return boardState; } private Board board; private BoardPanel boardPanel; private final Player computerPlayer; private final HumanPlayer humanPlayer = new HumanPlayer(); private final MainFrame mf; private PlayerModel playerModel = null; public Referee(MainFrame mnFrm, String player, Player computerPlayer) { if (PlayerModel.exists(player)) { PlayerModel.getPlayerPath(player); playerModel = PlayerModel.load(PlayerModel.getPlayerPath(player)); } if (getPlayerModel() == null) { playerModel = new PlayerModel(player); } mf = mnFrm; this.computerPlayer = computerPlayer; initGame(); } public Player getComputerPlayer() { return computerPlayer; } public HumanPlayer getHumanPlayer() { return humanPlayer; } public String getMessage() { if (isOver()) { return GAME_OVER; } else if (board.isPlayerTurn()) { return PLAYER_TURN; } else { return COM_TURN; } } public int getPlayerScore() { return board.getTurn(); } public TileColor getTile(int r, int c) { return board.getTile(r, c); } public boolean isOver() { return board.isTerminalState(); } public void playToken(Move move) { board.playTile(move.getCell(), move.getColor()); } @Override public void run() { while (true) { initGame(); mf.updateBoard(); play(); getPlayerModel().logGame(getPlayerScore()); if (!getPlayerModel().save()) { System.err.println("Saving PlayerModel failed."); } new HighScoreDialog(mf, getPlayerModel()); } } public void setBoardPanel(BoardPanel boardPanel) { this.boardPanel = boardPanel; } private boolean[] getMoveArray(Move mv) { boolean[] move = new boolean[getPlayerModel().getNumOutputNodes()]; move[0] = (mv.getColor() == TileColor.BLUE); move[1] = (mv.getColor() == TileColor.GREEN); move[2] = (mv.getColor() == TileColor.RED); move[3] = (mv.getColor() == TileColor.YELLOW); int tile = 0; for (int r = 0; r < Board.NUM_ROWS; r++) { for (int c = 0; c < Board.NUM_COLS; c++) { move[tile + 4] = (mv.getCell().r == r && mv.getCell().c == c); tile++; } } return move; } private PlayerModel getPlayerModel() { return playerModel; } private ScorePanel getScorePanel() { return mf.getScorePanel(); } private void initGame() { board = new Board(); } private void play() { int plies = 0; while (!isOver()) { if (board.isPlayerTurn()) { boolean wasInterrupted = false; while (!humanPlayer.isReady()) { try { Thread.sleep(250L); } catch (InterruptedException ie) { wasInterrupted = true; } } if (wasInterrupted) { System.out .println("Interrupted while waiting for human to move!"); } else { getPlayerModel().getOutputNodes(getBoardState(board)); Move mv = humanPlayer.getMove(board, playerModel); if (board.getTile(mv.getCell().r, mv.getCell().c) == TileColor.NONE) { playToken(humanPlayer.getMove(board, playerModel)); getPlayerModel().train(getMoveArray(mv)); } else { humanPlayer.denyMove(); } } } else { Move mv = computerPlayer.getMove(board, getPlayerModel()); playToken(mv); // This is the call that gets a prediction of a user's move. // Some changes will probably be necessary to put it in the // right place and also to get the node weights. But... all in // due time. // UPDATE: I made a neural network agent. This call is in there // now. If the current agent doesn't use the neural network, // then this doesn't need to be called. It will just train on // random, meaningless data. // getPlayerModel().getOutputNodes(getBoardState(board)); } getScorePanel().updateScore(getPlayerScore()); mf.updateMessage(getMessage()); boardPanel.updateIcons(); LOGGER.info("plies: " + plies++); try { Thread.sleep(250L); } catch (InterruptedException ie) { System.out .println("Interrupted while waiting for human view ply!"); } } } }