package model.playerModel; import java.util.Random; import model.Board; import model.playerModel.node.InputNode; import model.playerModel.node.SigmoidNode; public class PlayerModel { public static final Random rand = new Random(); private final SigmoidNode[] hiddenLayer; private final int[] highScore = new int[10]; private int highScoresAchieved = 0; // One node for each tile-color combination, plus one for each upcoming // tile-color combination. private final InputNode[] inputNode = new InputNode[(Board.NUM_COLS * Board.NUM_ROWS * (Board.TileColor.values().length - 1))]; private int nextHighInGames = 0; // One node for each tile plus four for the colors to be selected. // outputNode[0] is blue. // outputNode[1] is green. // outputNode[2] is red. // outputNode[3] is yellow. // outputNode[4] through outputNode[n] represent grid spaces. A true means // that the player is predicted to place on that tile. // They should be read from the top-left to bottom-right, across rows. // Ideally, the network should return only one true between 0 and 3 and only // one true between 4 and n, representing one color and the tile in which it // should be placed. private final SigmoidNode[] outputNode = new SigmoidNode[(Board.NUM_COLS * Board.NUM_ROWS) + 4]; public PlayerModel() { for (int i = 0; i < highScore.length; i++) { highScore[i] = -1; } hiddenLayer = new SigmoidNode[inputNode.length + ((inputNode.length * 2) / 3)]; for (int i = 0; i < inputNode.length; i++) { inputNode[i] = new InputNode(); } for (int i = 0; i < hiddenLayer.length; i++) { hiddenLayer[i] = new SigmoidNode(); for (int j = 0; j < inputNode.length; j++) { hiddenLayer[i].addNode(inputNode[j], 1); } } for (int i = 0; i < outputNode.length; i++) { outputNode[i] = new SigmoidNode(); for (int j = 0; j < hiddenLayer.length; j++) { outputNode[i].addNode(hiddenLayer[j], 1); } } } public int[] getHighScores() { return highScore; } public boolean[] getPrediction(boolean[] input) { if (input.length == inputNode.length) { boolean[] prediction = new boolean[outputNode.length]; for (int i = 0; i < input.length; i++) { inputNode[i].setStimulation(input[i]); } for (int i = 0; i < prediction.length; i++) { prediction[i] = outputNode[i].axon(); } return prediction; } return null; } public GameGoal getTargetScore() { GameGoal goal; int targetScore; int highScore = getHighScore(); if (highScoresAchieved == 0) { goal = new GameGoal(0, true); nextHighInGames = 1; } else if (nextHighInGames == 0) { // Set next game for high score. nextHighInGames = (int) (Math.pow(highScoresAchieved + 1, 2) / 2); // Return high score times increase percentage. targetScore = highScore / (2 * (highScoresAchieved + 1)); if (targetScore <= highScore) { targetScore = highScore + 1; } goal = new GameGoal(targetScore, true); } else { double scoreReduction = .1 * rand.nextDouble(); targetScore = (int) (highScore - (highScore * scoreReduction)); if (targetScore >= highScore) { targetScore = highScore - 1; } goal = new GameGoal(targetScore, false); } return goal; } public void logGame(int score) { if (highScore[0] == -1) { highScore[0] = score; } else { loop: for (int i = 0; i < highScore.length; i++) { if (score > highScore[i]) { for (int j = highScore.length - 2; j >= i; j--) { highScore[j + 1] = highScore[j]; } highScore[i] = score; break loop; } } } highScoresAchieved += (score == highScore[0]) ? 1 : 0; nextHighInGames--; } public void train(boolean[] example) { if (example.length == outputNode.length) { for (int i = 0; i < outputNode.length; i++) { outputNode[i].learn(example[i]); } } } private int getHighScore() { return highScore[0]; } }