package ch.epfl.maze.util; import ch.epfl.maze.physical.Animal; import ch.epfl.maze.simulation.Simulation; import java.util.*; /** * Utility class that allows to compute statistics on a list of results. * * @author EPFL */ public final class Statistics { /* constants for the length of the distribution axis */ public static final int X_LENGTH = 40; public static final int Y_LENGTH = 13; /** * Returns the sum of all the numbers in results. * * @param results List of numbers * @return The total of the list */ public static int total(List results) { int total = 0; for (Integer result : results) { if (result == Integer.MAX_VALUE) { return Integer.MAX_VALUE; } total += result; } return total; } /** * Returns the mean of the numbers in results. *

* mean(X) = total(X) / N * * @param results List of numbers * @return The mean of the results */ public static int mean(List results) { int total = total(results); if (total == Integer.MAX_VALUE) { return Integer.MAX_VALUE; } return total / results.size(); } /** * Returns the variance of the numbers in results. *

* var(X) = (X - mean(X)) / N * * @param results List of numbers * @return The variance of the results */ public static double var(List results) { double mean = mean(results); if (mean == Integer.MAX_VALUE) { return Integer.MAX_VALUE; } double var = 0; for (Integer result : results) { var += (result - mean) * (result - mean); } return var / results.size(); } /** * Returns the standard deviation of the numbers in results. *

* std(X) = sqrt(var(X)) * * @param results List of numbers * @return The variance of the results */ public static double std(List results) { return Math.sqrt(var(results)); } /** * Computes distribution for each animal in simulation * * @param simulation Simulation to make statistics on * @param numberOfSimulations The number of simulations */ public static Map> computeStatistics( Simulation simulation, int numberOfSimulations) { // maps animals' names with their overall results (which are linked-list) Map> results = new TreeMap>(); for (Animal a : simulation.getWorld().getAnimals()) { results.put(a.getClass().getSimpleName(), new LinkedList()); } // simulates world a lot of times for (int i = 0; i < numberOfSimulations; i++) { // simulates world until the end simulation.restart(); while (!simulation.isOver()) { simulation.move(null); } // retrieves arrival times and appends them to the results Map> arrivalTimes = simulation.getArrivalTimes(); for (Map.Entry> entry : arrivalTimes.entrySet()) { for (Animal a : entry.getValue()) { String animalName = a.getClass().getSimpleName(); List list = results.get(animalName); list.add(entry.getKey()); } } } return results; } /** * Prints the distribution of all the results. * * @param results List of numbers */ public static void printDistribution(List results) { int min = results.get(0); int max = results.get(results.size() - 1); int length = (max - min) / X_LENGTH; // counts number of steps inside a range int lowerBound = Integer.MIN_VALUE; int upperBound = min + length; int index = 0; List boxPlot = new ArrayList<>(); for (int i = 0; i < X_LENGTH; i++) { int counter = 0; while (index < results.size() && (results.get(index) > lowerBound && results.get(index) <= upperBound)) { counter++; index++; } boxPlot.add(counter); lowerBound = upperBound; upperBound += length; } // draws plot on string String[] printPlot = new String[Y_LENGTH]; for (int i = 0; i < Y_LENGTH; i++) { printPlot[i] = "| "; } int maxCount = Collections.max(boxPlot); for (Integer count : boxPlot) { for (int i = 0; i < Y_LENGTH; i++) { if (count > (i * maxCount) / Y_LENGTH) { printPlot[i] += "#"; } else { printPlot[i] += " "; } } } // prints plot System.out.println("\n^"); for (int i = Y_LENGTH - 1; i > 0; i--) { System.out.println(printPlot[i]); } System.out.print("--"); for (int i = 0; i < X_LENGTH; i++) { System.out.print("-"); } System.out.println(">"); } }