Sunday Puzzle for March 13, 2022

Posted on

Manipulate Words from a Common Phrase Containing ‘in the’

This week’s challenge comes from Tyler Hinman, of San Francisco. He’s the reigning champion of the American Crossword Puzzle Tournament, which is coming up again on April 1-3. Think of two four-letter words that complete the phrase “_ in the _.” Move the first letter of the second word to the start of the first word. You’ll get two synonyms. What are they?

Link to the challenge
Take a common phrase containing ‘in the’, extract two words and manipulate them to find two synonyms

Discussion

The code to solve the puzzle was easy. Getting the list of phrases was tough! Eventually, I built up a list of over 10,000 common phrases and used it to solve the puzzle. Once again, I elected to use python.

Skills and Techniques to Solve

  • File handling
  • String manipulation

Again, the code is quite short, just 57 lines, including 16 comment lines

Screen shot showing my solution

Code Discussion

For simplicity, I will show the key code, saving 3 things for later:

  1. Building a list of English words called ‘wordLst’
  2. Defining a method ‘GetPriorWord’
  3. Defining another method ‘GetNextWord’

Here is the important, key word, skipping the three items above:

fName = 'C:\\Users\\Randy\\Documents\\Puzzles\\Data\\CommonPhrases.txt'
fHandle = open(fName, 'rt', encoding="utf8")
# Read each line in the file (about 10,000) and process lines containing ' in the '
for aLine in fHandle:
    p = aLine.find(' in the ')
    if p > 0:
        #Remove trailing linefeed
        fixed = aLine.strip()
        previous = GetPriorWord(fixed, p)
        if len(previous) == 4:
            next = GetNextWord(fixed, p)
            if len(next) == 4:
                #At this point, we know both words have length 4, 
                #now manipulate them according to the instructions:
                candidate1 = next[0] + previous
                candidate2 = next[1:]

                #if both candidates are valid words, print the result:
                if candidate1 in wordLst and candidate2 in wordLst:
                    print(fixed, ' → ', candidate1, candidate2)

First, we open the file with this code:

fHandle = open(fName, 'rt', encoding="utf8").

  • ‘rt’ means ‘read’ ‘text’
  • encoding=”utf8″ means expect and handle non-standard letters, like à la carte

Next, we loop through the lines in the file, we look for a line containing ‘in the’

p = aLine.find(' in the ')

variable ‘p’ is the position where we find that substring; if not found, p will be -1. Only about 20 phrases qualify. Next, we get the words immediately before and immediately after the position where we found ‘in the’:

        previous = GetPriorWord(fixed, p)
        if len(previous) == 4:
            next = GetNextWord(fixed, p)
            if len(next) == 4:

As discussed above, I will explain ‘GetPriorWord’ and ‘GetNextWord’ below. For now, the code above creates two variables holding the words we want, named ‘previous’ and ‘next’. If both have length 4, we proceed:

                #At this point, we know both words have length 4, 
                #now manipulate them according to the instructions:
                candidate1 = next[0] + previous
                candidate2 = next[1:]

                #if both candidates are valid words, print the result:
                if candidate1 in wordLst and candidate2 in wordLst:
                    print(fixed, ' → ', candidate1, candidate2)

‘candidate1’ is built by concatenating the first letter of next with previous. ‘candidate2’ is every letter following the first. If both are in my list of words ‘wordLst’, then we have a solution. Note that only one phrase matches this, so I didn’t write code to determine whether they are synonyms.

The Three Parts I Skipped Over

Here’s how I built wordLst:

# First load a list of English words
fName = "C:\\Users\\Randy\\Documents\\Puzzles\\Data\\2of12inf.txt"
fHandle = open(fName, 'rt')
wordLst = []
for aWord in fHandle:
    wordLst.append(aWord.strip())

Here are the definitions of my two methods ‘GetPriorWord’ and ‘GetNextWord’:

#When given a position p in a string 'aLine', finds the word preceeding it
def GetPriorWord(aLine, p):
    i = p - 1
    while i >= 0 and aLine[i] != ' ':
        i -= 1
    
    result = ''
    if i < p:
        result = aLine[i + 1:p - i - 1]
    return result

#When given a position p in string 'aLine, finds the word succeeding it
def GetNextWord(aLine, p):
    i = p + 8
    while i < len(aLine) and aLine[i].isalpha():
        i += 1
    
    result = ''
    if i > p + 8:
        result = aLine[p + 8:i]
    return result

Download My Code

You can download my solution, plus the phrase file, from my Dropbox account. You will need to create a free account with Dropbox to do so.

Leave a comment