Skip to content

Instantly share code, notes, and snippets.

@KTibow
Last active Jun 20, 2020
Embed
What would you like to do?
A simple Hangman guesser with Python
# Setup word list. Download if not there
# Note: "string" means the thing we're trying to guess
from urllib.request import urlopen
from os.path import isfile
from re import sub
from string import ascii_lowercase
print("Loading...")
if isfile("words.txt"):
words = open("words.txt", "r").read().split("\n")
else:
print("Downloading, stripping, and caching words...")
words = urlopen("https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt").read().decode().split("\n")
words = list(set([word.strip().lower() for word in words]))
cache = open("words.txt", "w")
cache.write("\n".join(words))
cache.close()
# Init global vars
lenofword = int(input("How long is the word? "))
constraints = {}
asked = []
# Import operator for sorting
import operator
# Explanation:
# We have a dict called constraints
# It can say that a letter is not in the string
# Like {'a': False}
# Or that a letter is in the string a certain number of times
# Like {'e': 2}
# This makes a dict with only the ones where the letter is in the string
# And sums up the number of times
# When it reaches the length of word, it stops.
while sum({k: v for k, v in constraints.items() if not isinstance(v, bool)}.values()) < lenofword:
# Workwords is a list of words that might match the string
workwords = []
# Loop through constraints
for cons, constr in constraints.items():
# If the constraint isn't a bool:
# (That means that it isn't False)
if not isinstance(constr, bool):
# Note we only use words with it that number of times
print("Using words only with", cons, constr, "times")
else:
# Note we only use words without it
print("Using words only without "+cons)
# Iterate through possible words
print("Loading...")
for i, word in enumerate(words):
# If the word is the right length
if len(word) == lenofword:
works = True
for cons, constr in constraints.items():
if not isinstance(constr, bool):
# Make sure it has the letter the right number of times
if word.count(cons) != constr:
works = False
else:
# Make sure it doesn't have the letter
if cons in word:
works = False
# If the conditions are right, add it to the list of working words
if works:
workwords.append(word)
# Remove duplicates
workwords = list(set(workwords))
# Verbosity
print("Found", len(workwords), "working words")
if len(workwords) == 0:
# Let the user fix it
print("Hmm... Looks like we have a problem here. Try to correct it:")
print("Original:")
print(constraints)
print("Enter the fixed one here")
constraints = eval(input("As a dict: "), {}, {})
else:
workletters = []
# Loop through each letter in each word
for i in range(lenofword):
for word in workwords:
works = True
# Make sure not guessed before
for cons, constr in constraints.items():
if word[i].lower() == cons:
works = False
# If it works, add it to the list
if works:
workletters.append(word[i].lower())
# Make a list of working letters by frequency
bestletters = {}
for letter in workletters:
if letter in bestletters:
bestletters[letter] = bestletters[letter] + 1
else:
bestletters[letter] = 1
# Sort the working letters by frequency
sortedletters = list(dict(sorted(bestletters.items(), key=operator.itemgetter(1), reverse=True)))
for srt in sortedletters:
if srt in asked:
del sortedletters[sortedletters.index(srt)]
# Let the user know
print("You should guess the letter", sortedletters[0],
"(or maybe " + sortedletters[1] + ")" if len(sortedletters) > 1 else "")
asked += sortedletters[0]
# Ask whether it was right
right = input("Was it right? (\"y\" or \"n\") ")
if "n" in right:
# If it was wrong, add it to constraints
constraints[sortedletters[0]] = False
elif "y" in right:
# If it was right, add it to constraints
constraints[sortedletters[0]] = int(input("How many times was it in the string? "))
print("Well done.")
for i, word in enumerate(words):
# If the word is the right length
if len(word) == lenofword:
works = True
for cons, constr in constraints.items():
if not isinstance(constr, bool):
# Make sure it has the letter the right number of times
if word.count(cons) != constr:
works = False
else:
# Make sure it doesn't have the letter
if cons in word:
works = False
# If the conditions are right, add it to the list of working words
if works:
workwords.append(word)
# Remove duplicates
workwords = list(set(workwords))
# Make sure it was right
if len(workwords) == 1:
print("It was", workwords[0]+", right?")
else:
for word in workwords:
print("It might have been", word)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment