code: def genetic_search(problem, fitness_fn, ngen=1000, pmut=0.1, n=20):
      
      s = problem.initial_state
      states = [problem.result(s, a) for a in problem.actions(s)]
      random.shuffle(states)
      return genetic_algorithm(states[:n], problem.value, ngen, pmut)
docs: Call genetic_algorithm on the appropriate parts of a problem.
      This requires the problem to have states that can mate and mutate,
      plus a value method that scores states.