Python Hangman Game
newbiegreen4ever
Posted on July 8, 2021
2021.07.08 16:38
Hangman game
Introduction
I wrote a command-line word-guessing game using basic features of Python. It is a project under the Python Bundle - Python I of codingnomads.
I wrote this follow-up article as my learning log.
1) Generate a random word
reference: Geeksforgeeks - pulling a random word or a string from a line in a text file
Since I have some minimal experiences with JavaScript before, I believe that I have the ability to walk the extra mile and to do the optional part.
I wrote a list of words separated by space and store them in a .txt file.
hangman.txt
programming strong codingnomads rewarding frustrating
The list of words in the .txt file is treated like a list. Random integer is used to randomly pick one word out of the list.
import random
with open(r"C:\Users\User\Desktop\codingnomads\Python-101\projects\hangman.txt", "r") as file:
data = file.read()
words = data.split()
words_pos = random.randint(0, len(words) - 1)
print(f"position: {words_pos}")
print(f"word at position: {words[words_pos]}")
1.1) details with reading the path
reference: stackoverflow - unicode escape
An error will occur if the path is not treated by unicode escape r"path"
2) Split a word into a list of character
reference: stackoverflow - is there a function in python to split a word into a list
The syntax of Python is really intuitive. The syntax to split a word into a list of character is simply list(word)
.
2.1) why list? why not empty string?
Because strings in Python are immutable, which means that I cannot change the content of an empty string. List is a simple structure which supports item assignment.
# container = " "
# container[1] = "a"
# TypeError: 'str' object does not support item assignment
3) Check input
I use a while-loop inside the main while-loop to check user input.
The user can only input:
- alphabet
guess.isalpha()
- a single alphabet
len(guess) == 1
- alphabet not yet guessed correctly
guess in container
while container != word:
guess = input("Guess an alphabet: ").lower()
while not guess.isalpha() or len(guess) > 1:
guess = input("We only allow single character input. Please guess again: ").lower()
while guess.lower() in container:
guess = input(f"{guess.upper()} is already guessed. Please guess another alphabet: ").lower()
3.1) remember indentation level
Indentation level is important in Python.
If the guess in container
loop is indented below not guess.isalpha() or len(guess) > 1
loop, Python will only check guess which is not an alphabet and with a length longer than 1. The consequences are that Python will only check the bad guesses are in container, and the answer will always be no. This makes the snippet not meaningful.
4) Create a counter for how many attempts a user has taken
Position is important. Although Python does not have a strict namespace rule meaning that variable declared inside loop can be accessed outside loop, where to declare a variable is still important.
Remeber to declare the counter outside the main while-loop while container != word
, otherwise the counter will be re-assigned the value of 0 in every loop. This means the counter not meaningful as it only shows 0
then 1
then 0
.
5) Return all index with same value
reference: codegrepper - how to return all index with same value in list
Codegrepper suggests a one-line solution with enumerate()
.
indices = [i for i, x in enumerate(word) if x == guess]
reference: stackoverflow - index of duplicate items in a python list
Stackoverflow suggests a simple answer which uses the counter as the index to locate the element with the desired value.
if elem in string_list:
counter = 0
elem_pos = []
for i in string_list:
if i == elem:
elem_pos.append(counter)
counter = counter + 1
print(elem_pos)
6) Assign new value to container list
Now I am working with mutable list not immutable string. Therefore, value of an element in a string can be reassigned.
for index in indices:
if word[index] == guess:
container[index] = guess
7) Display container
It is handy to know that print()
function takes the argument of sep
(seperation) and end
(ending). I change the default ending from "\n"
to ""
such that every element of the container will be displaced in the same line.
for char in container:
if char.isalpha():
print(f" {char} ", sep=" ", end="")
else:
print(" _ ", sep=" ", end="")
print("\n")
8) End of game message
Python can easily turn a string into a list by list(str)
, and turn a list into a string by "".join(list)
.
I want a string here because I want to apply the str.format
and str.upper()
methods to make my output prettier.
if container == word:
print(f"""
Congratulation! You made it!
The word is {"".join(word).upper()!r}!
""")
else:
print(f"""
Your guesses are close.
The word is {"".join(word).upper()!r}.
""")
Full code
import random
with open(r"C:\Users\User\Desktop\codingnomads\Python-101\projects\hangman.txt", "r") as file:
data = file.read()
words = data.split()
words_pos = random.randint(0, len(words) - 1)
# print(f"position: {words_pos}")
# print(f"word at position: {words[words_pos]}")
word = list(words[words_pos])
container = list(len(word) * " ")
limit = len(word) + 5
counter = 0
# print(word)
# print(container)
print(f"""
Welcome! Let's play Hangman, the word-guessing game.
You will have {limit} chances to guess the word
Let's begin!
""")
for char in word:
print(" _ ", sep=" ", end="")
print("\n\n\n")
while container != word:
guess = input("Guess an alphabet: ").lower()
while not guess.isalpha() or len(guess) > 1:
guess = input("We only allow single character input. Please guess again: ").lower()
while guess.lower() in container:
guess = input(f"{guess.upper()} is already guessed. Please guess another alphabet: ").lower()
counter += 1
print(f"Number of guessess: {counter}")
if counter > limit:
print(f"You have already guessed {counter} times. You run out of time.")
break
for char in word:
if guess == char:
indices = [i for i, x in enumerate(word) if x == guess]
# print(indices)
for index in indices:
if word[index] == guess:
container[index] = guess
for char in container:
if char.isalpha():
print(f" {char} ", sep=" ", end="")
else:
print(" _ ", sep=" ", end="")
print("\n")
if container == word:
print(f"""
Congratulation! You made it!
The word is {"".join(word).upper()!r}!
""")
# how to join list into a string
# https://www.simplilearn.com/tutorials/python-tutorial/list-to-string-in-python
else:
print(f"""
Your guesses are close.
The word is {"".join(word).upper()!r}.
""")
Thank you for reading my article. Please feel free to leave any comment.
Posted on July 8, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024