Given you're a rookie, I'd thought throw my hat in and do it without regex and attempt to explain. Maybe only read this once you've had your go. Your question title can be answered with:
def replace_nth_char(string, n, replacement):
n -= 1
l_string = list(string)
l_string[n] = replacement
return ''.join(l_string)
It converts the string to a list of letters which you can replace by index n
and then joins it back up.
I've also given the rest a go to show you more python options.
As you're managing the state, you might want to think about using a class. It helps you wrap all the functions and attributes together into one object with a purpose - playing your Vocabulary Game. I recommend looking into them. Here is one for the game:
import random
class VocabularyGame():
def __init__(self, chosen_words, hidden_words):
self.chosen_words = chosen_words
self.hidden_words = hidden_words
self.hidden_letters = list(set(''.join(words)))
self.masked_sentence = self.mask_words(chosen_words, hidden_words)
print(f"Game start: {self.masked_sentence}")
def mask_words(self, sentence, masks):
return ' '.join(['_'*len(w) if w in masks else w for w in sentence.split(' ')])
def try_letter(self, letter=None):
if letter is None:
letter = random.choice(self.hidden_letters)
self.masked_sentence = ''.join(
[c if c== letter else m for m, c in zip(self.masked_sentence, self.chosen_words)]
)
self.hidden_letters = [l for l in self.hidden_letters if l != letter]
print(f"Trying letter {letter}...\nRemaining letters: {self.masked_sentence}")
The __init__
section runs whenever we make new game instances and takes three arguments, (self, chosen_words, hidden_words)
. The use of self
references the current class instance (or game) and we can use it to set and retrieve attributes to the class, in this case, to remember our words and sentences.
def __init__(self, chosen_words, hidden_words):
self.chosen_words = chosen_words
self.hidden_words = hidden_words
self.hidden_letters = list(set(''.join(hidden_words)))
self.masked_sentence = self.mask_words(chosen_words, hidden_words)
print(f"Game start: {self.masked_sentence}")
list(set(''.join(words)))
gets all unique letters in the hidden words by joining them into one string and using sets to convert them into the unique letters. I convert this back into a list for ease of use later.
We then apply a function to mask the words with '_'.
def mask_words(self, sentence, masks):
return ' '.join(['_'*len(w) if w in masks else w for w in sentence.split(' ')])
This goes through each word in the sentence and replaces it with '_' for the length of the word, if it exists in hidden words. Then it joins it back up. Now we have our start state.
The last thing to do is to try a letter. We do this by defining a method (function on a class) def try_letter(self, letter=None):
. If no letter is provided, we pick a random one from the unique missing letters we defined earlier.
The we go through each letter in the original sentence and masked sentence together using zip
and when the original letter is our chosen letter, we replace the one in our masked sentence.
self.masked_sentence = ''.join(
[c if c==letter else m for m, c in zip(self.masked_sentence, self.chosen_words)]
)
Then remove the letter form our hidden letters list:
self.hidden_letters = [l for l in self.hidden_letters if l != letter]
Finally, we print result out using f-strings.
Now, we can play the game!
chosen_word = "TO CRANK (STH) UP"
words = ['CRANK', 'UP']
game = VocabularyGame(chosen_word, words)
Outputs: Game start: TO _____ (STH) __
Trying a letter 7 times for i in range(7): game.try_letter()
Outputs:
Trying letter N...
Remaining letters: TO ___N_ (STH) __
Trying letter K...
Remaining letters: TO ___NK (STH) __
Trying letter R...
Remaining letters: TO _R_NK (STH) __
Trying letter P...
Remaining letters: TO _R_NK (STH) _P
Trying letter C...
Remaining letters: TO CR_NK (STH) _P
Trying letter U...
Remaining letters: TO CR_NK (STH) UP
Trying letter A...
Remaining letters: TO CRANK (STH) UP