I'm a hobbist trying to become a professional software developer. I do have a lot interest in Data Science in general and my goal is to master Python before diging deeper into specific data science topics.
I created this game when I started studying object oriented programming. Thank you all in advance.
import os
import getpass
class Hangman:
winner = False
word = ''
mask = ''
mistakes = []
def __init__(self, word):
self.word = word
self.mask = '_ ' * len(word)
def make_move(self, letter):
letter_match = self.word.find(letter)
if letter_match >= 0:
for i, w in enumerate(self.word):
if w == letter:
new_mask = list(self.mask)
new_mask[i * 2] = letter
self.mask = ''.join(new_mask)
self.check_winner()
else:
self.mistakes.append(letter)
print('Wrong!')
def check_winner(self):
if self.mask.find('_') < 0:
self.show_board()
print('You won!')
self.winner = True
return self.winner
def check_looser(self):
if len(self.mistakes) > 4:
print('You loose! The word was %s' % self.word)
quit()
def show_board(self):
os.system('cls')
print(self.mask)
print(self.mistakes)
def play(self):
while not self.winner:
self.show_board()
letter_input = input('Choose a letter: ').upper()
self.make_move(letter_input)
self.check_looser()
secret_input = getpass.getpass('Secret Word: ').upper()
game = Hangman(secret_input)
game.play()
-
1\$\begingroup\$ You should elaborate a bit more about your code, what decisions you made and why, to get better reviews. \$\endgroup\$πάντα ῥεῖ– πάντα ῥεῖ2019年11月13日 17:32:28 +00:00Commented Nov 13, 2019 at 17:32
1 Answer 1
It might be slightly cleaner and more performant to keep self.mask
as a list, and just join
it before printing:
# Basically what you had before, without the space
# Just "list multiplication" instead of "string multiplication"
self.mask = ['_'] * len(word)
. . .
if w == letter:
mask[i] = letter
. . .
if '_' not in self.mask:
self.show_board()
print('You won!')
. . .
print(' '.join(self.mask))
Now there's less converting back and forth between strings and lists. This also saves you from needing to do i * 2
. The spaces can just be added in using join
before being printed, so you don't need to worry about them.
print(self.mistakes)
currently prints out a normal list representation to the end user without any context. I'd probably prefix a message to that, and format it a bit before printing:
print(f"Already tried: {', '.join(self.mistakes)}")
# Already tried: R, Q
I'd probably get rid of self.winner
and change how you're checking for winning. Notice what you're using it for: you assign it in check_winner
, then return that same value that you just assigned, but never use the return value. I'd have check_winner
just return the value, move the call to check_winner
to after the call to make_move
, and use the return value:
def check_winner(self):
if '_' not in self.mask:
self.show_board()
print('You won!')
return True
return False
. . .
def play(self):
won = False # Just track this locally instead
while not won:
self.show_board()
letter_input = input('Choose a letter: ').upper()
self.make_move(letter_input)
won = self.check_winner() # And assign it here
self.check_loser()
I'd also probably change check_loser
(As a heads up, it's spelled "loser". "Looser" means that one thing is "less tight" than something else). I'd maybe have it return a bool saying whether or not the player lost, and just return from that function instead. As I noted in a previous review (at the bottom), quit
can cause problems when testing code. Just returning from the main loop to allow control to pass back to the REPL is much cleaner.