学习 Python 并借助 AI 伙伴构建游戏程序

一个基于生成式 AI 的助手,它可以帮助您构建小型项目(如文字游戏)并从中学习编程。


Amazon Q
Python
教程
亚马逊云科技
Olawale Olaleye
难度
100 - 初级
时间
20 分钟
前提条件

海外区域: 注册 / 登录 亚马逊云科技

上次更新时间
2024 年 6 月 13 日
相关产品

让我们来构建一个简单的文字游戏,从而练习和学习 Python。为了跟随教程指导,您需要一个带有 Amazon Q 开发者版插件的集成开发环境。请按照以下步骤下载并安装该插件。

您从 Amazon Q 获取的建议可能与本教程存在差异,但您可以向 Amazon Q 提供自己的反馈,并获得相似或更好的结果。在任何步骤中,如果您对任何不明确的内容存在疑问,您都可以要求 Amazon Q 为您提供更详细的信息。


找到合适的项目

首先,创建一个包含空的 game.py 文件的新目录。在设置中,打开了集成开发环境,并在编辑器的一侧打开了 Amazon Q 聊天窗口。

在 Amazon Q 聊天窗口中,询问一些想法:

告诉我  5 个可以用 Python 制作的简单文字游戏。
带有 Amazon Q 聊天窗口的集成开发环境和一个空的 Python 项目

在聊天窗口中,得到了诸如“猜数字”、“上吊的人”以及“文字冒险”等选项。从尝试一个简单的游戏开始,比如“石头、剪刀、布”。因此,在聊天窗口中输入了下一个指令。

给我一个“石头、剪刀、布”游戏的起始 Python 代码。

将 Amazon Q 建议的代码复制到编辑器中(在代码后面有一个“在光标处插入”的按钮),并保存。

import random

def get_choices():
    player_choice = input("Enter your choice (rock, paper, scissors): ")
    player_choice = player_choice.lower()
    options = ["rock", "paper", "scissors"]
    computer_choice = random.choice(options)
    choices = {"player": player_choice, "computer": computer_choice}
    return choices

def check_win(player, computer):
    print(f"You chose {player}, computer chose {computer}")
    if player == computer:
        return "It's a tie!"
    elif player == "rock":
        if computer == "scissors":
            return "Rock smashes scissors! You win!"
        else:
            return "Paper covers rock! You lose."
    elif player == "paper":
        if computer == "rock":
            return "Paper covers rock! You win!"
        else:
            return "Scissors cuts paper! You lose."
    elif player == "scissors":
        if computer == "paper":
            return "Scissors cuts paper! You win!"
        else:
            return "Rock smashes scissors! You lose."

choices = get_choices()
result = check_win(choices["player"], choices["computer"])
print(result)

Amazon Q 在代码后面提供了代码的工作原理解释:

以下是代码的工作原理:

  1. get_choices ( ) 函数提示用户输入他们的选择(石头、剪刀或布),并随机挑选出电脑的选择。然后它返回一个包含玩家和电脑选择的字典。
  2. check_win ( ) 函数将玩家和电脑的选择作为参数。它首先打印输出双方所做的选择,接着检查平局条件。如果不是平局,它会根据“石头、剪刀、布”的规则检查玩家的选择和电脑的选择来确定胜者。然后它返回相应的结果信息。
  3. 通过调用 get_choices ( ) 函数来创建 choices 字典。
  4. result 变量存储 check_win ( ) 函数经由玩家和电脑选择参数传入而返回的结果信息。
  5. 最后,将结果信息打印输出到控制台。

这是一个“石头、剪刀、布”游戏的基本实现。您可以通过添加记录分数、多轮游戏或更友好的用户界面等功能来进一步增强它。

阅读这段描述并运行代码,看看会发生什么。

python game.py

Enter your choice (rock, paper, scissors): rock
You chose rock, computer chose scissors
Rock smashes scissors! You win!

游戏雏形初现,但它还有很多可以改进的地方!例如,游戏程序在第一轮结束后就终止了。

在 Amazon Q 的聊天窗口中,要求在第一轮结束后继续运行游戏。还建议重构代码,添加一个处理游戏循环的 play_game 函数。

创建一个 play_game 函数,该函数将循环执行直至玩家输入 "bye" 为止。

采纳 Amazon Q 的所有建议并逐一实现了它们。这里不再逐一复制所有信息,但您可以重现这些步骤并获得类似的答案。以下是这些更改后的完整代码。

import random

def get_choices():
    player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ")
    player_choice = player_choice.lower()
    if player_choice == "bye":
        return {"player": "bye"}
    options = ["rock", "paper", "scissors"]
    computer_choice = random.choice(options)
    choices = {"player": player_choice, "computer": computer_choice}
    return choices

def check_win(player, computer):
    print(f"You chose {player}, computer chose {computer}")
    if player == computer:
        return "It's a tie!"
    elif player == "rock":
        if computer == "scissors":
            return "Rock smashes scissors! You win!"
        else:
            return "Paper covers rock! You lose."
    elif player == "paper":
        if computer == "rock":
            return "Paper covers rock! You win!"
        else:
            return "Scissors cuts paper! You lose."
    elif player == "scissors":
        if computer == "paper":
            return "Scissors cuts paper! You win!"
        else:
            return "Rock smashes scissors! You lose."

def play_game():
    while True:
        choices = get_choices()
        if choices["player"] == "bye":
            print("Thanks for playing!")
            break
        result = check_win(choices["player"], choices["computer"])
        print(result)

play_game()

将编辑器中的代码替换为聊天窗口中的新版本,保存并再次运行。如此一来,现在就可以轻松进行多轮游戏了!

Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose paper
Paper covers rock! You lose.
Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose rock
It's a tie!
Enter your choice (rock, paper, scissors) or 'bye' to quit: bye
Thanks for playing!

重构代码

让我门尝试避免在代码中多次重复编写这三个可能的选项(石头、剪刀、布),将它们放进一个列表中。首先,向 Amazon Q 提问:

如何在 Python 中创建一个常量?

从 Amazon Q 的答案中了解到惯例做法是使用大写字母。

重构代码,并将三个选项(石头、剪刀、布)放入一个全局列表中。这个列表是常量列表,因此使用大写字母为其命名,如 CHOICES。

从聊天窗口中看到了重构后的代码。代码添加了一个额外的检查(使用递归)来确保玩家的选择是有效的选项。

CHOICES = ["rock", "paper", "scissors"]

def get_choices():
    player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ")
    player_choice = player_choice.lower()
    if player_choice == "bye":
        return {"player": "bye"}
    if player_choice not in CHOICES:
        print("Invalid choice. Please try again.")
        return get_choices()
    computer_choice = random.choice(CHOICES)
    choices = {"player": player_choice, "computer": computer_choice}
    return choices

在这种情况下,递归不是最优选择。要求 Amazon Q 对代码进行简化:

将 get_choices 函数中的递归替换为循环。

在 Amazon Q 的回应中,递归调用已经被一个 while True 循环所替代。

def get_choices():
    while True:
        player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ")
        player_choice = player_choice.lower()
        if player_choice == "bye":
            return {"player": "bye"}
        if player_choice in CHOICES:
            computer_choice = random.choice(CHOICES)
            choices = {"player": player_choice, "computer": computer_choice}
            return choices
        else:
            print("Invalid choice. Please try again.")

现在改进检查哪方获胜的部分。它包含许多 if / then 条件语句。对于游戏而言,通常需要找到一种数据结构来包含所有规则。这样可以在游戏的多个部分应用这些规则,而无需重复相同的代码。

以下是指令:

对于检查哪方获胜的部分,更新代码以使用 BEATS 字典,该字典对于任何选择都将返回输给该选择的选项。重构代码以从 BEATS 字典中计算 CHOICES。然后,将 check_win 函数重命名为 "who_wins",并使其返回 "player"(玩家)、"computer"(电脑)或 "tie"(平局)。
BEATS = {
    "rock": "scissors",
    "paper": "rock",
    "scissors": "paper"
}

CHOICES = list(BEATS.keys())

. . .

def who_wins(player, computer):
    print(f"You chose {player}, computer chose {computer}")
    if player == computer:
        return "tie"
    elif BEATS[player] == computer:
        return "player"
    else:
        return "computer"

由于 who_wins 函数输出的简化,该函数现在仅返回一个单词(player、computer 或 tie),因此 play_game 函数现在负责文本的格式设置和显示。

def play_game():
    while True:
        choices = get_choices()
        if choices["player"] == "bye":
            print("Thanks for playing!")
            break
        result = who_wins(choices["player"], choices["computer"])
        if result == "player":
            print("You win!")
        elif result == "computer":
            print("You lose.")
        else:
            print("It's a tie!")

此外,避免将玩家和电脑的选择混合在同一个函数 (get_choices) 中。玩家从终端进行输入,而电脑使用某种策略(目前是随机性)来做出选择。这是完全不同的两个过程,因此要求将该函数进行拆分:

将 get_choices 函数拆分为两个函数,一个用于玩家,一个用于电脑。

最终的代码包含了 get_player_choice 和 get_computer_choice 两个函数。以下是修改后的完整代码。

import random

BEATS = {
    "rock": "scissors",
    "paper": "rock",
    "scissors": "paper"
}

CHOICES = list(BEATS.keys())

def get_player_choice():
    while True:
        player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ")
        player_choice = player_choice.lower()
        if player_choice == "bye":
            return "bye"
        if player_choice in CHOICES:
            return player_choice
        else:
            print("Invalid choice. Please try again.")

def get_computer_choice():
    return random.choice(CHOICES)

def who_wins(player, computer):
    print(f"You chose {player}, computer chose {computer}")
    if player == computer:
        return "tie"
    elif BEATS[player] == computer:
        return "player"
    else:
        return "computer"

def play_game():
    while True:
        player_choice = get_player_choice()
        if player_choice == "bye":
            print("Thanks for playing!")
            break
        computer_choice = get_computer_choice()
        result = who_wins(player_choice, computer_choice)
        if result == "player":
            print("You win!")
        elif result == "computer":
            print("You lose.")
        else:
            print("It's a tie!")

play_game()

get_player_choice 函数还可以进一步改进。例如,"bye" 被重复了两次。在编辑器中选中这个函数,并从上下文菜单中选择 Amazon Q 和 Optimize。可以使用相同的方法来解释、修复或重构代码,或者使用自定义提示与所选代码进行交互以执行不同的操作,例如要求以特定方式更改代码。

根据建议,将函数替换为这个优化后的版本:

def get_player_choice():
    while True:
        player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ").lower()
        if player_choice == "bye" or player_choice in CHOICES:
            return player_choice
        print("Invalid choice. Please try again.")

跟踪得分

在改进电脑策略之前,让我们先跟踪玩家的得分,这样在一场长时间的游戏结束后,我们就可以知道谁获胜最多。以下是指令:

更新代码以在 play_game 函数内存储玩家和电脑的获胜次数。在每一轮结束时打印输出得分。最后,打印输出谁赢得更多。

为了避免在响应中使用全局变量,指定在 play_game 函数内存储得分。即使全局变量在小型程序中也许是可接受的,但最好避免使用它们,因为当应用程序增长并变得更加复杂时,它们可能会引发问题。

def play_game():
    player_wins = 0
    computer_wins = 0
    . . .
    
        if result == "player":
            print("You win!")
            player_wins += 1
        elif result == "computer":
            print("You lose.")
            computer_wins += 1
        . . .
        print(f"Score: Player {player_wins} - Computer {computer_wins}")

    if player_wins > computer_wins:
        print("You won more games!")
    elif computer_wins > player_wins:
        print("Computer won more games.")
    else:
        print("It's a tie overall.")

做一下快速测试来查看这是如何工作的。

Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose scissors
You win!
Score: Player 1 - 0 Computer
Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose scissors
You win!
Score: Player 2 - 0 Computer
Enter your choice (rock, paper, scissors) or 'bye' to quit: bye
Thanks for playing!
You won more games!

既然我们已经按照预期进行分数管理,现在是时候改进电脑策略了。


改进电脑策略

与其完全随机地做出选择,不如让电脑通过玩家之前的选择去理解他们的游戏玩法。为此,需要创建一个数据结构,当电脑预测到玩家的选择时,返回最佳对策。

计算出与 BEATS 字典相反的字典,并将其命名为 BEATEN_BY。
BEATEN_BY = {value: key for key, value in BEATS.items()}

现在,尝试通过玩家历史记录来改进电脑的选择方式:

通过以下更改来优化电脑的策略。在 get_computer_choice 函数中,输入一个包含玩家之前所有选择的列表。然后,从列表中随机选取一个元素,并返回能够打败该选择的选项(即 BEATEN_BY[random element] 的值)。在电脑做出选择后,更新这个列表。如果列表为空,则返回随机选择。

必须在这里非常清楚地说明如何使用这些数据结构,因为如果缺少上下文说明,BEATS 和 BEATEN_BY 字典可能会令人困惑。以下是建议的代码:

def get_computer_choice(player_choices):
    if player_choices:
        previous_choice = random.choice(player_choices)
        return BEATEN_BY[previous_choice]
    else:
        return random.choice(CHOICES)

def play_game():
    . . .
    player_choices = []

    while True:
        player_choice = get_player_choice()
        . . .
        computer_choice = get_computer_choice(player_choices)
        . . .
        player_choices.append(player_choice)

这个策略比随机性策略要好,但对于长时间的游戏,它还可以改进。事实上,最好不要依赖过于陈旧的历史记录。

优化电脑的策略,使其仅使用玩家历史记录中的最新 n 个条目,其中 n 等于 10。将这个变量 n 命名为 MEMORY_LENGTH。

以下是更新后的 get_computer_choice 函数和 MEMORY_LENGTH 常量。

MEMORY_LENGTH = 10

. . .

def get_computer_choice(player_choices):
    if len(player_choices) > MEMORY_LENGTH:
        recent_choices = player_choices[-MEMORY_LENGTH:]
    else:
        recent_choices = player_choices

    if recent_choices:
        previous_choice = random.choice(recent_choices)
        return BEATEN_BY[previous_choice]
    else:
        return random.choice(CHOICES)

我们快要完成了。get_computer_choice 函数还可以进一步改进。例如,在 Python 中,即使数组中的元素少于所请求的数量,也可以进行切片操作。我选中这个函数,并使用上下文菜单,让 Amazon Q 来优化代码。

以下是优化后的函数:

def get_computer_choice(player_choices):
    recent_choices = player_choices[-MEMORY_LENGTH:] if player_choices else []

    if recent_choices:
        previous_choice = random.choice(recent_choices)
        return BEATEN_BY[previous_choice]
    else:
        return random.choice(CHOICES)

这个版本的函数更简洁易懂。通过这些策略的改进,电脑无疑成为了一个更出色的玩家。

Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose scissors
You win!
Score: Player 1 - Computer 0
Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose paper
You lose.
Score: Player 1 - Computer 1
Enter your choice (rock, paper, scissors) or 'bye' to quit: rock
You chose rock, computer chose paper
You lose.
Score: Player 1 - Computer 2
Enter your choice (rock, paper, scissors) or 'bye' to quit: bye
Thanks for playing!
Computer won more games.

收尾工作以及使用类

让我们请求进行最后一次更新,以清理程序的启动方式。

仅在直接运行此程序而非作为模块导入时,才运行 play_game 函数。

这会将程序的最终部分更改为使用一个常见的 Python 惯例。

if __name__ == "__main__":
    play_game()

当前的游戏实现似乎不错,但是否可以将不同的游戏功能更紧密地结合在一起?

import random

BEATS = {
    "rock": "scissors",
    "paper": "rock",
    "scissors": "paper"
}

BEATEN_BY = {value: key for key, value in BEATS.items()}

CHOICES = list(BEATS.keys())

MEMORY_LENGTH = 10

def get_player_choice():
    while True:
        player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ").lower()
        if player_choice == "bye" or player_choice in CHOICES:
            return player_choice
        print("Invalid choice. Please try again.")

def get_computer_choice(player_choices):
    if len(player_choices) > MEMORY_LENGTH:
        recent_choices = player_choices[-MEMORY_LENGTH:]
    else:
        recent_choices = player_choices

    if recent_choices:
        previous_choice = random.choice(recent_choices)
        return BEATEN_BY[previous_choice]
    else:
        return random.choice(CHOICES)

def who_wins(player, computer):
    print(f"You chose {player}, computer chose {computer}")
    if player == computer:
        return "tie"
    elif BEATS[player] == computer:
        return "player"
    else:
        return "computer"

def play_game():
    player_wins = 0
    computer_wins = 0
    player_choices = []

    while True:
        player_choice = get_player_choice()
        if player_choice == "bye":
            print("Thanks for playing!")
            break
        computer_choice = get_computer_choice(player_choices)
        result = who_wins(player_choice, computer_choice)
        if result == "player":
            print("You win!")
            player_wins += 1
        elif result == "computer":
            print("You lose.")
            computer_wins += 1
        else:
            print("It's a tie!")

        player_choices.append(player_choice)
        print(f"Score: Player {player_wins} - Computer {computer_wins}")

    if player_wins > computer_wins:
        print("You won more games!")
    elif computer_wins > player_wins:
        print("Computer won more games.")
    else:
        print("It's a tie overall.")

if __name__ == "__main__":
    play_game()

让我们尝试使用面向对象的方法。整个游戏程序可以嵌入到一个类中。然后,每个游戏程序都是该类的一个实例。以下是请求样本:

用一个实现相同功能的 RockPaperScissorsGame 类来替换 BEATS、BEATEN_BY 和 CHOICES 这些数据结构。这个类应当有一个内置的 BEATS 结构,并据此计算所有其他数据。

以下是最终代码,供您参考。这个结果可能不够完美,但比之前有所改进。如果您一直跟着做,您可能会得到相似但不完全相同的代码。您可以继续向 Amazon Q 提问,并给出添加更多功能或重构代码的指令。

import random

class RockPaperScissorsGame:
    def __init__(self):
        self.BEATS = {
            "rock": "scissors",
            "paper": "rock",
            "scissors": "paper"
        }
        self.BEATEN_BY = {value: key for key, value in self.BEATS.items()}
        self.CHOICES = list(self.BEATS.keys())

    def get_player_choice(self):
        while True:
            player_choice = input("Enter your choice (rock, paper, scissors) or 'bye' to quit: ").lower()
            if player_choice == "bye" or player_choice in self.CHOICES:
                return player_choice
            print("Invalid choice. Please try again.")

    def get_computer_choice(self, player_choices, memory_length=10):
        if len(player_choices) > memory_length:
            recent_choices = player_choices[-memory_length:]
        else:
            recent_choices = player_choices

        if recent_choices:
            previous_choice = random.choice(recent_choices)
            return self.BEATEN_BY[previous_choice]
        else:
            return random.choice(self.CHOICES)

    def who_wins(self, player, computer):
        print(f"You chose {player}, computer chose {computer}")
        if player == computer:
            return "tie"
        elif self.BEATS[player] == computer:
            return "player"
        else:
            return "computer"

    def play_game(self):
        player_wins = 0
        computer_wins = 0
        player_choices = []

        while True:
            player_choice = self.get_player_choice()
            if player_choice == "bye":
                print("Thanks for playing!")
                break
            computer_choice = self.get_computer_choice(player_choices)
            result = self.who_wins(player_choice, computer_choice)
            if result == "player":
                print("You win!")
                player_wins += 1
            elif result == "computer":
                print("You lose.")
                computer_wins += 1
            else:
                print("It's a tie!")

            player_choices.append(player_choice)
            print(f"Score: Player {player_wins} - Computer {computer_wins}")

        if player_wins > computer_wins:
            print("You won more games!")
        elif computer_wins > player_wins:
            print("Computer won more games.")
        else:
            print("It's a tie overall.")

if __name__ == "__main__":
    game = RockPaperScissorsGame()
    game.play_game()

如果您喜欢本节关于 AI 辅助编程的内容,请别忘记尝试一下 Amazon Q 开发者版