你相信吗?用ChatGPT写井字棋游戏仅需几分钟

简介: 你相信吗?用ChatGPT写井字棋游戏仅需几分钟

井字棋

我们先实现一个最基本的使用控制台交互的井字棋游戏。

为了保持代码整洁,方便后续扩展,我们使用类Board来实现棋盘。除了常规的初始化方法__init__和字符串方法__str__,我们还要判断游戏的胜负、棋子位置的合理性。在main中,我们在while循环中实现两个玩家的交替下棋,直到一方胜利或棋盘满了为止。

代码整体比较简单,只是在判断胜利时需要处理好多个条件。

class Board:
    def __init__(self, size=3):
        self.board = [['_' for j in range(size)] for i in range(size)]
        self.size = size

    def __str__(self):
        res = ""
        for row in self.board:
            temp_row = ""
            for col in row:
                temp_row = temp_row + col + '\t'
            res += str(temp_row) + "\n"
        return res

    def display(self):
        print(self)

    def can_set(self, row, col):
        return 0 <= row < self.size and 0 <= col < self.size and self.board[row][col] == '_'

    def set_board(self, row, col, mark):
        if self.can_set(row, col):
            self.board[row][col] = mark
        else:
            print("Invalid input...,")

    def check_win(self):
        for row in self.board:
            if all(x == 'X' for x in row):
                return "Player 1 wins"
            elif all(x == 'O' for x in row):
                return "Player 2 wins"

        for col in range(self.size):
            if all(self.board[row][col] == 'X' for row in range(self.size)):
                return "Player 1 wins"
            elif all(self.board[row][col] == 'O' for row in range(self.size)):
                return "Player 2 wins"

        # Diagonal
        if all(self.board[i][i] == 'X' for i in range(self.size)) or all(self.board[i][self.size-1-i] == 'X' for i in range(self.size)):
            return "Player 1 wins"
        elif all(self.board[i][i] == 'O' for i in range(self.size)) or all(self.board[i][self.size-1-i] == 'O' for i in range(self.size)):
            return "Player 2 wins"

        return "No one wins"

    def is_full(self):
        return not any(self.board[i][j] == '_' for i in range(self.size) for j in range(self.size))


if __name__ == '__main__':
    size = int(input("Please input the size of the board: "))
    board = Board(size)
    board.display()
    # player 1:X  player 2:  O
    marks = ['X', 'O']
    player = 0
    while not board.is_full() and board.check_win() == "No one wins":
        index = input(f"Please player {player+1} input coordinates (row, col): ")
        try:
            row, col = index.split(',')
            row, col = int(row)-1, int(col)-1
        except ValueError:
            print("Invalid input. Please input two integers separated by a comma.")
            continue
        if board.can_set(row, col):
            board.set_board(row, col, marks[player])
        else:
            print("This cell is already occupied. Please choose another one.")
            continue
        player = (player + 1) % 2
        board.display()

    print(board.check_win())


使用tkinter创建图形界面

在这个程序中,使用了tkinter模块来创建窗口和按钮。每个按钮都由Button类创建,并通过grid()方法来定位。当按钮被点击时,clicked()方法被调用,将其设置为当前玩家的标记,并切换到下一个玩家。每次下棋后,程序会检查游戏是否已结束。如果游戏结束,程序会调用show_winner()方法来显示获胜者或平局信息,并禁用所有按钮。

import tkinter as tk

class TicTacToeGUI:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Tic Tac Toe")

        # 创建9个按钮
        self.buttons = []
        for i in range(3):
            row = []
            for j in range(3):
                button = tk.Button(self.root, text="", font=("Helvetica", 24), width=5, height=2, command=lambda row=i, col=j: self.clicked(row, col))
                button.grid(row=i, column=j)
                row.append(button)
            self.buttons.append(row)

        self.current_player = "X"
        self.board = [
            ["-", "-", "-"],
            ["-", "-", "-"],
            ["-", "-", "-"]
        ]

    def clicked(self, row, col):
        """
        当一个按钮被点击时,将其设置为当前玩家的标记,并切换到下一个玩家。
        """
        if self.board[row][col] == "-":
            self.buttons[row][col].config(text=self.current_player)
            self.board[row][col] = self.current_player
            if self.current_player == "X":
                self.current_player = "O"
            else:
                self.current_player = "X"
            self.check_game_over()

    def check_game_over(self):
        """
        检查游戏是否已结束
        """
        for i in range(3):
            # 检查行
            if self.board[i][0] != "-" and self.board[i][0] == self.board[i][1] and self.board[i][1] == self.board[i][2]:
                self.show_winner(self.board[i][0])
                return
            # 检查列
            if self.board[0][i] != "-" and self.board[0][i] == self.board[1][i] and self.board[1][i] == self.board[2][i]:
                self.show_winner(self.board[0][i])
                return
        # 检查对角线
        if self.board[0][0] != "-" and self.board[0][0] == self.board[1][1] and self.board[1][1] == self.board[2][2]:
            self.show_winner(self.board[0][0])
            return
        if self.board[0][2] != "-" and self.board[0][2] == self.board[1][1] and self.board[1][1] == self.board[2][0]:
            self.show_winner(self.board[0][2])
            return
        # 检查是否有空格
        for row in self.board:
            for cell in row:
                if cell == "-":
                    return
        # 如果没有空格,平局
        self.show_winner("Tie")

    def show_winner(self, winner):
        """
        显示获胜者或平局信息,并禁用所有按钮。
        """
        if winner == "Tie":
            message = "It's a tie!"
        else:
            message = f"Player {winner} wins!"
        for row in self.buttons:
            for button in row:
                button.config(state="disabled")
        self.root.title(message)

    def start(self):
        """
        开始游戏。
        """
        self.root.mainloop()

# 运行游戏
game = TicTacToeGUI()
game.start()

人机对战版

这是一个井字游戏的 Python 代码,分别有三个类:BoardAIPlayerGame

Board

这个类代表了游戏的棋盘,有以下方法:

  • __init__(self, size=3):构造函数,初始化棋盘为给定大小的二维列表,初始值为 ‘_’。
  • __str__(self):返回当前棋盘的字符串表示形式。
  • display(self):打印当前棋盘的字符串表示形式。
  • can_set(self, row, col):判断给定位置能否放置棋子。
  • set_board(self, row, col, mark):将给定位置放置给定的标记(‘X’ 或 ‘O’)。
  • check_win(self):判断当前棋局是否已分出胜负,返回 “Player 1 wins”、“Player 2 wins” 或 “No one wins”。
  • is_full(self):判断当前棋盘是否已满。
  • copy(self):返回当前棋盘的副本。

AIPlayer

这个类代表了游戏中的 AI 玩家,有以下方法:

  • __init__(self, mark):构造函数,初始化 AI 玩家的标记(‘X’ 或 ‘O’)。
  • get_best_move(self, board):计算当前 AI 玩家应该下的最佳位置。
  • minimax(self, board, is_maximizing, alpha, beta):计算给定棋盘状态下当前玩家的最大(或最小)得分。

Game

这个类代表了游戏本身,有以下方法:

  • __init__(self, size=3, ai_mode=False):构造函数,初始化游戏的棋盘大小和是否启用 AI 模式。
  • start(self):开始游戏。
  • 在 start 方法中,游戏会循环进行,直到棋盘已满或有一方获胜。每次循环,根据当前玩家是否是 AI,分别提示玩家输入位置或计算 AI 玩家应该下的位置,然后更新棋盘,交换当前玩家。
class Board:
    def __init__(self, size=3):
        self.board = [['_' for j in range(size)] for i in range(size)]
        self.size = size

    def __str__(self):
        res = ""
        for row in self.board:
            temp_row = ""
            for col in row:
                temp_row = temp_row + col + '\t'
            res += str(temp_row) + "\n"
        return res

    def display(self):
        print(self)

    def can_set(self, row, col):
        return 0 <= row < self.size and 0 <= col < self.size and self.board[row][col] == '_'

    def set_board(self, row, col, mark):
        if self.can_set(row, col):
            self.board[row][col] = mark
        else:
            print("Invalid input...,")

    def check_win(self):
        for row in self.board:
            if all(x == 'X' for x in row):
                return "Player 1 wins"
            elif all(x == 'O' for x in row):
                return "Player 2 wins"

        for col in range(self.size):
            if all(self.board[row][col] == 'X' for row in range(self.size)):
                return "Player 1 wins"
            elif all(self.board[row][col] == 'O' for row in range(self.size)):
                return "Player 2 wins"

        # Diagonal
        if all(self.board[i][i] == 'X' for i in range(self.size)) or all(
                self.board[i][self.size - 1 - i] == 'X' for i in range(self.size)):
            return "Player 1 wins"
        elif all(self.board[i][i] == 'O' for i in range(self.size)) or all(
                self.board[i][self.size - 1 - i] == 'O' for i in range(self.size)):
            return "Player 2 wins"

        return "No one wins"

    def is_full(self):
        return not any(self.board[i][j] == '_' for i in range(self.size) for j in range(self.size))

    def copy(self):
        new_board = Board(self.size)
        for i in range(self.size):
            for j in range(self.size):
                new_board.board[i][j] = self.board[i][j]
        return new_board

class AIPlayer:
    def __init__(self, mark):
        self.mark = mark

    def get_best_move(self, board):
        best_score = -1000
        best_move = None

        for row in range(board.size):
            for col in range(board.size):
                if board.can_set(row, col):
                    board_copy = board.copy()
                    board_copy.set_board(row, col, self.mark)
                    score = self.minimax(board_copy, False, -1000, 1000)
                    if score > best_score:
                        best_score = score
                        best_move = (row, col)

        return best_move

    def minimax(self, board, is_maximizing, alpha, beta):
        result = board.check_win()
        if result == "Player 1 wins":
            return -1
        elif result == "Player 2 wins":
            return 1
        elif board.is_full():
            return 0

        if is_maximizing:
            best_score = -1000
            for row in range(board.size):
                for col in range(board.size):
                    if board.can_set(row, col):
                        board_copy = board.copy()
                        board_copy.set_board(row, col, 'O')
                        score = self.minimax(board_copy, False, alpha, beta)
                        best_score = max(best_score, score)
                        alpha = max(alpha, best_score)
                        if beta <= alpha:
                            break
            return best_score

        else:
            best_score = 1000
            for row in range(board.size):
                for col in range(board.size):
                    if board.can_set(row, col):
                        board_copy = board.copy()
                        board_copy.set_board(row, col, 'X')
                        score = self.minimax(board_copy, True, alpha, beta)
                        best_score = min(best_score, score)
                        beta = min(beta, best_score)
                        if beta <= alpha:
                            break
            return best_score


class Game:
    def __init__(self, size=3, ai_mode=False):
        self.board = Board(size)
        self.ai_mode = ai_mode
        self.player_marks = ['X', 'O']
        self.player_turn = 0

        if ai_mode:
            self.ai_player = AIPlayer(self.player_marks[1])

    def start(self):
        print("Starting the game...")
        self.board.display()

        while not self.board.is_full() and self.board.check_win() == "No one wins":
            current_player_mark = self.player_marks[self.player_turn]
            if self.player_turn == 1 and self.ai_mode:
                print("AI is thinking...")
                row, col = self.ai_player.get_best_move(self.board)
                print(f"AI placed {current_player_mark} at row {row + 1}, col {col + 1}")
                self.board.set_board(row, col, current_player_mark)
            else:
                index = input(f"Please player {self.player_turn + 1} input coordinates (row, col): ")
                try:
                    row, col = index.split(',')
                    row, col = int(row) - 1, int(col) - 1
                except ValueError:
                    print("Invalid input. Please input two integers separated by a comma.")
                    continue
                if not self.board.can_set(row, col):
                    print("This cell is already occupied. Please choose another one.")
                    continue
                self.board.set_board(row, col, current_player_mark)

            self.board.display()
            self.player_turn = (self.player_turn + 1) % 2

        print(self.board.check_win())


if __name__ == '__main__':
    game = Game(size=3, ai_mode=True)
    game.start()

说明

第二部分(人机对战)全部由ChatGPT生成(中间经过多次调整),第一部分的代码是ChatGPT在我的代码基础上优化后的结果。

对于简单的问题,ChatGPT通常能给出完美的回答。但对于复杂问题则相对差一些,需要多次修改。此外,ChatGPT无法保证内容的正确性,有时候会给出似是而非的误导性回答。值得一提的是,ChatGPT对代码的理解能力特别强,能很好地给自己的代码加注释(大概是因为代码比较规范,流程相对固定,比较容易学习)。

ChatGPT能提高写代码及其它文字的效率,可以用来

  • 注释代码
  • 写一段简单函数
  • 提供灵感(比如起标题)
  • 写格式比较固定的文字(邮件等)

但是,ChatGPT对事实类问题的回答比较离谱:

更多ChatGPT的案例可以看看:

ChatGPT评测观察之对话能力|语义理解较准,尚难以摆脱知识整合和逻辑推理困境 https://mp.weixin.qq.com/s/ZjZgMZIXiD966hcFua_gew


ChatGPT是一种生成式预训练transformer(generative pre-trained transformer, GPT),使用有监督学习和强化学习对GPT-3.5进行微调。在两种方法中,人类训练者都用于提高模型的性能。在有监督学习中,模型被提供了对话,训练者在其中扮演了用户和AI助手的双方角色。在强化学习步骤中,人类训练者首先对模型先前创建的响应进行排名。这些排名被用于创建“奖励模型”,…

此外,OpenAI继续收集来自ChatGPT用户的数据,这些数据可以用于进一步训练和微调ChatGPT。用户可以赞或踩他们从ChatGPT收到的响应;在赞或踩时,他们还可以填写一个文本字段以提供额外的反馈。

更多细节可以参考:

维基百科ChatGPT: https://en.wikipedia.org/wiki/ChatGPT

InstructGPT论文: Training language models to follow instructions with human feedback


最后提一下,井字棋的最优策略竟是先占角!

https://www.guokr.com/article/4754

相关文章
两句话,ChatGPT帮我写一个打飞机的游戏
两句话,ChatGPT帮我写一个打飞机的游戏
|
机器学习/深度学习 人工智能 算法
ChatGPT唤醒AI游戏?
ChatGPT唤醒AI游戏?
161 0
|
机器学习/深度学习 人工智能 自然语言处理
GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?(3)
GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?
254 0
|
机器学习/深度学习 人工智能 API
GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?(2)
GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?
112 0
|
机器学习/深度学习 人工智能 自然语言处理
GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?
GPT-4震撼发布:多模态大模型,直接升级ChatGPT、必应,开放API,游戏终结了?
165 0
|
人工智能 区块链
聊聊学习制作游戏的方法,以及最近大火的ChatGPT
先跟着入门课程把基础知识掌握好,把工具使用熟练,学习做游戏最重要的是动手做,尽可能完成每节课程后面的实践练习,只有做的多了,知识才能掌握的扎实,才能更快的入门。
171 0
|
开发者
ChatGPT能够教你学习游戏制作吗?
嗨!大家好,我是小蚂蚁。 下面的这张是我的一位学员在学员群里发的同 ChatGPT 对话的截图。 可以看到,ChatGPT 知道微信小游戏制作工具,知道它可以通过拖拽积木块儿的方式编写小游戏代码,甚至知道它的一些基础操作,以及它的优点和弊端。 如果单单只是这些,还不足以让人惊讶,因为毕竟这些信息也都是可以通过搜索查到的。但是当看到下面的具体实现问题的回答时,我还是被惊讶到了。
127 0
|
机器学习/深度学习 人工智能 自然语言处理
|
3月前
|
人工智能 自然语言处理 搜索推荐
chatgpt这么火,现在AI搜索引擎有哪些呢?
国外AI搜索引擎包括ChatGPT,擅长自然语言处理与内容生成;Google Bard,提供智能个性化搜索体验;Microsoft Bing集成GPT模型增强智能检索;Perplexity AI以简洁答案及文献引用著称;Neeva强调隐私保护与无广告服务。国内方面,天工AI支持多种功能如知识问答与代码编程;腾讯元宝基于混元模型助力内容创造与学习;360AI搜索以精准全面的信息搜索见长;秘塔AI专注提升写作质量和效率;开搜AI搜索提供个性化智能搜索服务。以上引擎均利用先进AI技术提升用户体验。更多详情参阅[AI搜索合集](zhangfeidezhu.com/?page_id=651)。
110 8
chatgpt这么火,现在AI搜索引擎有哪些呢?
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
HuggingGPT解析:使用 ChatGPT及HuggingFace上的族系解决AI问题
HuggingGPT是一个框架,它使用大型语言模型(如ChatGPT)作为控制器来管理和协调Hugging Face上的AI模型,以语言作为通用接口解决多模态和领域的复杂AI任务。
57 0
HuggingGPT解析:使用 ChatGPT及HuggingFace上的族系解决AI问题