def run(self, fitness_threshold, generation_limit):
        result = []
        while self.generationCount < generation_limit:
            self.generationCount += 1
            self.selection()
            self.crossover(generation_limit // 1000)
            fittest = self.population.get_fittest()
            if fittest.fitness >= fitness_threshold:
                if result and tuple(fittest.key) == tuple(result[-1][2]):
                    continue
                r = (fittest.decrypt(), fittest.fitness, fittest.key)
                result.append(r)
                fprint("Solution Found:\n{}\nFitness:{} Key:{}".format(
                    r[0], r[1], r[2]))
                if input(
                        "\nIs this solution bingo? Enter b to break the program. Otherwise press Enter to continue searching..."
                ) == 'b':
                    return
                fitness_threshold = fittest.fitness

            fprint("Generation: {} Fittest: {}".format(
                self.generationCount, self.population.fittest))

        if not result:
            fprint("Can't find solution")
        else:
            fprint("\n\nSolutions Found:{}")
            for i, r in enumerate(result):
                fprint("{}.\n{}\nFitness:{} Key:{}".format(
                    i, r[0], r[1], r[2]))
    def crossover(self, revive_threshold):
        P = self.key_length
        c1 = [0] * P
        c2 = [0] * P
        p1 = self.fittest.key
        p2 = self.secondFittest.key
        tmp_set = set()

        r = randint(0, P - 1)
        for i in range(r):
            c1[i] = p1[i]
            tmp_set.add(p1[i])
        i = 0
        k = 0
        while i < P - r and k < P:
            if p2[k] not in tmp_set:
                c1[i + r] = p2[k]
                tmp_set.add(p2[k])
                i += 1
            else:
                k += 1

        tmp_set.clear()

        r = randint(0, P - 1)
        for i in range(P - 1, r - 1, -1):
            c2[i] = p1[i]
            tmp_set.add(p1[i])
        i = 1
        k = P - 1
        while i <= r and k >= 0:
            if p2[k] not in tmp_set:
                c2[r - i] = p2[k]
                tmp_set.add(p2[k])
                i += 1
            else:
                k -= 1

        fprint("r:{}|p1:{}|p2:{}|c1:{}|c2:{}".format(r, p1, p2, c1, c2))

        r = randint(0, 2)

        for i in range(r):
            # mutation
            swap = sample(list(range(P)), 2)
            c1[swap[0]], c1[swap[1]] = c1[swap[1]], c1[swap[0]]
            swap = sample(list(range(P)), 2)
            c2[swap[0]], c2[swap[1]] = c2[swap[1]], c2[swap[0]]

        c_i1 = Individual(self.crypt, self.key_length, key=c1)
        c_i1.calcFitness()
        c_i2 = Individual(self.crypt, self.key_length, key=c2)
        c_i2.calcFitness()
        # get_fittest_offspring(self)
        c_i_max = max(c_i1, c_i2, key=(lambda x: x.fitness))

        #add_fittest_offspring(self)
        self.population.replace(self.population.get_least_fittest_index(),
                                c_i_max, revive_threshold)
 def replace(self, replace_index, replace, revive_threshold):
     rk = tuple(replace.key)
     if rk in self.individuals_dict:
         self.individuals_dict[rk] += 1
         self.check_revive(rk, revive_threshold)
         return
     try:
         del self.individuals_dict[tuple(
             self.individuals[replace_index].key)]
     except:
         fprint("KeyError:{}".format(
             tuple(self.individuals[replace_index].key)))
     del self.individuals[replace_index]
     self.individuals.add(replace)
     self.individuals_dict[rk] += 1
 def __init__(self, crypt, key_length):
     self.crypt = crypt
     self.generationCount = 0
     self.key_length = key_length
     fprint("Initializing...Please wait")
     self.population = Population(1000, crypt, key_length)
     for i in range(self.population.pop_size):
         fprint(self.population.individuals[i].key)
     self.fittest = self.population.get_fittest_rand()
     self.secondFittest = self.population.get_second_fittest_rand()
     fprint("Generation: {} Fittest: {}".format(self.generationCount,
                                                self.population.fittest))
 def check_revive(self, key, revive_threshold):
     if self.individuals_dict[key] > revive_threshold:
         fprint("revive...")
         self.init()