package uucki;

import uucki.game.reversi.Board;
import uucki.algorithm.Algorithm;
import uucki.algorithm.MonteCarloTreeSearch;
import uucki.algorithm.Minimax;
import uucki.type.FieldValue;
import uucki.modes.VersusAI;
import uucki.modes.AIvsAI;
import uucki.modes.CustomBoard;

import java.io.*;
import java.util.*;

public class OptimizeParameter {

    public final static int POPULATION_LIMIT = 1;
    public final static int GENERATIONS = 1;
    public static Random random;

    public static void main(String[] args) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        random = new Random();

        double lowEnd = 0.0;
        double highEnd = 10.0;
        try {
            System.out.println("Low end number to search");
            lowEnd = Double.parseDouble(br.readLine());
            System.out.println("high end number to search");
            highEnd = Double.parseDouble(br.readLine());
        } catch (IOException e) {
            System.out.println("IO error");
            return;
        }

        List<Double> population = new ArrayList<Double>(POPULATION_LIMIT);

        for(int i = 0; i < POPULATION_LIMIT; i++) {
            double value = random.nextDouble() * (highEnd - lowEnd) + lowEnd;
            population.add(value);
        }

        for(int i = 0; i < GENERATIONS; i++) {
            double mean = mean(population);
            double variance = variance(population);
            System.out.println(i + "," + mean + "," + variance);
            population = grow(population, variance);
            population = tournament(population);
        }

    }

    private static double mean(List<Double> list) {
        return list.stream().mapToDouble(a -> a).average().getAsDouble();
    }

    private static double variance(List<Double> list) {
        double mean = mean(list);
        return list.stream().mapToDouble(a -> Math.abs(mean - a)).sum() / list.size();
    }

    public static List<Double> grow(List<Double> population, double variance) {
        List<Double> newPopulation = new ArrayList<Double>(population);
        population.stream().map(d -> mutate(d, variance)).forEach(d -> newPopulation.add(d));
        return newPopulation;
    }

    private static double mutate(double value, double variance) {
        double range = variance;
        return random.nextGaussian() * range + value;
    }

    public static List<Double> tournament(List<Double> population) {
        List<Double> newPopulation = new ArrayList<Double>(POPULATION_LIMIT);

        while(population.size() >= 2) {
            Double value1 = anyItem(population);
            Double value2 = anyItem(population);
            newPopulation.add(runGame(value1, value2));
        }

        return newPopulation;
    }

    //get and remove random element from list
    private static double anyItem(List<Double> population) {
        int index = random.nextInt(population.size());
        return population.remove(index);
    }

    public static double runGame(double value1, double value2) {
        //System.out.println("Running game, white: " + value1 + ", black: " + value2);
        int value1Wins = 0;
        int value2Wins = 0;
        for(int i = 0; i < 2; i++) {
            double winningValue = 0;
            if (i % 2 == 0) {
                winningValue = runSingleGame(value1, value2);
            } else {
                winningValue = runSingleGame(value2, value1);
            }
            if(winningValue == value1) {
                value1Wins++;
            } else {
                value2Wins++;
            }
        }
        //System.out.println("Winner: " + (value1Wins > value2Wins ? value1 : value2));
        if(value1Wins > value2Wins) {
            return value1;
        }
        return value2;
    }

    public static double runSingleGame(double value1, double value2) {
        Algorithm ai1 = new MonteCarloTreeSearch(value1, true, false);
        Algorithm ai2 = new MonteCarloTreeSearch(value2, true, false);
        Board board = Board.initialBoard(false);
        AIvsAI mode = new AIvsAI(board, ai1, ai2);
        board = mode.game();
        if(board.getWinner() == FieldValue.WHITE) {
            return value1;
        } else {
            return value2;
        }
    }
}

@@ -629,24 +629,1170 @@
  Random();%0A%0A
+        List%3CDouble%3E population = new ArrayList%3CDouble%3E();%0A        population.add(0.25);%0A        population.add(0.75);%0A        population.add(1.0);%0A        population.add(1.25);%0A        population.add(1.5);%0A        population.add(1.75);%0A        population.add(2.0);%0A        rankPopulation(population);%0A    %7D%0A%0A    private static void rankPopulation(List%3CDouble%3E population) %7B%0A        HashMap%3CDouble, Integer%3E score = new HashMap%3CDouble, Integer%3E(population.size());%0A        for(Double c : population) %7B%0A            for(int round = 0; round %3C 10; round++) %7B%0A%0A                for(Double opponent : population) %7B%0A                    if (opponent == c) %7B%0A                        continue;%0A                    %7D%0A%0A                    double winner = runGame(c, opponent);%0A                    int currentScore = score.getOrDefault(winner, 0);%0A                    score.put(winner, currentScore+1);%0A                %7D%0A            %7D%0A        %7D%0A%0A        for(Map.Entry%3CDouble, Integer%3E entry : score.entrySet()) %7B%0A            System.out.println(entry.getKey() + %22: %22 + entry.getValue());%0A        %7D%0A    %7D%0A%0A    private static void findBestC(BufferedReader br) %7B%0A
         doub
@@ -1804,24 +1804,24 @@
 wEnd = 0.0;%0A
-
         doub
@@ -2750,32 +2750,32 @@
 nt(population);%0A
+
         %7D%0A%0A    %7D
@@ -2764,25 +2764,24 @@
 ;%0A        %7D%0A
-%0A
     %7D%0A%0A    p

add method to optimizeparameter to see test a fixed population, and rank them by wins