我正在用自己的两只脚开始学习编程的艰巨旅程,并创建了一个回合制战斗模拟器(想想神奇宝贝)。这个想法来自这里。

它很粗糙,可能需要大量改进,所以我愿意听取任何有关改进的批评和建议。

    # Turn Based Battle Simulator

# Player and computer take turns to attack each other with different moves
# until one is defeated.

import random


def main():
    """Main function that will welcome the player to the game."""

    print("\tWelcome to Battle Sim! This is a turn based combat simulator where")
    print("\tthere can only be one winner.")

    print("\nHow to play.\n\nPlayers take turn to choose a move. Moves can either deal moderate damage")
    print("with a low range, deal high damage but over a wide")
    print("range, or they can heal. (Note: Moves can miss, including Heal!)")

    print("\nEach player starts with 100 health, and the first")
    print("player to reduce their opponent to 0 is the winner.")

    print("\nThat's it! Good luck")

    play_again = True

    # Set up the play again loop
    while play_again:
        winner = None
        player_health = 100
        computer_health = 100

        # determine whose turn it is
        turn = random.randint(1,2) # heads or tails
        if turn == 1:
            player_turn = True
            computer_turn = False
            print("\nPlayer will go first.")
        else:
            player_turn = False
            computer_turn = True
            print("\nComputer will go first.")


        print("\nPlayer health: ", player_health, "Computer health: ", computer_health)

        # set up the main game loop
        while (player_health != 0 or computer_health != 0):

            heal_up = False # determine if heal has been used by the player. Resets false each loop.
            miss = False # determine if the chosen move will miss.

            # create a dictionary of the possible moves and randomly select the damage it does when selected
            moves = {"Punch": random.randint(18, 25),
                     "Mega Punch": random.randint(10, 35),
                     "Heal": random.randint(20, 25)}

            if player_turn:
                print("\nPlease select a move:\n1. Punch (Deal damage between 18-25)\n2. Mega Punch (Deal damage between 10-35)\n3. Heal (Restore between 20-25 health)\n")

                player_move = input("> ").lower()

                move_miss = random.randint(1,5) # 20% of missing
                if move_miss == 1:
                    miss = True
                else:
                    miss = False

                if miss:
                    player_move = 0 # player misses and deals no damage
                    print("You missed!")
                else:
                    if player_move in ("1", "punch"):
                        player_move = moves["Punch"]
                        print("\nYou used Punch. It dealt ", player_move, " damage.")
                    elif player_move in ("2", "mega punch"):
                        player_move = moves["Mega Punch"]
                        print("\nYou used Mega Punch. It dealt ", player_move, " damage.")
                    elif player_move in ("3", "heal"):
                        heal_up = True # heal activated
                        player_move = moves["Heal"]
                        print("\nYou used Heal. It healed for ", player_move, " health.")
                    else:
                        print("\nThat is not a valid move. Please try again.")
                        continue

            else: # computer turn

                move_miss = random.randint(1,5)
                if move_miss == 1:
                    miss = True
                else:
                    miss = False

                if miss:
                    computer_move = 0 # the computer misses and deals no damage
                    print("The computer missed!")
                else:
                    if computer_health > 30: 
                        if player_health > 75:
                            computer_move = moves["Punch"]
                            print("\nThe computer used Punch. It dealt ", computer_move, " damage.")
                        elif player_health > 35 and player_health <= 75: # computer decides whether to go big or play it safe
                            imoves = ["Punch", "Mega Punch"]
                            imoves = random.choice(imoves)
                            computer_move = moves[imoves]
                            print("\nThe computer used ", imoves, ". It dealt ", computer_move, " damage.")
                        elif player_health <= 35:
                            computer_move = moves["Mega Punch"] # FINISH HIM!
                            print("\nThe computer used Mega Punch. It dealt ", computer_move, " damage.")                       
                    else: # if the computer has less than 30 health, there is a 50% chance they will heal
                        heal_or_fight = random.randint(1,2) 
                        if heal_or_fight == 1:
                            heal_up = True
                            computer_move = moves["Heal"]
                            print("\nThe computer used Heal. It healed for ", computer_move, " health.")
                        else:
                            if player_health > 75:
                                computer_move = moves["Punch"]
                                print("\nThe computer used Punch. It dealt ", computer_move, " damage.")
                            elif player_health > 35 and player_health <= 75:
                                imoves = ["Punch", "Mega Punch"]
                                imoves = random.choice(imoves)
                                computer_move = moves[imoves]
                                print("\nThe computer used ", imoves, ". It dealt ", computer_move, " damage.")
                            elif player_health <= 35:
                                computer_move = moves["Mega Punch"] # FINISH HIM!
                                print("\nThe computer used Mega Punch. It dealt ", computer_move, " damage.")

            if heal_up:
                if player_turn:
                    player_health += player_move
                    if player_health > 100:
                        player_health = 100 # cap max health at 100. No over healing!
                else:
                    computer_health += computer_move
                    if computer_health > 100:
                        computer_health = 100
            else:
                if player_turn:
                    computer_health -= player_move
                    if computer_health < 0:
                        computer_health = 0 # cap minimum health at 0
                        winner = "Player"
                        break
                else:
                    player_health -= computer_move
                    if player_health < 0:
                        player_health = 0
                        winner = "Computer"
                        break

            print("\nPlayer health: ", player_health, "Computer health: ", computer_health)

            # switch turns
            player_turn = not player_turn
            computer_turn = not computer_turn

        # once main game while loop breaks, determine winner and congratulate

        if winner == "Player":
            print("\nPlayer health: ", player_health, "Computer health: ", computer_health)
            print("\nCongratulations! You have won. You're an animal!!")
        else:
            print("\nPlayer health: ", player_health, "Computer health: ", computer_health)
            print("\nSorry, but your opponent wiped the floor with you. Better luck next time.")

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

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

main()


#1 楼

样式

您总体上对代码进行了很好的样式设置,我只提供了一些小技巧,例如。


首先,运行main时,您需要在if __name__ == "__main__":块下运行它。有关更多信息,请参见此Stack Overflow答案。

代码文件顶部的注释应为文档字符串。它应类似于以下示例,并带有文件及其内容的描述。

"""
filename.py

Put a description of your file here.
"""



设计

您的设计不如您的编码风格好,因此,我将在此处对可以改进的地方进行更深入的介绍。



main的顶部一行上有很多print语句。我建议定义一个函数来轻松打印很多行而无需重复print语句。

def print_lines(*lines):
    """
    A helpful function for printing many
    separate strings on separate lines.
    """
    print("\n".join([line for line in lines]))


# EXAMPLE USAGE
print_lines(
    "Hello.",
    "Goodbye"
)




您当前的设计使用变量来管理不同的内容有关玩家和敌人的统计信息和属性将请求面向对象编程。我建议设置类似这样的方法,例如使用Characterdo_damage之类的方法创建一个take_damage类。使用字典获取某些输入,而不是创建if / elif / else链。这是一个示例。
最后,除了减少输入之外,我建议从用户输入中修剪无用的空格。这使用户的输入更加宽容。

无论如何,这就是我能想到的。如果您还有其他要我讲的内容,请在评论中提及,然后我会做的。希望对您有所帮助!

评论


\ $ \ begingroup \ $
@EthanBierlein健康:int在构造函数参数中有什么作用?我在Python 3.4.2上进行了尝试,虽然没有语法错误,但似乎没有做任何明显的事情。
\ $ \ endgroup \ $
– Kroltan
2015年6月19日在23:47



\ $ \ begingroup \ $
@Kroltan称为功能注释。它们允许您声明参数类型和函数的返回类型。例如:def power(a:float,b:float)-> float:返回a ** b
\ $ \ endgroup \ $
– Ethan Bierlein
2015年6月19日在23:57



\ $ \ begingroup \ $
@EthanBierlein有趣,不知道!但这并不能强制类型,对吗?
\ $ \ endgroup \ $
– Kroltan
15年6月19日在23:59

\ $ \ begingroup \ $
@Kroltan但是可以。如果您尝试输入错误的类型,则会引发TypeError。
\ $ \ endgroup \ $
– Ethan Bierlein
2015年6月20日0:00在

\ $ \ begingroup \ $
@Kroltan不,它不强制类型。您必须为此使用一个库。 Python 3.5将提供这样的库。参见PEP 484。
\ $ \ endgroup \ $
–约书亚
2015年6月20日在12:04



#2 楼

str.format

在Python的这些年中,连接字符串和变量的方式主要有两种。现在我们有了新的格式化方式。
我们将在示例中使用以下常量。

>>> a = 'You'
>>> b = 'Mega Punch'
>>> c = 50


第一种方式

>>> a + ' used ' + b + '. It dealt ' + str(c) + ' damage.'
'You used Mega Punch. It dealt 50 damage.'


这很烦人,如果a或b更改为int则不安全。我没有使用,运算符,因为如果将其分配给变量,它将产生一个元组。

第二种方法

>>> '%s used %s. It dealt %s damage.' % (a, b, c)
'You used Mega Punch. It dealt 50 damage.'


这与新的.format方法非常相似。但是,对此有一些反对意见,如其文档中所述:


此处描述的格式化操作表现出各种古怪,导致许多常见错误(例如无法正确显示元组和字典)。使用更新的str.format()接口有助于避免这些错误,并提供一种通常更强大,灵活和可扩展的文本格式设置方法。


str.format方法

>>> '{} used {}. It dealt {} damage.'.format(a, b, c)
'You used Mega Punch. It dealt 50 damage.'
>>> '{1} used {0}. It dealt {2} damage.'.format(a, b, c)
'Mega Punch used You. It dealt 50 damage.'
>>> '{0} used {1}. {0} dealt {2} damage.'.format(a, b, c)
'You used Mega Punch. You dealt 50 damage.'
#Every console app that makes a UI needs this!
>>> '{}{:>15}'.format('Pika', '23/100')
'Pika         23/100'


这只是演示使用str.format方法的几种方法。它还允许您更改输入变量的类型,显示的小数位数和操作列表。但是,最重要的只是动摇!

关于***运算符。

关于这些运算符有很多问题。而且它们的文档还很空缺。

>>> a = random.randint(1, 9)
>>> a
9
>>> a
9
# It didn't change? That's 'cause you are not calling the function,
# you're just asking for the same output again. So if we could...
>>> l = [1, 9]
>>> random.randint(l)
TypeError: randint() takes exactly 3 arguments (2 given)
# And this is why we have the `*` operator
>>> random.randint(*l)
4
>>> random.randint(*l)
2


但是我建议不要使用它。正如您将想到的一样:

def print_lines(*lines):
    print("\n".join([line for line in lines]))
# This is confusing. And `print` is a function in python3!
# If we ignore how good print is we get
def print_lines(*lines):
    print('\n'.join(lines))

# But how do we use it?
print_lines('hello', 'world')
print_lines(*['hello', 'world'])

# "There should be one-- and preferably only one --obvious way to do it."
print('hello', 'world', sep='\n')
print(['hello', 'world'], sep='\n')


打印现在是一种功能!引用来自Python的禅宗。

列表理解

我稍后在Class示例中使用它,并禁止其他人使用它。它们使您可以减少编写的代码量。您可以简单地更改它们,使其成为生成器。生成器非常适合处理大量数据,因为它们仅在需要时才将信息存储到内存中。

# You have a list of strings, and you want them to be all lowercase.
>>> lst = [ ... ]
>>> lst2 = []
>>> for i in lst:
        lst2.append(i.lower())
# That's a lot of writing for such a simple task.
# And so we will use list comprehension.
>>> lst3 = [i.lower() for i in lst]
# And they are the same.
>>> lst2 == lst3
True




您想重复使用代码。那是什么班级的大脑死亡反应!您的代码实现的主要功能是错过,移动并检查其中一个口袋妖怪是否晕倒了。当我被介绍给班级时,我被告知要使用超级,继承和很多我苦苦挣扎的东西。因此,我将举一个简单的类制作示例的“小”例子。 (因为您没有使用过,我假设您不喜欢/了解/了解它们。)

moves={'Punch': [18, 25],
       'Mega Punch': [10, 35],
       'Heal': [-25, -20]
       }

moves_list=list(moves)
moves_list_lower=[move.lower() for move in moves_list]

move_names='\n'+'\n'.join(
    "{0}. {1} (Deal damage between '{2[0]}' - '{2[1]}')".format(
        i,
        move,
        moves[move]
    )
    for i, move in enumerate(moves_list)
)

class Pokemon:
    def __init__(self, title):
        self.title = title

    def select_move(self)
        move = input(move_names + '\n> ').lower()
        try:
            return moves_list[int(move)]
        except ValueError:
            return moves_list[moves_list_lower.index(move)]
        except IndexError:
            print('That is not a valid move. Please try again.')

    def use_move(self, other, move):
        # 20% of missing
        if random.randint(1,5):
            print('{} missed!'.format(self.title.capitalize()))
        else:
            # Works as shown earlier.
            magnitude = random.randint(*moves[move])
            if moves[move][0] < 0:
                # A simple self.health += magnitude
                self.heal(magnitude)
                desc = 'healed for {} health.'
            else:
                # A simple self.health -= magnitude
                other.deal(magnitude)
                desc = 'dealt {} damage.'
            print(('{} used {}. It' + desc).format(
                   self.title.capitalize(),
                   move,
                   magnitude
                   ))




全局名称空间中的所有动作信息。


我们保留了简单的动作字典,因为它存储了我们需要的所有信息。

moves_list是字典中所有键的副本,因此我们可以更轻松地建立索引。

moves_list_lowermoves_list的小写副本。这样我们就可以使用它来查看此人是否输入了有效的举动。

move_names将在每个玩家回合开始时输出与打印声明大致相同的内容。但是,由于字典的工作方式,每次加载游戏时它都会改变。您可以对moves_list进行排序,以便在要“修复”此问题时将其修复。它还输出治疗效果,作为负面伤害。我相信您可以找到解决此问题的方法。

但是所有这些都应该像@EthanBierlein所说的那样用if __name__ == "__main__":包裹。在该程序中,因为它只是向您展示如何实现它。并允许您自己思考。我个人讨厌“学习课程,这是__init__的工作原理”。
我还使用了tryexcept语句。我不知道它是否功能齐全,但是它向您展示了如何消除混乱。有关这些“处理异常”的更多信息。
如果我要继续制作该程序,我将亲自使用继承并使用方法重写来使它成为可能,以便计算机对select_move有不同的使用方式。
如果您想知道什么是样式Python的最佳方法,那就是PEP8和PEP257。而不是一团糟。我对此进行了重新编写,并希望它与以前的版本一样好或更好。如果不是,请还原它。 -作者。