def solve_problem(self, problem: Problem): solver = StrategyTypes.GENETIC secret_type = problem.secret_type() secret_size = problem.secret_size() if secret_size == 1 or secret_size == 3: solver = StrategyTypes.SWASZEK elif secret_type == SecretTypes.NUMERIC: if secret_size == 2: solver = StrategyTypes.KNUTH elif secret_size > 3: solver = StrategyTypes.GENETIC elif secret_size == SecretTypes.LSTRING: if secret_size == 2: solver = StrategyTypes.KNUTH elif secret_size < 5: solver = StrategyTypes.SWASZEK else: solver = StrategyTypes.GENETIC elif secret_type == SecretTypes.STRING: if secret_size < 5: solver = StrategyTypes.SWASZEK else: solver = StrategyTypes.GENETIC return self.__strategies[solver].solve_problem(problem)
def convert(secret: str, strategy, problem: Problem) -> Dict: """ Convert the resultant test information into a simplified representation :param secret: secret to uncover :param strategy: strategy used to solve the problem :param problem: resultant problem :return: dict of the captured information """ return { "secret": secret, "algorithm": strategy, "size": problem.secret_size(), "rounds": problem.turns_to_solve(), "solved": problem.solved(), "type": problem.secret_type(), "time": problem.time_to_solve(), }
def prune_guesses(possibilities, current_guess, red, white): new_possibilities = [] for possibility in possibilities: possib = ''.join(possibility) if (possib != current_guess) and (Problem.compare_sequences(possib, current_guess) == (white, red)): new_possibilities.append(possibility) return new_possibilities
def _genetic_evolution(self, max_population, max_generations, problem: Problem, guesses): """ Performs the genetic evolution of a population (randomly generated), which is a process inspired by natural selection, by the usage bio-inspired operators. In this implementation, these operators consist of Crossover (both one-point and two-point variations with 0.5 probability each), Mutation and Permutation (probability of 0.03) and Inversion(probability of 0.02). An eligibility list of potential guesses is populated with the fitness score of each guess. In case a generated child is already present in the population, we randomly generate a guess in order to diversify our pool of guesses. :param max_population: The maximum size of initial population and eligibility list. :param max_generations: The maximum number of times the population suffers the genetic evolution. :param problem: Problem used generate the population from. :param guesses: List of previous guesses. :return: List of eligible (fitness_score = 0) guesses. """ elements = problem.possible_elements() population = [ self._random_guess(elements, problem) for _ in range(max_population) ] eligible = [] h = 1 while len(eligible) <= max_population and h <= max_generations: # Genetic Evolution offspring = [] for i in range(len(population) - 1): children = self._crossover(population[i], population[i + 1]) for child in children: if rnd.random() <= Config.MUTATION_PROB: child = self._mutation(child, elements) if rnd.random() <= Config.PERMUTATION_PROB: child = self._permutation(child) if rnd.random() <= Config.INVERSION_PROB: child = self._inversion(child) if child in population: child = self._random_guess(elements, problem) offspring.append(child) # Eligibility Test for child in offspring: if self._fitness_score( child, guesses, problem) == 0 and "".join(child) not in eligible: eligible.append("".join(child)) h += 1 return eligible
def _prune_guesses(guesses, last_guess, answer): """ Provides guesses after pruning all the sequences that would not provide the same response. :param guesses: guesses to be pruned :param last_guess: last sequence proposed as a solution :param answer: response to last_guess :return: pruned guesses """ return (guess for guess in guesses if Problem.compare_sequences(guess, last_guess) == answer)
def count_score(combination, solutions): """ Provides the score of a combination. The score of a combination is the maximum size of the solution space, in the worst case, if the said combination was the secret sequence. :param combination: combination being tested :param solutions: solution space """ score_count = defaultdict(int) for solution in solutions: score = sum(Problem.compare_sequences( combination, solution)) # sum the two elements of the array score_count[score] += 1 return combination, score_count[max(score_count, key=score_count.get)]
def assert_solved(problem: Problem, solved: bool): assert problem.solved() == solved