Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from string import ascii_lowercase # shame to restrict to ascii, your choice
- from io import StringIO # to use a string like a file
- from random import choice # to randomly pick a word
- from pathlib import Path # to better handle files on your computer
- import logging # for outputting programmer/tester info
- import argparse # to take arguments from command line, to enable debugging
- HANGMAN_ASCII_ART = """Welcome to the
- _ _
- | | | |
- | |__| | __ _ _ __ __ _ _ __ ___ __ _ _ __ __ _ __ _ _ __ ___ ___
- | __ |/ _` | '_ \ / _` | '_ ` _ \ / _` | '_ \ / _` |/ _` | '_ ` _ \ / __|
- | | | | (_| | | | | (_| | | | | | | (_| | | | | | ( | | (_| | | | | | | (__
- |_| |_|\__,_|_| |_|\__, |_| |_| |_|\__,_|_| |_| \__, |\__,_|_| |_| |_|____|
- __/ | __/ |
- |___/ |___/"""
- MAX_TRIES = 'You Have 6 Tries'
- HANGMAN_PHOTOS = {
- 1: """
- x-------x
- """,
- 2: """
- x-------x
- |
- |
- |
- |
- |
- x-------x
- """,
- 3: """
- x-------x
- | |
- | 0
- |
- |
- |
- x-------x
- """,
- 4: """
- x-------x
- | |
- | 0
- | |
- |
- |
- x-------x
- """,
- 5: r"""
- x-------x
- | |
- | 0
- | /|\
- |
- |
- x-------x
- """,
- 6: r"""
- x-------x
- | |
- | 0
- | /|\
- | /
- |
- x-------x
- """,
- 7: r"""
- x-------x
- | |
- | 0
- | /|\
- | / \
- |
- x-------x
- """
- }
- # using StringIO buffer instead of external file, use can choose to name a file
- BUFFER = """Alpha
- Beta
- Charlie
- Delta"""
- def print_hangman(fails: int) -> None:
- """ prints state of gallows based on number of failed guesses """
- if fails == 0:
- return
- if fails in HANGMAN_PHOTOS:
- print(HANGMAN_PHOTOS[fails])
- print(f"\n{fails} bad guess{'' if fails == 1 else 'es'}\n")
- else:
- raise ValueError(f"Invalid number of tries, {fails}, for HANGMAN_PHOTOS")
- def get_word(file_path: Path | str) -> str:
- """ pick and return random word from internal list or user supplied file """
- # added a lot here to original to give you some ideas on handling files and dealing with exceptions
- # needs more testing / experimentation
- # notice we decide whether to use open or StringIO function
- if isinstance(file_path, Path): # check we have a Path object
- if not (file_path.exists() and file_path.is_file()): # are we looking at a file?
- logging.error(f'{file_path=} exists or is_file test failed', exc_info=True)
- raise IOError(f'File, {file_path} not available')
- opener = open # so we can use open function
- elif isinstance(file_path, str) and file_path: # otherwise assume we have multine string
- opener = StringIO # so we can use StringIO function
- else: # not expecting anything other than a Path or a string
- logging.error(f'{file_path=} not a Path or str test failed', exc_info=True)
- raise IOError(f'File/buffer, {file_path} not available')
- logging.debug(f'trying to read {file_path=}')
- try: # let's see if this works
- with opener(file_path) as file:
- words = file.read().split()
- except IOError: # oops (probably some other exceptions need catching here)
- logging.error(f'{file_path=} caused an error when reading', exc_info=True)
- raise IOError(f'Unable to read file, {file_path}')
- word = choice(words).lower() # pick a word at random, force it to be lowercase
- logging.debug(f'{word=}') # handy to know what was picked when testing
- return word
- def guess_word(file_path: Path | str) -> str | None:
- """Prompts the player to guess the secret word at the specified index in the file."""
- # actually, this runction is a lot simpler now as we ask for file_path in main
- try:
- secret_word = get_word(file_path)
- except IOError as errmsg:
- print(errmsg)
- return None
- except OSError as errmsg:
- print(errmsg)
- return None
- return secret_word
- def check_valid_input(letter_guessed: list[str], old_letters_guessed: list[str]) -> bool:
- if len(letter_guessed) != 1:
- return False
- if letter_guessed not in ascii_lowercase:
- return False
- if letter_guessed in old_letters_guessed: # already tried that one, maybe a little unfair
- return False
- return True
- def try_update_letter_guessed(letter_guessed: list[str], old_letters_guessed: list[str]) -> bool:
- if check_valid_input(letter_guessed, old_letters_guessed):
- old_letters_guessed.append(letter_guessed)
- status = True
- logging.debug(f'Added guess {letter_guessed} to guesses so far')
- else:
- print(f"{letter_guessed} is not a good choice")
- status = False
- print("Guesses so far:", ", ".join(sorted(old_letters_guessed)))
- return status
- def show_hidden_word(secret_word: list[str], old_letters_guessed: list[str]) -> str:
- return '\nPattern: ' + ''.join(ltr if ltr in old_letters_guessed else '_' for ltr in secret_word)
- def check_win(secret_word: list[str], old_letters_guessed: list[str]) -> bool:
- return set(secret_word).issubset(old_letters_guessed)
- def main() -> None:
- print(HANGMAN_ASCII_ART)
- print(MAX_TRIES)
- print()
- num_of_tries = 0
- old_letters_guessed = []
- num_of_fails = 0
- user_file_path = input('File to use: (return for built-in words) ')
- if user_file_path:
- file_path = Path(user_file_path)
- else:
- file_path = BUFFER # internal multi-line string of words
- secret_word = guess_word(file_path)
- if secret_word is None:
- print('Was not able to pick a secret word')
- return # could pass an error code here
- guessed = False
- while num_of_fails <= 6 and not guessed:
- num_of_tries += 1
- print_hangman(num_of_fails)
- print(show_hidden_word(secret_word, old_letters_guessed))
- letter_guessed = input(f"Guess #{num_of_tries:2}: please guess a letter (or whole word): ").strip().lower()
- if letter_guessed == secret_word: # have they jumped ahead and guessed whole word?
- guessed = True
- else:
- valid = try_update_letter_guessed(letter_guessed, old_letters_guessed)
- if not valid or letter_guessed not in secret_word:
- num_of_fails += 1
- else:
- guessed = check_win(secret_word, old_letters_guessed)
- print_hangman(num_of_fails)
- print(show_hidden_word(secret_word, old_letters_guessed))
- if guessed:
- print(f"Congratulations! You guessed the word with {num_of_tries} guesses.")
- else:
- print("Sorry, you ran out of tries. The word was:", secret_word)
- def set_up_logging():
- # setting up argparse to use command line arguments to check debugging status
- parser = argparse.ArgumentParser()
- parser.add_argument(
- '-d', '--debug',
- help="Print lots of debugging statements",
- action="store_const", dest="loglevel", const=logging.DEBUG,
- default=logging.WARNING,
- )
- parser.add_argument(
- '-v', '--verbose',
- help="Be verbose",
- action="store_const", dest="loglevel", const=logging.INFO,
- )
- args = parser.parse_args()
- logging.basicConfig(level=args.loglevel)
- if __name__ == '__main__':
- set_up_logging()
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement