package com.srs.tetris.bob;

import com.srs.tetris.game.Game;
import com.srs.tetris.game.GameSettings;
import com.srs.tetris.player.Player;
import java.util.Collections;
import java.util.List;
import java.util.OptionalDouble;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

public class PlayerEvaluator {

	private int threads = Runtime.getRuntime().availableProcessors();

	private int games;
	private List<Future<Game>> futures;

	public PlayerEvaluator(int games) {
		this.games = games;
	}

	public void evaluate() throws InterruptedException, ExecutionException {

		ExecutorService executor = Executors.newFixedThreadPool(threads);

		long start = System.currentTimeMillis();

		futures = executor.invokeAll(IntStream.range(0, games)
			.mapToObj(i -> new Callable<Game>() {
				@Override
				public Game call() throws Exception {
					System.out.println("Starting game " + i);
					return createAndPlayGame();
				}
			})
			.collect(toList())
		);

		double averageLines = futures.stream().map(this::unwrapFuture)
			.mapToInt(g -> g.getCompletedLines())
			.average().orElse(0.0);

		double averageScore = futures.stream().map(this::unwrapFuture)
			.mapToInt(g -> g.getScore())
			.average().orElse(0.0);

		double averageElapsedTime = futures.stream().map(this::unwrapFuture)
			.mapToDouble(g -> g.getEndTime() - g.getStartTime())
			.average().orElse(0.0);

		double elapsed = (System.currentTimeMillis() - start) / 1e3;

		System.out.println();
		System.out.printf("Average Lines: %.2f\n", averageLines);
		System.out.printf("Average Score: %,.2f\n", averageScore);
		System.out.printf("Average Elapsed Time (ms): %,.2f\n", averageElapsedTime);
		System.out.println();
		System.out.printf("Total Elapsed Time (s): %,.3f\n", elapsed);
	}

	private Game createAndPlayGame() {
		Game game = createGame();
		game.run();
		return game;
	}

	private Game createGame() {
		BobPlayer player = new BobPlayer();

		GameSettings gameSettings = GameSettings.direct(player);
		Game game = new Game(gameSettings);
		game.init();

		return game;
	}

	private <T> T unwrapFuture(Future<T> future) {
		try {
			return future.get();
		} catch (Throwable t) {
			throw new RuntimeException(t);
		}
	}

	public static void main(String[] args) throws ExecutionException, InterruptedException {
		PlayerEvaluator evaluator = new PlayerEvaluator(1000);
		evaluator.evaluate();
	}
}

@@ -163,16 +163,97 @@
 ctions;%0A
+import java.util.DoubleSummaryStatistics;%0Aimport java.util.IntSummaryStatistics;%0A
 import j
@@ -506,16 +506,66 @@
 Future;%0A
+import java.util.concurrent.atomic.AtomicInteger;%0A
 import j
@@ -964,16 +964,59 @@
 eption %7B
+%0A%09%09long start = System.currentTimeMillis();
 %0A%0A%09%09Exec
@@ -1084,50 +1084,52 @@
 %0A%0A%09%09
-long start = System.currentTimeMillis(
+AtomicInteger count = new AtomicInteger(0
 );%0A
-%0A
 %09%09fu
@@ -1159,48 +1159,26 @@
 All(
-Int
 Stream.
-range(0, games)%0A%09%09%09.mapToObj(i
+generate(()
  -%3E 
@@ -1281,34 +1281,83 @@
 rint
-ln(%22Starting game %22 + i
+(%22.%22);%0A%09%09%09%09%09if (count.incrementAndGet() %25 100 == 0) System.out.println(
 );%0A
+%0A
 %09%09%09%09
@@ -1397,16 +1397,33 @@
 %7D%0A%09%09%09%7D)%0A
+%09%09%09.limit(games)%0A
 %09%09%09.coll
@@ -1448,23 +1448,54 @@
 %0A%0A%09%09
-double averageL
+executor.shutdown();%0A%0A%09%09IntSummaryStatistics l
 ines
@@ -1587,49 +1587,54 @@
 %09%09%09.
-average().orElse(0.0);%0A%0A%09%09double averageS
+summaryStatistics();%0A%0A%09%09IntSummaryStatistics s
 core
@@ -1717,59 +1717,63 @@
 %09%09%09.
-average().orElse(0.0
+summaryStatistics(
 );%0A%0A%09%09
-d
+D
 ouble
- averageE
+SummaryStatistics e
 lapsed
-Time
  = f
@@ -1829,24 +1829,25 @@
 Double(g -%3E 
+(
 g.getEndTime
@@ -1872,33 +1872,38 @@
 e())
-%0A%09%09%09.average().orElse(0.0
+ / 1e3)%0A%09%09%09.summaryStatistics(
 );%0A%0A
@@ -1911,17 +1911,22 @@
 %09double 
-e
+totalE
 lapsed =
@@ -2017,211 +2017,229 @@
 rint
-f(%22Average Lines: %25.2f%5Cn%22, averageLines);%0A%09%09System.out.printf(%22Average Score: %25,.2f%5Cn%22, averageScore);%0A%09%09System.out.printf(%22Average Elapsed Time (ms): %25,.2f%5Cn%22, averageElapsedTime);%0A%09%09System.out.println(
+ln();%0A%09%09System.out.println(%22Lines: %22 + lines);%0A%09%09System.out.println(%22Score: %22 + score);%0A%09%09System.out.println(%22Elapsed: %22 + elapsed);%0A%09%09System.out.println();%0A%09%09System.out.printf(%22Average Lines: %25,.2f%5Cn%22, lines.getAverage()
 );%0A%09
@@ -2292,17 +2292,22 @@
 .3f%5Cn%22, 
-e
+totalE
 lapsed);

Print max and min stats as well