Простая игра Hangman

В моем стремлении стать мастером-программистом я создал простую игру Hangman, и поэтому я решил загрузить ее здесь и посмотреть, как ее можно улучшить.

Один вопрос, который у меня был, - это использование обработки исключений. Я попытался использовать его здесь, но я понял, что это может быть излишним. Должен ли я использовать try /except, если я знаю, что будут исключения, или это хорошая практика использовать их независимо?

"""Hangman
Standard game of Hangman. A word is chosen at random from a list and the
user must guess the word letter by letter before running out of attempts."""

import random

def main():
    welcome = ['Welcome to Hangman! A word will be chosen at random and',
               'you must try to guess the word correctly letter by letter',
               'before you run out of attempts. Good luck!'
               ]

    for line in welcome:
        print(line, sep='\n')

    # setting up the play_again loop

    play_again = True

    while play_again:
        # set up the game loop

        words = ["hangman", "chairs", "backpack", "bodywash", "clothing",
                 "computer", "python", "program", "glasses", "sweatshirt",
                 "sweatpants", "mattress", "friends", "clocks", "biology",
                 "algebra", "suitcase", "knives", "ninjas", "shampoo"
                 ]

        chosen_word = random.choice(words).lower()
        player_guess = None # will hold the players guess
        guessed_letters = [] # a list of letters guessed so far
        word_guessed = []
        for letter in chosen_word:
            word_guessed.append("-") # create an unguessed, blank version of the word
        joined_word = None # joins the words in the list word_guessed

        HANGMAN = (
"""
-----
|   |
|
|
|
|
|
|
|
--------
""",
"""
-----
|   |
|   0
|
|
|
|
|
|
--------
""",
"""
-----
|   |
|   0
|  -+-
|
|
|
|
|
--------
""",
"""
-----
|   |
|   0
| /-+-
|
|
|
|
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|
|
|
|
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|   | 
|
|
|
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|   | 
|   | 
|
|
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|   | 
|   | 
|  |
|
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|   | 
|   | 
|  | 
|  | 
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|   | 
|   | 
|  | | 
|  | 
|
--------
""",
"""
-----
|   |
|   0
| /-+-\ 
|   | 
|   | 
|  | | 
|  | | 
|
--------
""")

        print(HANGMAN[0])
        attempts = len(HANGMAN) - 1


        while (attempts != 0 and "-" in word_guessed):
            print(("\nYou have {} attempts remaining").format(attempts))
            joined_word = "".join(word_guessed)
            print(joined_word)

            try:
                player_guess = str(input("\nPlease select a letter between A-Z" + "\n> ")).lower()
            except: # check valid input
                print("That is not valid input. Please try again.")
                continue                
            else: 
                if not player_guess.isalpha(): # check the input is a letter. Also checks an input has been made.
                    print("That is not a letter. Please try again.")
                    continue
                elif len(player_guess) > 1: # check the input is only one letter
                    print("That is more than one letter. Please try again.")
                    continue
                elif player_guess in guessed_letters: # check it letter hasn't been guessed already
                    print("You have already guessed that letter. Please try again.")
                    continue
                else:
                    pass

            guessed_letters.append(player_guess)

            for letter in range(len(chosen_word)):
                if player_guess == chosen_word[letter]:
                    word_guessed[letter] = player_guess # replace all letters in the chosen word that match the players guess

            if player_guess not in chosen_word:
                attempts -= 1
                print(HANGMAN[(len(HANGMAN) - 1) - attempts])

        if "-" not in word_guessed: # no blanks remaining
            print(("\nCongratulations! {} was the word").format(chosen_word))
        else: # loop must have ended because attempts reached 0
            print(("\nUnlucky! The word was {}.").format(chosen_word))

        print("\nWould you like to play again?")

        response = input("> ").lower()
        if response not in ("yes", "y"):
            play_again = False

if __name__ == "__main__":
    main()
12 голосов | спросил acardnell24 6 J000000Monday15 2015, 20:48:59

4 ответа


8

У вас есть голое исключение; то есть.,

try:
     some_code()
except:
     clean_up()

Проблема с голым, кроме того, что она будет ловить все исключения, включая те, которые вы действительно не хотите игнорировать (например, KeyboardInterrupt и SystemExit). Было бы намного лучше, если бы ваш исключающий блок поймал только конкретное исключение, которое вы ожидаете, и пусть все остальные пузырьки будут нормальными.

Несколько других общих комментариев к вашему коду:

  • В строке 200 у вас есть эта конструкция:

    for letter in range(len(chosen_word)):
        if player_guess == chosen_word[letter]:
            word_guessed[letter] = player_guess
    

    Вы перебираете индексную переменную, но также используете элемент списка. Было бы лучше написать:

    for idx, letter in enumerate(chosen_word):
        if player_guess == letter:
            word_guessed[idx] = player_guess
    
  • Вместо использования значения флага play_again вы можете использовать оператор break. То есть структурируйте свой код следующим образом:

    while True:
        # play the game
    
        if not player_response_is_play_again():
            break
    

    Это немного чище и проще в использовании, потому что мне не нужно следовать переменной play_again.

  • Функция main () огромная . Большая часть этого кода не может использоваться повторно, потому что она привязана к одной монолитной функции. Вам было бы гораздо лучше разбить его на небольшие, четкие единицы кода: их легче протестировать и отладить, и было бы более многократно загружаться.

ответил alexwlchan 6 J000000Monday15 2015, 21:10:29
5

У вас слишком много кода в вашей функции main. Попробуйте посмотреть, можете ли вы разделить логику на отдельные функции, каждая из которых имеет свои собственные аргументы. Например, нижний блок кода:

words = ["hangman", "chairs", "backpack", "bodywash", "clothing",
                 "computer", "python", "program", "glasses", "sweatshirt",
                 "sweatpants", "mattress", "friends", "clocks", "biology",
                 "algebra", "suitcase", "knives", "ninjas", "shampoo"
                 ]

chosen_word = random.choice(words).lower()

Можно легко разделить на функцию с именем choose_word, например:

def choose_word(word_list):
    """
    Choose a random word from the word_list
    and return it.
    """
    return random.choice(word_list)

У вас также есть длинные строки mutliline. Например, следующая многострочная строка:

"""
-----
|   |
|
|
|
|
|
|
|
--------
"""

С этим можно легко укоротить:

"-----\n|   |\n|\n|\n|\n|\n|\n|\n|\n--------"

Заметьте, это не требуется. Это личное предпочтение.


То, как вы печатаете несколько фрагментов текста, также нечетное. Например, следующий фрагмент кода:

welcome = ['Welcome to Hangman! A word will be chosen at random and',
               'you must try to guess the word correctly letter by letter',
               'before you run out of attempts. Good luck!'
               ]

    for line in welcome:
        print(line, sep='\n')

Снова можно сократить:

print(
    "Welcome to Hangman! A word will be chosen at random and",
    "you must try to guess the word correctly letter by letter",
    "before you run out of attempts. Good luck!",
    sep="\n"
)

Я также заметил, что вы смешиваете использование одинарных кавычек, '' и двойные кавычки, "". Хотя это не огромная сделка, я бы рекомендовал выбрать один или другой и придерживаться его.


То, как вы создаете списки стилей, тоже странно. Хотя это не требуется, я бы рекомендовал сделать это следующим образом:

my_list = [
    value,
    ...
]

Наконец, при получении пользовательского ввода вам не нужно преобразовывать его в строку с помощью функции str. Вы можете просто получить его так: user_input = input("prompt").

ответил Ethan Bierlein 6 J000000Monday15 2015, 21:11:35
4
for line in welcome:
    print(line, sep='\n')

Это выглядит как код, который будет в функции для печати нескольких строк в массиве. Однако, поскольку у вас есть только одно сообщение, находящееся в массиве, это кажется излишним, тем более, что существует только три строки.

Было бы намного проще распечатать сообщение так:

print "..."
print "..."
...

Вместо того, чтобы пытаться получить собственный список слов, я рекомендую попробовать один из этих трех вариантов:

  • Найти API.

В Интернете, вероятно, имеется множество API, которые будут служить в качестве словаря для вашей программы.

Pro : вам не нужно ничего скачивать; просто сделайте простой вызов API.

Кон : API имеют ограничения, такие как вызовы в день. Кроме того, иногда ваш код может зависеть от вызова API.

Слова Unix в словаре, который поставляется с Unix и Unix-подобными операционными системами.

Pro . Это всего лишь файл на компьютере, в котором есть одно слово в строке, что упрощает его чтение.

Кон . Ваш пользователь может не использовать Unix или Unix-подобную операционную систему.

  • Использовать PyEnchant.

Я не знаю об этом. Я видел, что он используется в каком-то коде Python, прежде чем это связано с английской ссылкой на слова, но я не знаю, как работает его встроенный словарь.


chosen_word = random.choice(words).lower()

Нет смысла вызывать метод .lower, потому что все слова в вашем словаре уже имеют нижний регистр.


Когда вы спрашиваете, хочет ли пользователь снова играть:

print("\nWould you like to play again?")

Вместо того, чтобы иметь условие, в котором вы проверяете два варианта позже («да» и «y»), дайте пользователю свои параметры:

print("\nWould you like to play again? [Y/N]")

И, чтобы сделать шаг дальше и избавиться от вызова дополнительной функции, поместите это сообщение внутри вызова input:

input("\nWould you like to play again? [Y/N]\n>")

Переменная welcome в начале вашего кода:

welcome = ['Welcome to Hangman! A word will be chosen at random and',
           'you must try to guess the word correctly letter by letter',
           'before you run out of attempts. Good luck!'
           ]

Не должно быть в массиве; он должен быть в кортеже, потому что значения в нем не будут меняться.

То же самое относится к вашему массиву words.


Чтобы ответить на ваш вопрос об исключениях, я думаю, что вы должны использовать try/exception, если знаете, что будут ошибки. Всегда полезно поймать и остановить ошибку, но нет смысла пытаться, если не будет ошибок.

Кроме того, зная, что будут ошибки, потому что тогда вы можете поймать правильный вид ошибки, а не просто ловлять Exception.

Вы хорошо справились с этой ошибкой и не согласны с использованием try/except и if/else:

try:
    player_guess = str(input("\nPlease select a letter between A-Z" + "\n> ")).lower()
except: # check valid input
    print("That is not valid input. Please try again.")
    continue 

Однако вы должны поймать тип ошибки, которая выйдет из этой строки.

Я не уверен, какая ошибка выйдет, но я думаю, что это либо TypeError, либо IOError. В любом случае, вы изменили бы свой код try/except на следующее:

try:
    ...
catch ExceptionType:
    ...
ответил SirPython 6 J000000Monday15 2015, 21:17:04
3

Вы спросили о вашей обработке исключений.

        try:
            player_guess = str(input("\nPlease select a letter between A-Z" + "\n> ")).lower()
        except: # check valid input
            print("That is not valid input. Please try again.")
            continue                
        else: 
            if not player_guess.isalpha(): # check the input is a letter. Also checks an input has been made.
                print("That is not a letter. Please try again.")
                continue
            elif len(player_guess) > 1: # check the input is only one letter
                print("That is more than one letter. Please try again.")
                continue
            elif player_guess in guessed_letters: # check it letter hasn't been guessed already
                print("You have already guessed that letter. Please try again.")
                continue
            else:
                pass

вы сначала запускаете ввод, чтобы посмотреть, является ли это строкой, а затем говорят, что это недопустимый ввод, а затем вы проверяете, является ли символ альфа-символом. Вы должны просто проверить, является ли он первым альфа-символом, тогда вы можете устранить необходимость в try /catch.

Это либо буква, либо нет, верно?

ответил Malachi 6 J000000Monday15 2015, 23:42:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132