package apostov;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.apache.commons.math3.fraction.Fraction;
import org.apache.commons.math3.util.Combinations;
import org.apache.commons.math3.util.CombinatoricsUtils;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

public class HandResultEnumerator {

	public ImmutableMap<HolecardHand, Fraction> enumerateBoardsAndMeasureWins(final ImmutableList<HolecardHand> candidates) {
		final ImmutableList<Card> deck = new DeckFactory().newDeck(
				candidates.stream()
					.map(HolecardHand::getHolecardsAsList)
					.flatMap(Collection::stream)
					.collect(toSet())
		);
		
		final ShowdownEvaluator evaluator = new ShowdownEvaluator();
		final int binomialCoefficient = (int) CombinatoricsUtils.binomialCoefficient(deck.size(), 5);
		
		final Map<HolecardHand, Fraction> overallSuccessChanceByHand = StreamSupport.stream(new Combinations(deck.size(), 5).spliterator(), false)
			.map((a) -> stream(a).mapToObj(i -> deck.get(i)).collect(toList()))
			.map(l -> {
				assert l.size() == 5;
				return new Board(l.get(0), l.get(1), l.get(2), l.get(3), l.get(4));
			})
			.map(b -> evaluator.evaluateShowdown(candidates, b))
			.map(wc -> Maps.toMap(wc, w -> new Fraction(1, binomialCoefficient * wc.size())))
			.map(Map::entrySet)
			.flatMap(Collection::stream)
			.collect(Collectors.toMap(
						Map.Entry::getKey,
						Map.Entry::getValue,
						(x, y) -> x.add(y)
					)
			);
		
		return ImmutableMap.copyOf(overallSuccessChanceByHand);
	}
	
}

@@ -205,24 +205,199 @@
 .util.Map;%0D%0A
+import java.util.concurrent.Callable;%0D%0Aimport java.util.concurrent.ConcurrentMap;%0D%0Aimport java.util.concurrent.ExecutionException;%0D%0Aimport java.util.concurrent.ForkJoinPool;%0D%0A
 import java.
@@ -1308,64 +1308,253 @@
 nal 
-Map%3CHolecardHand, Fraction%3E overallSuccessChanceByHand =
+ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());%0D%0A%09%09final Map%3CHolecardHand, Fraction%3E overallSuccessChanceByHand;%0D%0A%09%09final Callable%3CConcurrentMap%3CHolecardHand, Fraction%3E%3E successChanceComputationTask = %0D%0A%09%09%09() -%3E
  Str
@@ -1623,19 +1623,19 @@
 (), 
-fals
+tru
 e)%0D%0A%09%09%09
+%09
 .map
@@ -1698,24 +1698,25 @@
 ist()))%0D%0A%09%09%09
+%09
 .map(l -%3E %7B%0D
@@ -1716,16 +1716,17 @@
 l -%3E %7B%0D%0A
+%09
 %09%09%09%09asse
@@ -1748,16 +1748,17 @@
 5;%0D%0A%09%09%09%09
+%09
 return n
@@ -1825,12 +1825,14 @@
 %0A%09%09%09
+%09
 %7D)%0D%0A
+%09
 %09%09%09.
@@ -1883,24 +1883,25 @@
 es, b))%0D%0A%09%09%09
+%09
 .map(wc -%3E M
@@ -1974,16 +1974,17 @@
 )))%0D%0A%09%09%09
+%09
 .map(Map
@@ -1996,16 +1996,17 @@
 rySet)%0D%0A
+%09
 %09%09%09.flat
@@ -2030,16 +2030,17 @@
 tream)%0D%0A
+%09
 %09%09%09.coll
@@ -2052,24 +2052,34 @@
 ollectors.to
+Concurrent
 Map(%0D%0A%09%09%09%09%09%09
@@ -2154,23 +2154,211 @@
 d(y)
+));
 %0D%0A%09%09
-%09%09%09)%0D%0A%09%09%09);
+%0D%0A%09%09try %7B%0D%0A%09%09%09overallSuccessChanceByHand = pool.submit(successChanceComputationTask).get();%0D%0A%09%09%7D catch (final InterruptedException %7C ExecutionException e) %7B%0D%0A%09%09%09throw new RuntimeException(e);%0D%0A%09%09%7D
 %0D%0A%09%09

Use all the available CPU cores.