Advertisement
Guest User

Untitled

a guest
Feb 9th, 2020
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.34 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. from collections import deque
  3.  
  4. def masks(w):
  5.     '''Return a generator that iterates through all of the masked verions of the word where
  6.    each letter is replaces with a *. E.g. 'few' -> ['*ew', 'f*w', 'fe*']
  7.  
  8.    '''
  9.     for i in range(len(w)):
  10.         w2 = w[:i] + '*' + w[i+1:]
  11.         yield w2
  12.  
  13. def valid(w):
  14.     '''Return whether or not the word seems valid (no punctuation, first letter isn't caps)'''
  15.     return all([ 'a' <= c <= 'z' for c in w.strip()])
  16.  
  17. def preproccess(wordfile):
  18.     '''Given a filename that contains one word per line, return a dictionary which contains each 'mask' as a key
  19.    and every possible word that mask represents as a value. E.g. 'he*d' -> ['head', 'held', 'herd']. TODO:
  20.    prune this to remove single-entry keys which aren't helpufl.
  21.    '''
  22.     words = {}
  23.     with open(wordfile, 'r') as infile:
  24.         raw = [w.strip() for w in infile.readlines() if valid(w)]
  25.         for w in raw:
  26.             for w2 in masks(w):
  27.                 if w2 not in words:
  28.                     words[w2] = []
  29.                 words[w2].append(w)
  30.     return words
  31.    
  32. def search(start, goal, wordfile):
  33.     '''Find a shortest path from goal to start using the given wordfile. Each step in the path involves swapping
  34.    exactly one letter and creating another word from the list
  35.    '''
  36.     words = preproccess(wordfile)
  37.     print('loadded wrods, searching...')
  38.     q = deque([goal])  # BFS queue, start at the start and work backwards.
  39.     bp = {}  # "back-pointers" to keep track of the parent node to reconstruct the path at the end.
  40.     bp[goal] = None
  41.     num = 0
  42.     done = False
  43.     while q and not done:
  44.         w = q.popleft()
  45.         num += 1
  46.         for e in masks(w):
  47.             if e not in words:
  48.                 print(f"ERROR bad key {e}")
  49.                 continue
  50.             for w2 in words[e]:
  51.                 if w2 in bp or w2 == w:
  52.                     continue
  53.                 bp[w2] = w
  54.                 if w2 == start:
  55.                     done = True
  56.                     break
  57.                 q.append(w2)
  58.             if done:
  59.                 break
  60.  
  61.     if start in bp:
  62.         print(f"found solution in {num} expansions of BFS:\n")
  63.         curr = start
  64.         while curr != goal:
  65.             print(curr,'  ')
  66.             curr = bp[curr]
  67.         print(goal, '  ')
  68.     else:
  69.         print(f"no solution in {num}")
  70.  
  71. def combine(infiles, outfile):
  72.     '''Utility function to open multiple word lists (infiles array) and store the intersection of valid words in the outfile'''
  73.     s = None
  74.     for f in infiles:
  75.         with open(f, 'r') as infile:
  76.             words = set([w.strip() for w in infile.readlines() if valid(w)])
  77.             if s:
  78.                 s = s.intersection(words)
  79.             else:
  80.                 s = words
  81.  
  82.     with open(outfile, 'w') as out:
  83.         for w in s:
  84.             out.write(w + "\n")
  85.  
  86. if __name__ == "__main__":
  87.     import argparse
  88.     parser = argparse.ArgumentParser(description="Solve Lewis Carroll's Doublet Puzzles")
  89.     parser.add_argument('wordfile', metavar = 'filename.txt', help='filename holding all words seperated by a newline')
  90.     parser.add_argument('start', metavar = 'FROM')
  91.     parser.add_argument('goal', metavar = 'TO')
  92.     args = parser.parse_args()
  93.  
  94.     search(args.start, args.goal, args.wordfile)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement