My daughter and I are trying to teach ourselves Python and OOP. We wrote a hangman game, and we'd really appreciate some feedback. Are we heading in the right direction? How could we improve it? Anything that makes a Python programmer go "ouch"? Anything that makes an OOP expert cringe? All sorts of questions occur to us. For example, should we be instantiating classes when there is only one instance? Feel free to be brutal! We've posted it as a repl here: https://replit.com/@scripta/Hangman#main.py
Changed the invoking functionality into a class "Game" as per ASM's suggestion.
A huge thanks for the time and effort that went into commenting on the code. With apologies for having initially changed the code in this initial post (see above), here is a new post with most of the suggestions acted upon: OOP Hangman Game - amended code
import random class Word: def __init__(self): words = ("foxglove", "captain", "oxygen", "microwave", "rhubarb") self._word = random.choice(words) self.letters_in_word=set(self._word) @property def word(self): return self._word def progress(self, guesses): # create string of underscores and guessed letters to show progress to guessing word progress_string= "" for char in self.word: if guesses.guessed(char): progress_string= progress_string+" "+char+" " else: progress_string= progress_string +" _ " return(progress_string) def guessed(self, guesses): letters_guessed = self.letters_in_word.intersection(guesses.guesses_made) if letters_guessed == self.letters_in_word: return True else: return False class Guesses: def __init__(self): # guesses holds all guesses made (wrong or right) self.guesses_made = set() def guessed(self,char): if char in self.guesses_made: return True else: return False def record(self,guess,word): # All valid guesses (wrong or right) are added to the guesses set self.guesses_made.add(guess) if not guess in word.letters_in_word: Gallows.record_bad_guess() def made(self): # to sort the set of guesses made we need to cast it to a list guesses_list= list(self.guesses_made) guesses_list.sort() guesses_string="" #comma separate the guesses for char in guesses_list: guesses_string= guesses_string+char+"," return guesses_string class Gallows: _bad_guesses=0 gallows_images = (" \n \n \n \n \n__________", " \n | \n | \n | \n | \n_|________", " _____\n | \n | \n | \n | \n_|________", " _____\n |/ \n | \n | \n | \n_|________", " _____\n |/ |\n | \n | \n | \n_|________", " _____\n |/ |\n | O \n | \n | \n_|________", " _____\n |/ |\n | O \n | | \n | \n_|________", " _____\n |/ |\n | O \n | /| \n | \n_|________", " _____\n |/ |\n | O \n | /|\\ \n | \n_|________", " _____\n |/ |\n | O \n | /|\\ \n | / \n_|________", " _____\n |/ |\n | O \n | /|\\ \n | / \\\n_|________",) @classmethod def record_bad_guess(cls): cls._bad_guesses +=1 @classmethod def hanged(cls): if cls._bad_guesses >= len(cls.gallows_images)-1: return True else: return False @classmethod def draw(cls): return cls.gallows_images[cls._bad_guesses] class Game: def get_letter(self, guesses): while True: char= input("\nPlease enter your guess: ") if len(char)<1: print ("You didn't choose a letter!") elif len(char)!=1: print ("One letter at a time!") elif not char.isalpha(): print ("Alphabetic characters only!") elif guesses.guessed (char): print ("You already guessed that letter") else: break return (char) def display_progress(self, target, gallows, guesses): print("\n",target.progress(guesses)) print(gallows.draw()) print("\nUsed: \n",guesses.made()) def play(self): target= Word() guesses= Guesses() gallows= Gallows() while True: guess= self.get_letter(guesses) guesses.record(guess,target) self.display_progress(target, gallows, guesses) if target.guessed(guesses): print("\nYou win, well done") break if gallows.hanged(): print ("\nI win. The word was:",target.word) break if __name__ == "__main__": game= Game() game.play()