Headless.java (5650B)
1 package nl.isygameclient; 2 3 import com.google.gson.Gson; 4 import com.google.gson.reflect.TypeToken; 5 import java.io.IOException; 6 import java.lang.reflect.Type; 7 import java.nio.file.Files; 8 import java.nio.file.NoSuchFileException; 9 import java.nio.file.Paths; 10 import java.util.*; 11 import java.util.concurrent.Executors; 12 import java.util.concurrent.locks.Lock; 13 import java.util.concurrent.locks.ReentrantLock; 14 import java.util.stream.Collectors; 15 import nl.isygameclient.models.Ai; 16 import nl.isygameclient.models.Game; 17 import nl.isygameclient.models.Player; 18 import nl.isygameclient.models.PlayerManager; 19 import nl.isygameclient.models.games.Othello; 20 import nl.isygameclient.util.DataSaver; 21 import nl.isygameclient.util.Vector2D; 22 23 24 public class Headless { 25 private static final String JSON_FILENAME = "heuristics.json"; 26 private static final int THREAD_POOL_SIZE = 10; 27 private static final int ROUNDS_PER_GAME = 100; 28 29 private static long calculateAverage(List<Long> values) { 30 long sum = values.stream().mapToLong(Long::longValue).sum(); 31 return sum / values.size(); 32 } 33 34 private static Map<String, Game> createGames(Map<String, int[][]> heuristics) { 35 Map<String, Game> games = new HashMap<>(); 36 for (Map.Entry<String, int[][]> heuristic1 : heuristics.entrySet()) { 37 for (Map.Entry<String, int[][]> heuristic2 : heuristics.entrySet()) { 38 39 ArrayList<Player> players = new ArrayList<>(); 40 players.add(new Ai(heuristic1.getKey(), "black", heuristic1.getValue())); 41 players.add(new Ai(heuristic2.getKey(), "white", heuristic2.getValue())); 42 43 var playerManager = new PlayerManager(0, players); 44 Othello othello = new Othello(playerManager); 45 games.put(heuristic1.getKey() + ", " + heuristic2.getKey(), othello); 46 } 47 } 48 return games; 49 } 50 51 private static String buildDataString( 52 String gameName, int gameTurns, boolean isDraw, Player winner, long totalGameTime, 53 Map<Player, ArrayList<Long>> playersTimePerMoves, 54 Map<Player, ArrayList<Vector2D<Integer, Integer>>> playersMovesMade) { 55 StringBuilder builder = new StringBuilder(); 56 57 String joined = String.join(",", gameName, String.valueOf(gameTurns), String.valueOf(isDraw), 58 winner.getPlayerName(), winner.getPlayingAs(), String.valueOf(totalGameTime)) + 59 ","; 60 builder.append(joined); 61 62 playersTimePerMoves.forEach((k, v) -> { 63 var average = calculateAverage(v); 64 builder.append(average).append(","); 65 }); 66 playersMovesMade.forEach((k, v) -> { 67 String listString = v.stream().map(Object::toString).collect(Collectors.joining("; ")); 68 builder.append(listString).append(","); 69 }); 70 return builder.toString(); 71 } 72 73 private static Map<String, int[][]> loadHeuristics() { 74 try { 75 Type mapType = new TypeToken<Map<String, int[][]>>() { 76 }.getType(); 77 String inFile = new String(Files.readAllBytes(Paths.get(JSON_FILENAME))); 78 return new Gson().fromJson(inFile, mapType); 79 } catch (NoSuchFileException e) { 80 System.err.println("NO HEURISTICS JSON HAS BEEN PROVIDED."); 81 e.printStackTrace(); 82 } catch (IOException e) { 83 e.printStackTrace(); 84 } 85 return null; 86 } 87 88 public static void main(String[] args) { 89 var heuristics = loadHeuristics(); 90 if (heuristics == null) { 91 System.err.println("No heuristics in file."); 92 return; 93 } 94 95 var executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE); 96 var games = createGames(heuristics); 97 var dataSaver = new DataSaver(); 98 dataSaver.saveData("Name Ai1, Name Ai2, Game Turns, Draw, Winner Name, Winner Playing As, Total Game Time, Average Time Per Move Ai1, Average Time Per Move Ai2, Moves Ai1, Moves Ai2"); 99 for (Map.Entry<String, Game> game : games.entrySet()) { 100 Runnable simulation = new Simulation(game.getKey(), game.getValue(), ROUNDS_PER_GAME, new ReentrantLock(), dataSaver); 101 executor.execute(simulation); 102 } 103 executor.shutdown(); 104 105 while (!executor.isTerminated()) { 106 } 107 108 System.out.println("All simulations completed successfully."); 109 } 110 111 private record Simulation(String gameName, Game game, int rounds, Lock lock, DataSaver dataSaver) implements Runnable { 112 @Override 113 public void run() { 114 System.out.println("Starting simulation: " + gameName); 115 116 var playerManager = game.getPlayerManager(); 117 for (int i = 0; i < rounds; i++) { 118 System.out.println("Start round" + i + " " + gameName); 119 120 Map<Player, ArrayList<Long>> playersTimePerMoves = new HashMap<>(); 121 Map<Player, ArrayList<Vector2D<Integer, Integer>>> PlayersMovesMade = new HashMap<>(); 122 123 long totalGameTime = 0; 124 int gameTurns = 0; 125 while (!game.isGameOver()) { 126 gameTurns++; 127 var currentPlayer = playerManager.getCurrentPlayer(); 128 if (game.getValidMoves(currentPlayer).isEmpty()) { 129 playerManager.nextPlayer(); 130 continue; 131 } 132 133 final long startTime = System.currentTimeMillis(); 134 var move = currentPlayer.onPlayerTurn(); 135 game.move(currentPlayer, move); 136 final long endTime = System.currentTimeMillis(); 137 final long deltaTime = endTime - startTime; 138 totalGameTime += deltaTime; 139 140 PlayersMovesMade.computeIfAbsent(currentPlayer, k -> new ArrayList<>()).add(move); 141 playersTimePerMoves.computeIfAbsent(currentPlayer, k -> new ArrayList<>()).add(deltaTime); 142 } 143 144 var winner = game.getWinners().get(0); 145 var data = buildDataString(gameName, gameTurns, game.isDraw(), winner, totalGameTime, playersTimePerMoves, PlayersMovesMade); 146 147 lock.lock(); 148 try { 149 dataSaver.saveData(data); 150 } finally { 151 lock.unlock(); 152 } 153 game.restart(); 154 System.out.println("end round" + i + " " + gameName); 155 } 156 System.out.println(gameName + " has finished"); 157 } 158 } 159 }