nodes: 0, module; 1, function_definition; 2, function_name:crack; 3, parameters; 4, block; 5, identifier:ciphertext; 6, list_splat_pattern; 7, default_parameter; 8, default_parameter; 9, expression_statement; 10, if_statement; 11, comment:# Find a local maximum by swapping two letters and scoring the decryption; 12, function_definition; 13, comment:# Outer climb rereuns hill climb ntrials number of times each time at a different start location; 14, function_definition; 15, expression_statement; 16, return_statement; 17, identifier:fitness_functions; 18, identifier:ntrials; 19, integer:30; 20, identifier:nswaps; 21, integer:3000; 22, comment:"""Break ``ciphertext`` using hill climbing.
  
      Note:
          Currently ntrails and nswaps default to magic numbers.
          Generally the trend is, the longer the text, the lower the number of trials
          you need to run, because the hill climbing will lead to the best answer faster.
          Because randomness is involved, there is the possibility of the correct decryption
          not being found. In this circumstance you just need to run the code again.
  
      Example:
          >>> decryptions = crack("XUOOB", fitness.english.quadgrams)
          >>> print(decryptions[0])
          HELLO
  
      Args:
          ciphertext (str): The text to decrypt
          *fitness_functions (variable length argument list): Functions to score decryption with
  
      Keyword Args:
          ntrials (int): The number of times to run the hill climbing algorithm
          nswaps (int): The number of rounds to find a local maximum
  
      Returns:
          Sorted list of decryptions
  
      Raises:
          ValueError: If nswaps or ntrails are not positive integers
          ValueError: If no fitness_functions are given
      """; 23, boolean_operator; 24, block; 25, function_name:next_node_inner_climb; 26, parameters; 27, comment:# Swap 2 characters in the key; 28, block; 29, function_name:next_node_outer_climb; 30, parameters; 31, block; 32, assignment; 33, call; 34, comparison_operator:ntrials <= 0; 35, comparison_operator:nswaps <= 0; 36, raise_statement; 37, identifier:node; 38, expression_statement; 39, expression_statement; 40, expression_statement; 41, expression_statement; 42, return_statement; 43, identifier:node; 44, expression_statement; 45, expression_statement; 46, return_statement; 47, comment:# The last item in this list is the item with the highest score; 48, pattern_list; 49, call; 50, identifier:sorted; 51, argument_list; 52, identifier:ntrials; 53, integer:0; 54, identifier:nswaps; 55, integer:0; 56, call; 57, assignment; 58, assignment; 59, assignment; 60, assignment; 61, expression_list; 62, call; 63, assignment; 64, expression_list; 65, identifier:_; 66, identifier:_; 67, identifier:decryptions; 68, identifier:hill_climb; 69, argument_list; 70, identifier:decryptions; 71, keyword_argument; 72, identifier:ValueError; 73, argument_list; 74, pattern_list; 75, call; 76, pattern_list; 77, expression_list; 78, identifier:plaintext; 79, call; 80, identifier:node_score; 81, call; 82, identifier:node; 83, identifier:node_score; 84, call; 85, attribute; 86, argument_list; 87, pattern_list; 88, call; 89, identifier:key; 90, identifier:best_score; 91, subscript; 92, identifier:ntrials; 93, call; 94, identifier:next_node_outer_climb; 95, identifier:reverse; 96, True; 97, string:"ntrials and nswaps must be positive integers"; 98, identifier:a; 99, identifier:b; 100, attribute; 101, argument_list; 102, subscript; 103, subscript; 104, subscript; 105, subscript; 106, identifier:decrypt; 107, argument_list; 108, identifier:score; 109, argument_list; 110, identifier:Decryption; 111, argument_list; 112, identifier:random; 113, identifier:shuffle; 114, identifier:node; 115, identifier:key; 116, identifier:best_score; 117, identifier:outputs; 118, identifier:hill_climb; 119, argument_list; 120, identifier:outputs; 121, unary_operator; 122, identifier:list; 123, argument_list; 124, identifier:random; 125, identifier:sample; 126, call; 127, integer:2; 128, identifier:node; 129, identifier:a; 130, identifier:node; 131, identifier:b; 132, identifier:node; 133, identifier:b; 134, identifier:node; 135, identifier:a; 136, identifier:node; 137, identifier:ciphertext; 138, identifier:plaintext; 139, list_splat; 140, identifier:plaintext; 141, call; 142, identifier:node_score; 143, identifier:nswaps; 144, subscript; 145, identifier:next_node_inner_climb; 146, integer:1; 147, attribute; 148, identifier:range; 149, argument_list; 150, identifier:fitness_functions; 151, attribute; 152, argument_list; 153, identifier:node; 154, slice; 155, identifier:string; 156, identifier:ascii_uppercase; 157, call; 158, string; 159, identifier:join; 160, identifier:node; 161, identifier:len; 162, argument_list; 163, identifier:node
code: def crack(ciphertext, *fitness_functions, ntrials=30, nswaps=3000):
      """Break ``ciphertext`` using hill climbing.
  
      Note:
          Currently ntrails and nswaps default to magic numbers.
          Generally the trend is, the longer the text, the lower the number of trials
          you need to run, because the hill climbing will lead to the best answer faster.
          Because randomness is involved, there is the possibility of the correct decryption
          not being found. In this circumstance you just need to run the code again.
  
      Example:
          >>> decryptions = crack("XUOOB", fitness.english.quadgrams)
          >>> print(decryptions[0])
          HELLO
  
      Args:
          ciphertext (str): The text to decrypt
          *fitness_functions (variable length argument list): Functions to score decryption with
  
      Keyword Args:
          ntrials (int): The number of times to run the hill climbing algorithm
          nswaps (int): The number of rounds to find a local maximum
  
      Returns:
          Sorted list of decryptions
  
      Raises:
          ValueError: If nswaps or ntrails are not positive integers
          ValueError: If no fitness_functions are given
      """
      if ntrials <= 0 or nswaps <= 0:
          raise ValueError("ntrials and nswaps must be positive integers")
  
      # Find a local maximum by swapping two letters and scoring the decryption
      def next_node_inner_climb(node):
          # Swap 2 characters in the key
          a, b = random.sample(range(len(node)), 2)
          node[a], node[b] = node[b], node[a]
          plaintext = decrypt(node, ciphertext)
          node_score = score(plaintext, *fitness_functions)
          return node, node_score, Decryption(plaintext, ''.join(node), node_score)
  
      # Outer climb rereuns hill climb ntrials number of times each time at a different start location
      def next_node_outer_climb(node):
          random.shuffle(node)
          key, best_score, outputs = hill_climb(nswaps, node[:], next_node_inner_climb)
          return key, best_score, outputs[-1]  # The last item in this list is the item with the highest score
  
      _, _, decryptions = hill_climb(ntrials, list(string.ascii_uppercase), next_node_outer_climb)
      return sorted(decryptions, reverse=True)