I've stopped programming in Python for a long time now, someone recommended to me that the best way to get into it is by trying to code a game of Hangman, and that's what I did. Or tried to, at least.
import random
class Game:
def __init__(self, game_word):
self.game_word = game_word
class Player:
def __init__(self, guessed_word, guess_count, used_letters):
self.guess_count = guess_count
self.guessed_word = guessed_word
self.used_letters = used_letters
def get_word(): # getting a word from a txt file with a list of single words
word_file = open("words.txt")
game_word = random.choice(word_file.readlines())
game_word = game_word.strip().lower()
word_file.close()
return game_word
def user_guess(game, player):
print("Enter a letter: ")
letter = input().lower()
if check_input(letter, player.used_letters) == 0: # if check_input is 0 then there are no errors in player input
if letter in game.game_word: # determining if the guessed letter in the word
for i in range(0, len(game.game_word)):
if letter == game.game_word[i]:
player.guessed_word[i] = letter # replacing the '-' in the player's "guessed_word" with the letter
player.used_letters.append(letter)
else:
player.guess_count -= 1 # letter is not in the word, so player loses a life
player.used_letters.append(letter)
def check_input(letter, used_letters): # Just some error checking
if letter in used_letters:
print("Already guessed using this letter, try again with a different one!")
return 1
elif not letter.isalpha():
print("Only alphabets allowed!")
return 1
elif len(letter) > 1:
print("Only one character allowed per guess")
return 1
return 0
def game_round(game, player):
print("".join(player.guessed_word))
print("Letters used: " + " ".join(player.used_letters))
print("Number of tries left: " + str(player.guess_count))
user_guess(game, player)
def game_init():
guessed_word = list() # what the user guesses so far
used_letters = list() # used_letters will be used to store all the letters the player inputs throughout the game
game_word = get_word() # get a random word from a text file
for i in range(len(game_word)): # Print '-' for each letter in the word by default
guessed_word.append("-")
guess_count = int(input("Set the maximum number of guesses that you want\n"
"Number of guesses(lives): "))
return Game(game_word), Player(guessed_word, guess_count, used_letters)
def end_condition(game, player):
if "-" not in player.guessed_word: # if there are no more '-' then it means the user guessed the whole word
print("".join(player.guessed_word))
print("Game won!")
return True
elif player.guess_count == 0: # no more guesses remain
print("The correct word is \'" + game.game_word + "\'")
print("Game lost!")
return True
return False
def retry():
choice = input("Would you like to play again? Press \'y\' to start over\nNew round: ")
if choice == "y":
return True
return False
def main():
input("Press \"Enter\" to start the game\n")
while True:
game, player = game_init()
while True:
game_round(game, player) # player makes a guess
if not end_condition(game, player): # if game not over, player makes another guess
continue
break
if retry(): # start new game
continue
break
print("Game Over!")
if __name__ == "__main__":
main()
I feel like this could be improved more since I've done a similar version where everything was in the main function, and it was half as long.
import random
def main():
input("Press \"Enter\" to start the game\n")
while True:
word_file = open("words.txt")
game_word = random.choice(word_file.readlines())
game_word = game_word.strip().lower()
word_file.close()
guessed = list()
used_letters = list()
for i in range(len(game_word)):
guessed.append("-")
count = 10
while True:
print("".join(guessed))
print("Letters used: " + " ".join(used_letters))
print("Number of tries left: " + str(count))
print("Enter a letter: ")
letter = input().lower()
if letter in used_letters:
print("Already guessed using this letter, try again with a different one!")
continue
elif not letter.isalpha():
print("Only alphabets allowed!")
continue
elif len(letter) > 1:
print("Only one character allowed per guess")
continue
elif letter in game_word:
for i in range(0, len(game_word)):
if letter == game_word[i]:
guessed[i] = letter
else:
count -= 1
used_letters.append(letter)
if "-" not in guessed:
print("".join(guessed))
print("Game won!")
game_over = True
break
elif count == 0:
print("The correct word is \'" + game_word + "\'")
print("Game lost!")
game_over = True
break
if game_over:
choice = input("Would you like to play again? Press \'y\' to start over\nNew round: ")
if choice == "y":
continue
else:
break
print("Game Over!")
if __name__ == "__main__":
main()
The words text file. In case the link doesn't work, the text file is just single-words separated by a new line.
1 Answer 1
In this code:
def __init__(self, guessed_word, guess_count, used_letters):
self.guess_count = guess_count
self.guessed_word = guessed_word
self.used_letters = used_letters
used_letters
should not be passed as an argument, nor should it be constructed as a list
in game_init
. Just construct it in __init__
. Also, it should be a set
instead of a list
for efficiency.
Similarly, rather than guessed_word
being initialized in game_init
, it should be initialized in Player.__init__
. You can pass game_word
to __init__
, and then in there, you can write
guessed_word = '-' * len(game_word)
As for guess_count
, the name is a little confusing, because it isn't strictly "guess count", but rather "remaining guesses".
This:
if choice == "y":
return True
return False
can be abbreviated to
return choice == 'y'
but you should also convert choice
to lowercase before doing that comparison.
This loop:
while True:
game_round(game, player) # player makes a guess
if not end_condition(game, player): # if game not over, player makes another guess
continue
break
can be abbreviated to
while not end_condition(game, player):
game_round(game, player)
These lines:
print("".join(player.guessed_word))
print("Letters used: " + " ".join(player.used_letters))
print("Number of tries left: " + str(player.guess_count))
should be moved to a method of Player
, perhaps called print_round
.
This:
word_file = open("words.txt")
game_word = random.choice(word_file.readlines())
game_word = game_word.strip().lower()
word_file.close()
should have word_file
in a with
statement, rather than an explicit close.
More generally, you're using Game
and Player
as C struct-like objects with no methods. You should make an attempt to convert them to true classes with methods on the objects, rather than global methods that operate on the class member variables.