def word_ladder(self, origin, destination): """Constructs a word ladder between the given words using the fetched vocabulary. A word ladder is a sequence of words, from origin to destination, where each intermediary word changes exactly one letter in the previous word. All intermediate words in the ladder must be real words. Constructing a word ladder loosely follows the methodology of A* path finding. A tree data structure is used to store a collection of words and the paths between them. The tree is filled first with the destination word and is then traversed breadth first adding each word's legal one character substitutions. Traversal ends when any path has reached the origin and that path's ancestry is returned. The tree is traversed breadth first so that the shortest path is found in all cases. A tree begins at the destination and works backwards to the origin so that the chosen path's ancestry is in the correct order. :param origin: The starting word to construct a word ladder from. :param destination: The word that the ladder traverses to. :return: A sequence of words that constitutes a word ladder. """ paths = Tree() # tree stores all possible paths paths.add_root(destination) # start at destination so that ancestry path is in the correct order visited = set() # no need for ANY branch to revisit a word that another branch has been to for node in paths.breadth_first(): if node.data == origin: # if node is origin, the word ladder is complete path = [] for ancestor in node.ancestor_data(): # construct a path from this nodes ancestors. path.append(ancestor) return path else: for word in self.similar(node.data): # add each similar word to this nodes path... if word not in visited: # ...only if it hasn't been visited by ANY other tree path node.add(word) visited.add(word) return [] # no path was found
def tree_test(self): tree = Tree() root = tree.add_root(1) root_child = root.add(2) other_root_child = root.add(3) root_child_child = root_child.add(4) # test root has correct parent, data, and children self.assertEqual(root.parent, None) self.assertEqual(root.data, 1) self.assertEqual(len(root.children), 2) self.assertIn(root_child, root.children) self.assertIn(other_root_child, root.children) # test child of root has correct parent, data, and children self.assertEqual(root_child.parent, root) self.assertEqual(root_child.data, 2) self.assertEqual(len(root_child.children), 1) self.assertIn(root_child_child, root_child.children) # test other child of root has correct parent, data, and children self.assertEqual(other_root_child.parent, root) self.assertEqual(other_root_child.data, 3) self.assertEqual(len(other_root_child.children), 0)