import multiprocessing as mp
import threading
import queue
import numpy as np
import nn

# taken from:
# https://machinelearningmastery.com/simple-genetic-algorithm-from-scratch-in-python/

import new_main

# genetic algorithm search for continuous function optimization
from numpy.random import randint
from numpy.random import rand


# objective function
def objective(x):
    return x[0] ** 2.0 + x[1] ** 2.0


# decode bitstring to numbers
def decode(bounds, n_bits, bitstring):
    decoded = list()
    largest = 2 ** n_bits
    for i in range(len(bounds)):
        # extract the substring
        start, end = i * n_bits, (i * n_bits) + n_bits
        substring = bitstring[start:end]
        # convert bitstring to a string of chars
        chars = ''.join([str(s) for s in substring])
        # convert string to integer
        integer = int(chars, 2)
        # scale integer to desired range
        value = bounds[i][0] + (integer / largest) * (bounds[i][1] - bounds[i][0])
        # store
        decoded.append(value)
    return decoded


# tournament selection
def selection(pop, scores, k=3):
    # first random selection
    selection_ix = randint(len(pop))
    for ix in randint(0, len(pop), k - 1):
        # check if better (e.g. perform a tournament)
        if scores[ix] < scores[selection_ix]:
            selection_ix = ix
    return pop[selection_ix]


# crossover two parents to create two children
def crossover(p1, p2, r_cross):
    # children are copies of parents by default
    c1, c2 = p1.copy(), p2.copy()
    # check for recombination
    if rand() < r_cross:
        # select crossover point that is not on the end of the string
        pt = randint(1, len(p1) - 2)
        # perform crossover
        c1 = p1[:pt] + p2[pt:]
        c2 = p2[:pt] + p1[pt:]
    return [c1, c2]


# mutation operator
def mutation(bitstring, r_mut):
    for i in range(len(bitstring)):
        # check for a mutation
        if rand() < r_mut:
            # flip the bit
            bitstring[i] = 1 - bitstring[i]

# genetic algorithm
def genetic_algorithm(objective, bounds, n_bits, n_iter, n_pop, r_cross, r_mut):
    # initial population of random bitstring
    pop = [randint(0, 2, n_bits * len(bounds)).tolist() for _ in range(n_pop)]
    # keep track of best solution
    best = 0
    best_eval = queue.Queue()
    objective(best_eval, decode(bounds, n_bits, pop[0]))
    best_eval = best_eval.get()
    # enumerate generations
    for gen in range(n_iter):
        # decode population
        decoded = [decode(bounds, n_bits, p) for p in pop]
        # evaluate all candidates in the population
        # ******
        outputQueue = queue.Queue()
        thread = threading.Thread(target=simulate_game, args=(outputQueue, decoded))
        thread.start()
        scores = outputQueue.get()
        # ******
        # check for new best solution
        for i in range(n_pop):
            if scores[i] < best_eval:
                best, best_eval = pop[i], scores[i]
                # print(">%d, new best f(%s) = %f" % (gen, decoded[i], scores[i]))
        # select parents
        selected = [selection(pop, scores) for _ in range(n_pop)]
        # create the next generation
        children = list()
        for i in range(0, n_pop, 2):
            # get selected parents in pairs
            p1, p2 = selected[i], selected[i + 1]
            # crossover and mutation
            for c in crossover(p1, p2, r_cross):
                # mutation
                mutation(c, r_mut)
                # store for next generation
                children.append(c)
            # replace population
        pop = children
        # We want a longer game time to train to the expanding path
        # for every iteration
        new_main.ITERATION_TIME += 0.5
    return [best, best_eval]

def simulate_game(outputQueue, decoded):
    print("starting game")
    scores = []
    population = []
    for d in decoded:
        population.append(new_main.Phenotype(d))
    game = new_main.Game(population)
    scores = game.get_scores()
    outputQueue.put(scores)
    print(scores)
    print("finished game")

# objective function
def objective(output, weights):
    output.put(sum(weights))


# define range for input
bounds = [[-1.0, 1.0]]*nn.num_weights
# define the total iterations
n_iter = 100
# bits per variable
n_bits = 16
# define the population size
n_pop = 20
# crossover rate
r_cross = 0.9
# mutation rate
r_mut = 0.5 / (float(n_bits) * len(bounds))
# perform the genetic algorithm search
best, score = genetic_algorithm(objective, bounds, n_bits, n_iter, n_pop, r_cross, r_mut)
print('Done!')
decoded = decode(bounds, n_bits, best)
print('f(%s) = %f' % (decoded, score))
import multiprocessing as mp
import threading
import queue
import numpy as np
import nn

# taken from:
# https://machinelearningmastery.com/simple-genetic-algorithm-from-scratch-in-python/

import new_main

# genetic algorithm search for continuous function optimization
from numpy.random import randint
from numpy.random import rand


# objective function
def objective(x):
    return x[0] ** 2.0 + x[1] ** 2.0


# decode bitstring to numbers
def decode(bounds, n_bits, bitstring):
    decoded = list()
    largest = 2 ** n_bits
    for i in range(len(bounds)):
        # extract the substring
        start, end = i * n_bits, (i * n_bits) + n_bits
        substring = bitstring[start:end]
        # convert bitstring to a string of chars
        chars = ''.join([str(s) for s in substring])
        # convert string to integer
        integer = int(chars, 2)
        # scale integer to desired range
        value = bounds[i][0] + (integer / largest) * (bounds[i][1] - bounds[i][0])
        # store
        decoded.append(value)
    return decoded


# tournament selection
def selection(pop, scores, k=3):
    # first random selection
    selection_ix = randint(len(pop))
    for ix in randint(0, len(pop), k - 1):
        # check if better (e.g. perform a tournament)
        if scores[ix] < scores[selection_ix]:
            selection_ix = ix
    return pop[selection_ix]


# crossover two parents to create two children
def crossover(p1, p2, r_cross):
    # children are copies of parents by default
    c1, c2 = p1.copy(), p2.copy()
    # check for recombination
    if rand() < r_cross:
        # select crossover point that is not on the end of the string
        pt = randint(1, len(p1) - 2)
        # perform crossover
        c1 = p1[:pt] + p2[pt:]
        c2 = p2[:pt] + p1[pt:]
    return [c1, c2]


# mutation operator
def mutation(bitstring, r_mut):
    for i in range(len(bitstring)):
        # check for a mutation
        if rand() < r_mut:
            # flip the bit
            bitstring[i] = 1 - bitstring[i]

# genetic algorithm
def genetic_algorithm(objective, bounds, n_bits, n_iter, n_pop, r_cross, r_mut):
    # initial population of random bitstring
    pop = [randint(0, 2, n_bits * len(bounds)).tolist() for _ in range(n_pop)]
    # keep track of best solution
    best = 0
    best_eval = queue.Queue()
    objective(best_eval, decode(bounds, n_bits, pop[0]))
    best_eval = best_eval.get()
    # enumerate generations
    for gen in range(n_iter):
        # decode population
        decoded = [decode(bounds, n_bits, p) for p in pop]
        # evaluate all candidates in the population
        # ******
        outputQueue = queue.Queue()
        thread = threading.Thread(target=simulate_game, args=(outputQueue, decoded))
        thread.start()
        scores = outputQueue.get()
        # ******
        # check for new best solution
        for i in range(n_pop):
            if scores[i] < best_eval:
                best, best_eval = pop[i], scores[i]
                # print(">%d, new best f(%s) = %f" % (gen, decoded[i], scores[i]))
        # select parents
        selected = [selection(pop, scores) for _ in range(n_pop)]
        # create the next generation
        children = list()
        for i in range(0, n_pop, 2):
            # get selected parents in pairs
            p1, p2 = selected[i], selected[i + 1]
            # crossover and mutation
            for c in crossover(p1, p2, r_cross):
                # mutation
                mutation(c, r_mut)
                # store for next generation
                children.append(c)
            # replace population
        pop = children
        # We want a longer game time to train to the expanding path
        # for every iteration
        new_main.ITERATION_TIME += 0.5
    return [best, best_eval]

def simulate_game(outputQueue, decoded):
    print("starting game")
    scores = []
    population = []
    for d in decoded:
        population.append(new_main.Phenotype(d))
    game = new_main.Game(population)
    scores = game.get_scores()
    outputQueue.put(scores)
    print(scores)
    print("finished game")

# objective function
def objective(output, weights):
    output.put(sum(weights))


# define range for input
bounds = [[-1.0, 1.0]]*nn.num_weights
# define the total iterations
n_iter = 100
# bits per variable
n_bits = 16
# define the population size
n_pop = 20
# crossover rate
r_cross = 0.9
# mutation rate
r_mut = 0.5 / (float(n_bits) * len(bounds))
# perform the genetic algorithm search
best, score = genetic_algorithm(objective, bounds, n_bits, n_iter, n_pop, r_cross, r_mut)
print('Done!')
decoded = decode(bounds, n_bits, best)
print('f(%s) = %f' % (decoded, score))
# taken from: # https://machinelearningmastery.com/simple-genetic-algorithm-from-scratch-in-python/ # genetic algorithm search for continuous function optimization # objective function # decode bitstring to numbers # extract the substring # convert bitstring to a string of chars # convert string to integer # scale integer to desired range # store # tournament selection # first random selection # check if better (e.g. perform a tournament) # crossover two parents to create two children # children are copies of parents by default # check for recombination # select crossover point that is not on the end of the string # perform crossover # mutation operator # check for a mutation # flip the bit # genetic algorithm # initial population of random bitstring # keep track of best solution # enumerate generations # decode population # evaluate all candidates in the population # ****** # ****** # check for new best solution # print(">%d, new best f(%s) = %f" % (gen, decoded[i], scores[i])) # select parents # create the next generation # get selected parents in pairs # crossover and mutation # mutation # store for next generation # replace population # We want a longer game time to train to the expanding path # for every iteration # objective function # define range for input # define the total iterations # bits per variable # define the population size # crossover rate # mutation rate # perform the genetic algorithm search