Created
October 13, 2023 08:06
-
-
Save jhoneycutt/88915c96585712eb660f22e12bef21a7 to your computer and use it in GitHub Desktop.
NY Times letter-boxed solver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import sys | |
import time | |
# Lexicon must be a JSON array of strings. | |
LEXICON_PATH = "lexicon.json" | |
if len(sys.argv) != 5: | |
name = sys.argv[0] | |
print(f"Usage : {name} <side 1> <side 2> <side 3> <side 4>") | |
print(f"Example: {name} ERP SBW OID UHC") | |
sys.exit(-1) | |
sides = [side.lower() for side in sys.argv[1:]] | |
all_sides_string = "".join(sides) | |
full_letter_set = set(all_sides_string) | |
# Create a map from each letter to each playable letter, i.e. the letters on | |
# the other 3 sides. | |
side_map = { | |
sides[0][0]: set(sides[1] + sides[2] + sides[3]), | |
sides[0][1]: set(sides[1] + sides[2] + sides[3]), | |
sides[0][2]: set(sides[1] + sides[2] + sides[3]), | |
sides[1][0]: set(sides[0] + sides[2] + sides[3]), | |
sides[1][1]: set(sides[0] + sides[2] + sides[3]), | |
sides[1][2]: set(sides[0] + sides[2] + sides[3]), | |
sides[2][0]: set(sides[0] + sides[1] + sides[3]), | |
sides[2][1]: set(sides[0] + sides[1] + sides[3]), | |
sides[2][2]: set(sides[0] + sides[1] + sides[3]), | |
sides[3][0]: set(sides[0] + sides[1] + sides[2]), | |
sides[3][1]: set(sides[0] + sides[1] + sides[2]), | |
sides[3][2]: set(sides[0] + sides[1] + sides[2]), | |
} | |
def can_play(word): | |
for i, letter in enumerate(word): | |
if letter not in full_letter_set: | |
return False | |
if not i: | |
continue | |
if letter not in side_map[word[i - 1]]: | |
return False | |
return True | |
start_time = time.time() | |
lexicon = None | |
with open(LEXICON_PATH) as w: | |
lexicon = json.load(w) | |
playable_words = [word for word in lexicon if can_play(word)] | |
# Create a mapping from a letter to all playable words starting with that | |
# letter. | |
playable_words_map = { letter: [] for letter in full_letter_set } | |
for word in playable_words: | |
if word[0] in full_letter_set: | |
playable_words_map[word[0]].append(word) | |
candidate_count = 0 | |
for first_word in playable_words: | |
last_letter = first_word[-1] | |
second_word_candidates = playable_words_map[last_letter] | |
for second_word in second_word_candidates: | |
if set(first_word + second_word) == full_letter_set: | |
candidate_count += 1 | |
print(f"Candidate: {first_word}, {second_word}") | |
elapsed = time.time() - start_time | |
print(f"\n{candidate_count} candidates found in {elapsed:.2f} secs.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment