首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我在Python里的第一个Hangman游戏

我在Python里的第一个Hangman游戏
EN

Code Review用户
提问于 2019-09-24 06:08:29
回答 1查看 901关注 0票数 10

这是我的第一场比赛,我真的很自豪,但我认为这是可怕的混乱。有什么办法可以改进吗?

代码语言:javascript
复制
#HANGMAN

# Valid Word Checker

def valid_word(word):

    ill_chars = ["!","@","#","$","%","^","&","*","(",")",",",".", " ","1","2","3","4","5","6","7","8","9","0"]
    for i in word:
        if i in ill_chars:
            print(f"\nError: It must be a letter. No symbols, numbers or spaces allowed. \n\n '{i}' is not allowed\n")
            return False
    if len(word) > 12:
        print("\n\nError: Word is too long. Use a word with eight characters or less.")
        return False
    return True

word_list = []
spaces = []
guessed_letters = []

ill_chars = ["!","@","#","$","%","^","&","*","(",")",",",".", " ","1","2","3","4","5","6","7","8","9","0"]

head ="    O"
armL = "   /"
torso = "|" 
armR = "\\"
legL = "/"
legR = " \\"

hangman_parts = [head, armL, torso, armR, legL, legR]
hangman_progress = ["", 
                    "|", 
                  "\n|", 
                  "\n|"]

hangman_final = ["|~~~~|\n"]

# Check if word is valid

wordisValid = False
while True:
    word = input("\n\n\nChoose any word\n\n\n").lower()
    if valid_word(word) == True:
        wordisValid = True
        break
    else:
        continue

# Add to list
for i in word:

    word_list.append(i)
    spaces.append("_ ") 

# Main Game Loop
bad_letter = 0

while wordisValid == True:  


    print("".join(hangman_final))
    print("\n\n\n\n")
    print("".join(spaces))
    print("\n\nThe word has: " + str(len(word)) + " letters.")
    print("\nYou've tried the following letters: " + "\n\n" + "".join(guessed_letters) + "\n\n")


    # Winning Loop

    if "".join(spaces) == word:
        print(f"YOU WIN! The word was: {word}")
        break
    # Choose Letters

    player_guess = input("\n\nPlease choose a letter: \n\n\n\n").lower()
    guessed_letters.append(" " + player_guess)

    if player_guess in ill_chars:
        print(f"\nError: It must be a letter. No symbols, numbers or spaces allowed. \n\n '{player_guess}' is not allowed\n")
    elif len(player_guess) > 1:
        print("\nError: You must use one letter.\n")
    elif player_guess == "":
        print("\nError: No input provided.\n")


    # Wrong Letter
    elif player_guess not in word_list:

        bad_letter += 1

        if bad_letter == 1:
            hangman_final.append(hangman_progress[1] + head)

        elif bad_letter == 2:
            hangman_final.append(hangman_progress[2] + "    " + torso)

        elif bad_letter == 3:
            hangman_final.pop(2)
            hangman_final.append(hangman_progress[2] + armL + torso)

        elif bad_letter == 4:
            hangman_final.pop(2)
            hangman_final.append(hangman_progress[2] + armL + torso + armR)

        elif bad_letter == 5:
            hangman_final.append(hangman_progress[3] + "   " + legL)

        elif bad_letter == 6:
            hangman_final.pop(3)
            hangman_final.append(hangman_progress[3] + "   " + legL + legR)
            print("\n\nThe word was: " + word)
            print("\n\n\n\n\n\n\n" + "".join(hangman_final))
            print(" YOU GOT HUNG ")
            break


        print("".join(hangman_final))
        print("\n\n\n\n")
        print("".join(spaces))
        print("\n\nThe word has: " + str(len(word)) + " letters.")
        print("\nYou've tried the following letters: " + "\n\n" + "".join(guessed_letters) + "\n\n")
        print(f"\n\n\n{player_guess} is not in the word. Try again.\n\n")


    # END GAME
    if bad_letter == 6:
        break

    # Add letters guessed to a list
    counter = 0
    for i in word:

        if player_guess == i:
            spaces[counter] = player_guess
        counter += 1

尽管它是有效的,我不确定我是否有正确的想法,当涉及到作出这种类型的项目。

EN

回答 1

Code Review用户

回答已采纳

发布于 2019-09-24 07:59:34

虽然很明显,您对python还不熟悉,但是仍然可以让它第一次运行。做得好!

输入验证

目前,您有一个禁止字符列表。虽然这样可以工作,但默认情况下python允许unicode输入。这意味着人们可以输入成千上万的字母。我建议使用有效输入的白名单。如下所示:

代码语言:javascript
复制
VALID_LETTERS = "abcdefghijklmnopqrstuvwxyz"  # This won't ever change, and typically this sort
# of things  is a module-level variable. 

def valid_word(word):
    for letter in word:
        if letter not in VALID_LETTERS:
            print(f"Letter {letter} is not a valid letter. Please use just a-z.")
            return
    if len(word) > 8:  # This was 12 in your script. Little mistake? And you might want a 
        # module-level constant for this as well.
        print("\n\nError: Word is too long. Use a word with eight characters or less.")
        return False
    return True

main()和

通常,在python中,我们从不会在加载模块时执行代码。详情请在这里阅读,以及我们如何防范它。我过会儿再谈这个。现在,这意味着我们应该尽可能多地使用函数--让我们称它们为main()和put ()。

main()将是主菜单函数。因为我们没有真正的菜单,这基本上会开始一个游戏,也许会问玩家是否想再玩一次。

游戏()将是一个让我们玩一个游戏的函数。这其中的大部分将是一个循环,以获取玩家的输入和计算游戏状态。基本上,脚本中不属于其他函数的所有内容都应该在game()函数中。

我以后会剪掉一些我们不需要的变量。当我们到达我们使用它们的地方时我会解释的。

如下所示:

代码语言:javascript
复制
def game():
    # Variable naming is important. This is an example of a good name.
    guessed_letters = []

    # ill_chars = [...]  We already have this variable before here!

    # Lets assign the parts directly. We can index them as in "3rd part".
    # And for ourselves, we comment the meaning to make sure we still know what it means a year 
    # from now.
    hangman_parts = [
        "    O",  # Head
        "   /",  # Left Arm
        "|" ,  # Torse
        "\\",  # Right Arm
        "/",  # Left Leg
        " \\"  # Right Leg
    ]
    hangman_progress = ["", 
                        "|", 
                      "\n|", 
                      "\n|"]

    hangman_final = ["|~~~~|\n"]

    # Check if word is valid

    # Naming: should be word_is_valid, to be consistent with your other variables.
    word_is_valid = False
    while not word_is_valid:
        word = input("\n\n\nChoose any word\n\n\n").lower()
        word_is_valid = valid_word(word)
    # With this loop condition, it'll keep asking until valid_word returns True. So we can just 
    # assign that value to word_is_valid directly.

    # Since this is the word we're trying to guess, lets just push it upwards in
    # the console a lot, so we won't see it all the time:
    print("\n" * 100)  # Prints 100 newlines.

    # We don't need word_list, just word will do. We don't need spaces either.
    while True:  # Main game loop. We don't need to check for anything, we'll just use break or
        # return to get out.

现在我们要用一个列表理解。它几乎与生成器表达式相同,但它给出了一个真正的列表,因此我们可以问python它有多长:

代码语言:javascript
复制
        # Calculate how many bad letters we have with a list comprehension:
        bad_letter = len([letter for letter in guessed_letters if letter not in word])
        draw_hangman(bad_letter)
        if bad_letter > 5:
            print("\n\n\n\nYOU GOT HUNG")
            return
        print("\n\n\n\n")

你过去常常在两个不同的地方画你的绞刑架,而在一个地方做则更实用。它还确保如果您想要更改某些内容,则只需更改一次。

我也改变了画它的方法。为这个绘图操作设置一个函数更有用,并让它计算到目前为止如何从坏字母的数量中绘制。这使得绘图独立于当前的游戏状态。下面是我根据您对hangman_final的修改提出的版本:

代码语言:javascript
复制
def draw_hangman(bad_letter):
    print(hangman_final, end="")
    if bad_letter > 0:  # Head
        print(hangman_progress[1] + hangman_parts[0], end="")
    if bad_letter == 2:  # Torso and arms
        print(hangman_progress[2] + "    " + hangman_parts[2], end="")
    elif bad_letter == 3:
        print(hangman_progress[2] + "".join(hangman_parts[1:3]), end="")
    elif bad_letter > 3:
        print(hangman_progress[2] + "".join(hangman_parts[1:4]), end="")
    if bad_letter > 4:  # Legs
        print(hangman_progress[3] + "   " + hangman_parts[4], end="")
    if bad_letter > 5:
        print(hangman_parts[5], end="")

在这里,我们需要打印我们猜到的字母,而下划线不是这样。我们可以在一行中计算和打印:

代码语言:javascript
复制
        print(" ".join(letter for letter in word if letter in guessed_letters else "_"))

对于每个字母,如果它包含在guessed_letters中,它就会打印出来,否则就会打印一个下划线。这是一个生成器表达式。这个函数几乎等于以下函数:

代码语言:javascript
复制
def make_word(word, guessed_letters):
    result = []
    for letter in word:
        if letter in guessed_letters:
            result.append(letter)
        else:
            result.append("_")
    return result

我说这几乎是因为它不完全是从其中产生的列表,即使在for循环中使用它或将它提供给"".join()这样的函数时,它的作用也是一样的。它的作用也更像一个循环,而不是一个函数,但这一点现在并不重要。

我们将结果提供给连接。请注意,我们将其输入到“".join(),中间有一个空格,这将在每个字母之间放一个空格,就像您以前做的那样。

代码语言:javascript
复制
        print(f"\n\nThe word has: {len(word)} letters.")  # f-strings are shorter, and easy to use. 
        print(f"\nYou've tried the following letters:\n\n{''.join(guessed_letters) }\n\n")
        # For a string literal inside an f-string, use the other type of quotes

        # This is another generator expression - this one returns a not-quite-list of booleans, and
        # the all() builtin function returns True if and only if all results of the generator
        # expression are True.
        if all(letter in guessed_letters for letter in word):
            print(f"You WIN!\nThe word was: {word}")
            return

        input_valid = False
        while not input_valid:
            new_letter = input("\n\nPlease choose a letter: \n\n\n\n").lower()
            # VERY GOOD that you lowercase it! Prevents tons of weird behaviour.
            if len(new_letter) > 1:
                print("Please enter a single letter only.")
            elif new_letter not in VALID_LETTERS:
                print(f"{new_letter} is not a valid letter. Please enter a letter a-z")
            elif not new_letter:  # Empty strings evaluate to False
                print("Please enter a letter before pressing enter.")
            elif new_letter in guessed_letters:
                print("You already guessed {new_letter} before!")
            else:
                guessed_letters.append(new_letter):
                input_valid = True

这与你的投入非常接近。但是我把它放在一个循环中,所以如果我们有一个无效的输入,我们就不用再遍历整个游戏循环了。我使用了一个非常简单的信号布尔值来保持它的运行,但是也许有更优雅的方法来做到这一点。不过,保持简单是永远不会错的。

现在,要玩这个游戏,只需调用game()函数。但也许我们想玩多场系列赛?让我们让我们的main()函数:

代码语言:javascript
复制
def main():
    game()
    while "y" in input("Play again? [Y/n]").lower():
        game()

为什么这是在一个单独的功能?再一次,为了扩展性。也许,我们想从另一个模块导入我们的游戏。如果是这样的话,我们不希望它在导入时运行,而是在调用函数时运行。所以我们用这个守卫结束这个脚本:

代码语言:javascript
复制
if __name__ == "__main__":
    main()

如果我们直接执行这个文件,这将运行main()函数并让我们玩游戏。但是如果我们导入它,它就不会,所以我们可以在需要的时候调用这个函数。

票数 16
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/229552

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档