Python - hangman replacing letters and updating with count - python

def update(dictionary,letter):
if letter in dictionary["word"]:
I am making hangman game and I am stuck on how I can make my last function so that when a letter is guess

if letter in dictionary['word'] and letter not in dictionary['guessWord']:
dictionary['guessWord'] = ''.join([i if i in dictionary['guessWord'] or i == letter
else '*' for i in dictionary['word']])
else:
dictionary['lives'] -= 1
This techniques rebuilds guessWord from the secret word every time. join takes a list of strings and joins them together with a separator, in this case ''. For each character in the secret word, we examine whether that character is equal to letter or is already in the guessword. If so, it is put in the guessword. If not, it is replaced with *

You could use zip to iterate over tuples (character in word, character in guess). If letter given to update matches with character in correct answer then pick it, otherwise pick the current guess and join the picked characters together. Finally check if new guess same as current and in case they match reduce lives:
def update(dictionary, letter):
old = dictionary['guessWord']
dictionary['guessWord'] = ''.join(x if x == letter else y
for x, y in zip(dictionary['word'], old))
if old == dictionary['guessWord']:
dictionary['lives'] -= 1

Related

How to make it so that every alternate character in a string appears as a hyphen

I have been asked to create a simple word guessing game that will select a random word from a list, but then displays that word with every alternate letter replaced with a hyphen.
I have figured out the selection of the random word, but after that I don't have any idea.
The prompt does mention using the modulus operator (%) within a for-loop to detect if a letter's position is odd or even, which I understand to an extent, but I cant figure out how to make it work in this case.
Code using a for loop in Python:
word = "Python" #Add your code for random words instead
ans = ""
for i in range(len(word)):
if i%2 != 0:
ans += "-"
else:
ans += word[i]
print(ans)
Output:
P-t-o-
You could get letters at even positions using a striding subscript (word[::2]) and join them with an hyphen. Make sure to have an extra space for the last letter in case the word has an even number of letters.
word = "Elephant"
hyphened = "-".join((word+' ')[::2])
print(hyphened)
E-e-h-n-
This solution is even simpler than a for loop:
original_word = "alternate" #generate a word
word = list(original_word) #split the string in chars
word[1::2]=["-"]*len(word[1::2]) #replace chars in odd positions with '-'
print(original_word)
print("".join(word))
Hope this is useful.

How to filter a list of words as likely candidates for a secret word, given that I know certain letters

So I've been really struggling with this problem. First of all let's lay-out the basic rules that this Python program must follow:
Lingo is a popular word-guessing game show on television. The number
of letters of a target word to be guessed is given, and often also the
first letter. Players then make guesses subject to these restrictions
(number of letters and possibly also first letter), and the game tells
them which letters are correct and in the correct place, marked by a
red square (X), and which letters are correct but not in the correct
place, marked by a yellow circle (O). We do not use superfluous yellow
circles, i.e. a letter is marked correct at most as often as it
appears in the target word. If not all occurrences of the same letter
can get a yellow circle this way, priority is given from left to right
(but of course red squares have priority over yellow circles).
First I needed to create a function compare that compares a guessed word with a target word. The two inputs are string of the same length that entirely consist of lowercase ASCII letters. The output is a string of the same length consisting of the symbols X, O and -, where X represent a red square, O represents a yellow circle and - represents nothing.
Examples:
compare("health", "teethe") must return "OX--O-",
compare("rhythm", "teethe") must return "---XX-",
compare("mutate", "teethe") must return "--O-OX",
compare("teethe", "mutate") must return "O--O-X",
Now I've already successfully solved this part, but the next part is where I am stuck.
A function filter_targets(targets, guess_results) must be implemented.
This function must satisfy the following:
● targets is a list (or any other iterable) of possible target words; all words in targets must be of the same length.
● guess_results is a dictionary. Its keys are guessed words (which need not be in the target list) whose associated values are their compare results with a possible target.
● It must return a list of target words in targets that actually do satisfy all
the comparisons appearing in guess_results .
Examples:
Suppose targets contains all English 6-letter words obtained using the aforementioned word list and load function. Let guess_results contain the results of the first two guesses in the example given:
guess_results = {"health": "OX--O-", "rhythm": "---XX-"}
Then based on these results, we can see which words are still possible:
filter_targets(targets, guess_results) will return the following list:
["depths", "peitho", "seethe", "teethe", "tenths"]
Now my current program looks like this, it is very dirty code in my opinion and I would really love to see some implementations that are right. This code also still doesn't do what I want it to.
My reasoning was that if I convert the word or words in guess_results (it must also be able to take a single input, as my code hereunder is taking with the mem_list function) to the "XO-" format, then store all permutations of this format in a list, I can convert the words in wordlist to the format too. I would then check for every permutation in the list if it matches the "XO-" format of any word in the wordlist I am looping through, then store all matches in a separate list. I would then return that list as an answer.
I thought I was getting very close with this logic, but I now can't seem to permutate in a way the leaves some characters in place. And my current implementation would only work for a single word input.
from itertools import permutations
def load_words(file):
result = set()
with open(file) as f:
for line in f.readlines():
word = line.strip().lower()
if word.isalpha() and word.isascii():
result.add(word)
return sorted(result)
english_words = load_words("words.txt")
dutch_words = load_words("wordlist.txt")
english_10 = [word for word in dutch_words if len(word) == 10]
def filter_targets(targets, guess_results):
mem_list = ["-" for x in range(len("kasgelden"))]
perm_list = mem_list
# Checking X
for guess in guess_results.keys():
for idx in range(len(guess)):
if guess_results[guess][idx] == 'X':
mem_list[idx] = guess[idx]
o_list = []
# Checking O
for guess in guess_results.keys():
for idx in range(len(guess)):
if guess_results[guess][idx] == 'O':
mem_var = guess[idx]
o_list.append(mem_var)
add_list = mem_list
o_min = 0
o_max = len(o_list)
y = 0
# Adding the "O"
for element in add_list:
if element == "-" and o_min < o_max:
add_list[y] = o_list[o_min]
o_min += 1
y += 1
else:
y += 1
check_list = list(permutations(add_list))
guess_results = {"kasgelden": "--O--OOX-"}
d6 = [word for word in dutch_words if len(word) == 9]
filter_targets(d6, guess_results)
In this single world example: filter_targets(dw9, {"kasgelden": "--O--OOX-"}) should return ["doorspoel", "doublures", "hoofdstel", "moordspel",
"schildjes", "slurfdier", "thuisduel", "woordspel"] . With dw9 being all the words with a length of 9.
This problem is driving me completely crazy and has consumed three days of free time already, I hope someone can nudge me in the right direction here!
English wordlist I am using: https://raw.githubusercontent.com/dwyl/english-words/master/words.txt
Dutch wordlist I am using: https://raw.githubusercontent.com/OpenTaal/opentaal-wordlist/master/wordlist.txt
The guess results tell you two types of things:
For each position, is the guessed letter required or excluded.
For each guessed letter, does it appear in the correct answer.
You can track the first thing by maintaining a regex.
You can track the second thing with two strings, one containing needed characters, one containing forbidden ones.
You can build those as follows:
regex = ["[^^]"]*wordlen
required = restricted = ''
for guess,result in guess_results:
needs = never = ''
for i,score in enumerate(result):
letter = guess[i]
if score == 'X':
regex[i]=letter
needs += letter
elif score == 'O':
regex[i] = regex[i].replace(']',letter+']')
needs += letter
else:
regex[i] = regex[i].replace(']',letter+']')
never += letter
# don't reject a '-' found on doubled letter if one was needed.
restricted += ''.join(c for c in never if c not in needs)
# track the correct number of required letters.
required = ''.join([c*max(required.count(c),needs.count(c)) for c in set(required)] +
[c for c in needs if c not in required])
Then filtering the wordlist becomes
valid = [w for w in wordlist if (
re.match(''.join(regex), w) and
all(w.count(c)>=required.count(c) for c in required) and
not any(c in w for c in restricted) )]

How to reveal a specific letter in a string for Python?

I am in high school and am currently teaching myself Python. I am programming Hangman and it is going well so far (it is not very organized yet) but I am having a problem. I created a list of words that I would use for the game and replaced them with asterisks using the range function. Here is the code for that:
words = ['utopia', 'prosecute', 'delirious', 'superficial', 'fowl', 'abhorrent', 'divergent',
'noxious', 'scarce','lavish', 'hinder', 'onerous', 'colossal', 'infringe']
picked_words = random.choice(words)
for i in range(len(picked_words)):
print(picked_words.replace(picked_words,'*'), end = '')
I am at the point where I am guessing the letters and I need to slowly reveal the position of certain letters. I have tried looking for certain functions (I even thought that the find() function would work since it prints the location of a letter in a string but it did not) and I am at a loss. Especially for words with multiples of the same letter such as "onerous" and "infringe." I will write the code that I have so far for this section:
def right_letter(correct):
if correct == True:
print("There are {} {}'s.".format(number_of_char, guess))
for x in range(len(picked_words)):
print(picked_words.replace(picked_words,guess, #find way to fill in specific letters),end = '')
I have no clue what parts of the code are necessary to get an answer but my code is really unorganized because I do not know proper techniques yet. The portion that says for x in range(len(picked_words))... is where I am having trouble. The rest of the code ran fine before I added the print statement underneath it. Basically I am asking how to change a certain character or specific characters and put them where they belong. For example, if the randomized word was "infringe" and the first guess was "i" how do I go from ******** to i***i***?
Also, in case anyone was wondering what I originally thought the solution was...
picked_words[(picked_words.find(guess))]
I thought that it would simplify and become picked_words[index]
Here's an example of converting your code to the hangman game.
Note how variable display in the code is updated to show user the correct guessed letters.
import random
def hangman():
words = ['utopia', 'prosecute', 'delirious', 'superficial', 'fowl', 'abhorrent', 'divergent',
'noxious', 'scarce','lavish', 'hinder', 'onerous', 'colossal', 'infringe']
max_guesses = 5
word = random.choice(words)
guesses = 0
display = "*" * len(word)
print(display, " Is the word")
while guesses < max_guesses:
letter = input("Please Enter Your guess letter: ")
if letter.lower() not in word:
guesses += 1
print("You got it incorrect, you have: ", max_guesses - guesses , " Additional trials")
else:
print("Right guess!")
new_display = ''
for w, l in zip(word, display):
if letter.lower() == w:
new_display += letter.lower()
else:
new_display += l
display = new_display
print(display)
if not '*' in display:
print("You won!")
return
hangman()
Basically you will need to find a partial match between your letter and the word here.
The easiest way i can think of is Pythons in Operator. It can be used like this
if picked_letter in picked words
% here you need to figure out at which position(s) the letter in your word occurs
% and then replace the * at the correct positions. A nice way to do this is
% the use of regular expressions
picked_words = re.sub('[^[^picked_letter]*$]', '*', picked_words)
%this will replace every letter in your word with the Asterisk except for the one picked
else
%do Nothing
Note that running this Code in a loop would replace every character in your string except the picked one EVERY time., therefore it is probably best to design your picked_letter as a list containing all characters that have been picked so far. This also makes it easier to check wether a letter has already been entered.

Translation from English to Pig Latin

I'm doing part of the 'PigLatin translation' program.
Here is the part I'm doing writing right now.
input_str = input("Input a word: ")
consonant_check = 0
while input_str[int(consonant_check)] != 'a' or 'e' or 'i' or 'u':
output_str = input_str[:int(consonant_check)] + input_str[0,int(consonant_check)] + 'ay'
consonant_check = int(consonant_check) + 1
else:
print(output_str)
This part is supposed to check if the word input begins with a consonant. If it does, the program could remove all consonants from the beginning of the word and append them to the end of the word. Then append "ay" to the end of the word.
By collecting information online I had some clues about how to make it happen but I think there are still something wrong with my code.
I would approach it similar to what you intended, resulting in the code below.
In short, check the first character of a string. If it's not a vowel (not in ['a','e','i','o','u']), move the character to the end of the string. Keep doing that until you hit a vowel (so 'string' becomes 'trings' then 'ringst' then 'ingstr' before breaking the loop). Once you finally hit a vowel, you leave the loop, and print the modified string + 'ay'. If the first character is a vowel, you leave the loop and print the string + 'ay'.
There's no need to set a consonant check - you're always checking the first character (0). And there's no need to have two variables - just keep modifying and replacing the original string.
word_string = input("Input a word: ")
while word_string[0] not in ['a','e','i','o','u']:
word_string = word_string[1:] + word_string[0:1]
else:
print(word_string + 'ay')
This isn't a direct answer to your question, but my solution to the pig-latin problem. When learning python, I found that looking at completed examples helped a great deal.
word = "snake"
import string
# Create a list of vowels an consonants
vowels = ['a','e','i','o','u','y']
vowels += [v.upper() for v in vowels]
consonants = [x for x in string.ascii_letters if x not in vowels]
if word[0] in consonants:
# Find the first vowel
idx = min([word.find(v) for v in vowels if word.find(v)>0])
# Split the word at this point and add 'ay'
word = word[idx:] + word[:idx] + 'ay'
print(word)
# Returns "akesnay"
I think your logic is overall a little messed up. I would suggest tackling the problem like this.
1.) Check to see if the first letter is a consonant, if not, do nothing, if so, go to step 2
2.) Find all of the consonants in the word and store them in a list
3.) If it is, remove the vowels from the word, and then append all of the consonant onto the end, followed by 'ay'.
There are infinite ways to actually implement this and I think it would be a good exercise for you to try to implement it yourself, but let me know if you need any more help.

Python: add a number of random letters (A-Z; a-z) after each letter in a given word?

I need to write a program that will add a number of random letters after each letter in the supplied word.
Here is what I have:
import random
import string
def add_letters(word,number):
for i in range(number):
letters=''.join(random.choice(string.ascii_letters))
new_word=(letters.join(word))
return new_word
Here is what the output is supposed to look like if we enter add_letters(cat,1):
cZaQtR
My program always returns 1 letter even if I give it a different number. Also, it's always the same "random" letter after each letter in the word.
Any idea what I'm doing wrong?
There are a lot of logic errors here, and some clumsy coding (but don't worry, you'll get better while practicing)
At each loop, your new_word gets erased
You are assigning to new_word a generated letter plus the original word, it's not what you want to do.
No need to use ''.join
A correct answer would be something like:
def add_letters(word,number):
new_word = ""
for c in word: # iterate through the word
letters = ""
for k in range(number): # concatenate n random letters
letters += random.choice(string.ascii_letters)
new_word += c + letters # add the current char plus the letters to the new word
return new_word
Your logic is not correct. I would suggest adding some debugging printout inside your loop and see what you get, something like the following:
for i in range(number):
letters=''.join(random.choice(string.ascii_letters))
new_word=(letters.join(word))
print i, letters, word, new_word
This should tell you where you are going wrong. As an extra hint, you might use a second loop outside the first one.
You're never maintaining your added letters on each iteration.
You do new_word=(letters.join(word)) on every iteration, which will never keep the random letters from previous iterations, and using 'something'.join('another something') will add the 'something' in between every character of the 'another something'.
What you would want to look at instead, would be something more along the lines of
def add_letters(word, number):
new_word = ''
for character in word:
new_word += character
for _ in range(number):
new_word += random.choice(string.ascii_letters)
return new_word
which will iterate over every character of the supplied word, add it to the new_word string, then randomly choose as many characters as required and add them to the new_word, and continue till the original word is finished, and returns the new word.
Your problem is happening when you enter your loop you are always only generating at most one random character at a time with this:
letters=''.join(random.choice(string.ascii_letters))
You might want to look at your problem a different way, and instead, make use of another method in random called sample
With sample, you can provide how many random characters you want every time you call it, and they will be unique. This in effect changes your loop to instead of iterating over your number, to iterate over the word and add your characters accordingly.
import random
import string
def add_letters(word,number):
new_word = ""
for i in word:
letters = ''.join(random.sample(string.ascii_letters, number))
new_word += "{}{}".format(i, letters)
return new_word
Calling:
add_letters('cat', 2)
Outputs:
cNbarHtTM
import random
import string
def add_letters(word,number):
"""
Adds "number" randomly selected ASCII letters to the end of "word"
"""
return word + "".join([random.choice(string.ascii_letters) for k in range(number)])
for i in range(10):
print(add_letters("foo", i))
The [random.choice...] thing is a list comprehension. They're a really cool, powerful thing in Python, which I'd recommend you read up on if you don't fully understand the code.

Categories