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
Beispiel #4
0
    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
Beispiel #5
0
 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)
Beispiel #6
0
    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)]
Beispiel #7
0
 def assert_solved(problem: Problem, solved: bool):
     assert problem.solved() == solved