2
\$\begingroup\$

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.

asked Dec 21, 2018 at 16:51
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

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.

answered Dec 21, 2018 at 17:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.