game-client

Play TicTacToe and Reversi
Log | Files | Refs

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 }