【Python】利用tkinter开发AI对战井字棋游戏

简介: 【Python】利用tkinter开发AI对战井字棋游戏

1 前言


在学习tkinter时打算开发一款井字棋游戏,之前试过利用pygame开发【利用pygame开发井字棋博客】。但是这个项目没有嵌入AI智能对战,只能由两个玩家操作。正好借此机会利用tkinter开发对战界面,并嵌入AI对战。

游戏界面如下:



为了读者对游戏由更好的了解,这里放操作视频:

image.png

20220813_105943

为方便游玩,我利用pyinstaller打包了代码至exe文件可以让所有用户安装游玩!exe下载地址:软件下载

若仅仅想获取代码,本文的代码就是全部代码,可放心使用!


2 代码分模块介绍


2.1 导入需要的库


分别是tkinter 、random

from tkinter import *
import tkinter.messagebox as msq
import random


2.2 定义全局变量


这里定义了窗体大小,窗体标题以及九个可落子位置的序号和变量值。

def __init__(self, master=None):
        self.root = master  # 定义内部变量root
        self.root.title("井字棋")
        self.root.geometry('%dx%d' % (600, 400))  # 设置窗口大小
        self.panels = ["panel"]*10
        self.count = 0
        self.digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        self.mark = ""
        self.btn_text1 = StringVar()
        self.btn_text2 = StringVar()
        self.btn_text3 = StringVar()
        self.btn_text4 = StringVar()
        self.btn_text5 = StringVar()
        self.btn_text6 = StringVar()
        self.btn_text7 = StringVar()
        self.btn_text8 = StringVar()
        self.btn_text9 = StringVar()
        self.computerLetter = "O"
        self.createPage()


2.3 定义玩家类


def read_name(self):
        return [0,"玩家"]
    def read_choose(self):
        return "X"


2.4 定义页面类


利用gird对页面进行合理的分布,下子的方框实则是button,利用command对button进行动态改变

def createPage(self):
        self.page = Frame(self.root)  # 创建Frame
        self.page.pack()
        Label(self.page, text="{0},您选择的棋子是{1},您为先手".format(self.read_name()[1], self.read_choose())).grid(row=0, stick=W, pady=10)
        button1 = Button(self.page, textvariable=self.btn_text1, width=10, font=('Times 16 bold'), height=3, command=lambda:self.update_btn_text(1))
        button1.grid(row=1, column=1)
        button2 = Button(self.page, textvariable=self.btn_text2, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(2))
        button2.grid(row=1, column=2)
        button3 = Button(self.page, textvariable=self.btn_text3, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(3))
        button3.grid(row=1, column=3)
        button4 = Button(self.page, textvariable=self.btn_text4, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(4))
        button4.grid(row=2, column=1)
        button5 = Button(self.page, textvariable=self.btn_text5, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(5))
        button5.grid(row=2, column=2)
        button6 = Button(self.page, textvariable=self.btn_text6, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(6))
        button6.grid(row=2, column=3)
        button7 = Button(self.page, textvariable=self.btn_text7, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(7))
        button7.grid(row=3, column=1)
        button8 = Button(self.page, textvariable=self.btn_text8, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(8))
        button8.grid(row=3, column=2)
        button9 = Button(self.page, textvariable=self.btn_text9, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(9))
        button9.grid(row=3, column=3)


2.5 定义页面变化类以及玩家与AI轮流转换下子权限


def update_btn_text(self, digit):
        playerLetter = self.read_choose()
        if playerLetter == "X":
            self.computerLetter == "O"
        else:
            self.computerLetter = "X"
        if digit == 1 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text1.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 2 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text2.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 3 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text3.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 4 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text4.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 5 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text5.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 6 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text6.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 7 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text7.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 8 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text8.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 9 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text9.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if (len(self.digits) == 1 and self.win(self.panels, 'X') == False and self.win(self.panels, 'O') == False):
            self.page.destroy()
            msq.showinfo("RESULT", "平局")


2.6 定义判断胜负类


def win(self, panels, sign):
        return ((panels[1] == panels[2] == panels[3] == sign)
                or (panels[1] == panels[4] == panels[7] == sign)
                or (panels[1] == panels[5] == panels[9] == sign)
                or (panels[2] == panels[5] == panels[8] == sign)
                or (panels[3] == panels[6] == panels[9] == sign)
                or (panels[3] == panels[5] == panels[7] == sign)
                or (panels[4] == panels[5] == panels[6] == sign)
                or (panels[7] == panels[8] == panels[9] == sign))


2.7 定义智能AI下子类

def computer_move(self, panels, digits, computerLetter ,playerLetter):
        panelscopy = panels.copy()
        next_step1 = 0
        for i in digits:
            panelscopy[i] = computerLetter
            if (self.win(panelscopy, computerLetter)):
                next_step1 = i
                break
            panelscopy = panels.copy()
        panelscopy = panels.copy()
        for i in digits:
            panelscopy[i] = playerLetter
            if (self.win(panelscopy, playerLetter)):
                next_step2 = i
                break
            else:
                next_step2 = random.choice(digits)
            panelscopy = panels.copy()
        if next_step1 == 0:
            next_step = next_step2
        elif next_step1 != 0:
            next_step = next_step1
        digits.remove(next_step)
        panels[next_step] = computerLetter
        if next_step == 1:
            self.btn_text1.set(computerLetter)
        elif next_step == 2:
            self.btn_text2.set(computerLetter)
        elif next_step == 3:
            self.btn_text3.set(computerLetter)
        elif next_step == 4:
            self.btn_text4.set(computerLetter)
        elif next_step == 5:
            self.btn_text5.set(computerLetter)
        elif next_step == 6:
            self.btn_text6.set(computerLetter)
        elif next_step == 7:
            self.btn_text7.set(computerLetter)
        elif next_step == 8:
            self.btn_text8.set(computerLetter)
        elif next_step == 9:
            self.btn_text9.set(computerLetter)
        if (self.win(panels, computerLetter)):
            self.page.destroy()
            msq.showinfo("RESULT", "AI获胜")


3 整体代码展示(可直接使用!)


# -*- coding: utf-8 -*-
from tkinter import *
import tkinter.messagebox as msq
import random
class fupage2_play(object):
    def __init__(self, master=None):
        self.root = master  # 定义内部变量root
        self.root.title("井字棋")
        self.root.geometry('%dx%d' % (600, 400))  # 设置窗口大小
        self.panels = ["panel"]*10
        self.count = 0
        self.digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        self.mark = ""
        self.btn_text1 = StringVar()
        self.btn_text2 = StringVar()
        self.btn_text3 = StringVar()
        self.btn_text4 = StringVar()
        self.btn_text5 = StringVar()
        self.btn_text6 = StringVar()
        self.btn_text7 = StringVar()
        self.btn_text8 = StringVar()
        self.btn_text9 = StringVar()
        self.computerLetter = "O"
        self.createPage()
    def read_name(self):
        return [0,"玩家"]
    def read_choose(self):
        return "X"
    def createPage(self):
        self.page = Frame(self.root)  # 创建Frame
        self.page.pack()
        Label(self.page, text="{0},您选择的棋子是{1},您为先手".format(self.read_name()[1], self.read_choose())).grid(row=0, stick=W, pady=10)
        button1 = Button(self.page, textvariable=self.btn_text1, width=10, font=('Times 16 bold'), height=3, command=lambda:self.update_btn_text(1))
        button1.grid(row=1, column=1)
        button2 = Button(self.page, textvariable=self.btn_text2, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(2))
        button2.grid(row=1, column=2)
        button3 = Button(self.page, textvariable=self.btn_text3, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(3))
        button3.grid(row=1, column=3)
        button4 = Button(self.page, textvariable=self.btn_text4, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(4))
        button4.grid(row=2, column=1)
        button5 = Button(self.page, textvariable=self.btn_text5, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(5))
        button5.grid(row=2, column=2)
        button6 = Button(self.page, textvariable=self.btn_text6, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(6))
        button6.grid(row=2, column=3)
        button7 = Button(self.page, textvariable=self.btn_text7, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(7))
        button7.grid(row=3, column=1)
        button8 = Button(self.page, textvariable=self.btn_text8, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(8))
        button8.grid(row=3, column=2)
        button9 = Button(self.page, textvariable=self.btn_text9, width=10, height=3, font=('Times 16 bold'), command=lambda:self.update_btn_text(9))
        button9.grid(row=3, column=3)
    def update_btn_text(self, digit):
        playerLetter = self.read_choose()
        if playerLetter == "X":
            self.computerLetter == "O"
        else:
            self.computerLetter = "X"
        if digit == 1 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text1.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 2 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text2.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 3 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text3.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 4 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text4.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 5 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text5.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 6 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text6.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 7 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text7.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 8 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text8.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if digit == 9 and digit in self.digits:
            self.digits.remove(digit)
            self.panels[digit] = playerLetter
            self.btn_text9.set(playerLetter)
            if (self.win(self.panels, playerLetter)):
                self.page.destroy()
                msq.showinfo("RESULT", "{},你获胜!".format(self.read_name()[1]))
            else:
                self.computer_move(self.panels, self.digits, self.computerLetter, playerLetter)
        if (len(self.digits) == 1 and self.win(self.panels, 'X') == False and self.win(self.panels, 'O') == False):
            self.page.destroy()
            msq.showinfo("RESULT", "平局")
    def win(self, panels, sign):
        return ((panels[1] == panels[2] == panels[3] == sign)
                or (panels[1] == panels[4] == panels[7] == sign)
                or (panels[1] == panels[5] == panels[9] == sign)
                or (panels[2] == panels[5] == panels[8] == sign)
                or (panels[3] == panels[6] == panels[9] == sign)
                or (panels[3] == panels[5] == panels[7] == sign)
                or (panels[4] == panels[5] == panels[6] == sign)
                or (panels[7] == panels[8] == panels[9] == sign))
    def computer_move(self, panels, digits, computerLetter ,playerLetter):
        panelscopy = panels.copy()
        next_step1 = 0
        for i in digits:
            panelscopy[i] = computerLetter
            if (self.win(panelscopy, computerLetter)):
                next_step1 = i
                break
            panelscopy = panels.copy()
        panelscopy = panels.copy()
        for i in digits:
            panelscopy[i] = playerLetter
            if (self.win(panelscopy, playerLetter)):
                next_step2 = i
                break
            else:
                next_step2 = random.choice(digits)
            panelscopy = panels.copy()
        if next_step1 == 0:
            next_step = next_step2
        elif next_step1 != 0:
            next_step = next_step1
        digits.remove(next_step)
        panels[next_step] = computerLetter
        if next_step == 1:
            self.btn_text1.set(computerLetter)
        elif next_step == 2:
            self.btn_text2.set(computerLetter)
        elif next_step == 3:
            self.btn_text3.set(computerLetter)
        elif next_step == 4:
            self.btn_text4.set(computerLetter)
        elif next_step == 5:
            self.btn_text5.set(computerLetter)
        elif next_step == 6:
            self.btn_text6.set(computerLetter)
        elif next_step == 7:
            self.btn_text7.set(computerLetter)
        elif next_step == 8:
            self.btn_text8.set(computerLetter)
        elif next_step == 9:
            self.btn_text9.set(computerLetter)
        if (self.win(panels, computerLetter)):
            self.page.destroy()
            msq.showinfo("RESULT", "AI获胜")
if __name__ == "__main__":
    root = Tk()
    root.title('井字棋')
    fupage2_play(root)
    root.mainloop()

最后展现界面:

相关文章
|
7天前
|
人工智能 小程序
【一步步开发AI运动小程序】十五、AI运动识别中,如何判断人体站位的远近?
【云智AI运动识别小程序插件】提供人体、运动及姿态检测的AI能力,无需后台支持,具有快速、体验好、易集成等特点。本文介绍如何利用插件判断人体与摄像头的远近,确保人体图像在帧内的比例适中,以优化识别效果。通过`whole`检测规则,分别实现人体过近和过远的判断,并给出相应示例代码。
|
5天前
|
存储 人工智能 自然语言处理
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
ChatMCP 是一款基于模型上下文协议(MCP)的 AI 聊天客户端,支持多语言和自动化安装。它能够与多种大型语言模型(LLM)如 OpenAI、Claude 和 OLLama 等进行交互,具备自动化安装 MCP 服务器、SSE 传输支持、自动选择服务器、聊天记录管理等功能。
55 14
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
|
1天前
|
人工智能 小程序 API
【一步步开发AI运动小程序】十七、如何识别用户上传视频中的人体、运动、动作、姿态?
【云智AI运动识别小程序插件】提供人体、运动、姿态检测的AI能力,支持本地原生识别,无需后台服务,具有速度快、体验好、易集成等优点。本文介绍如何使用该插件实现用户上传视频的运动识别,包括视频解码抽帧和人体识别的实现方法。
|
6天前
|
人工智能 小程序 UED
【一步步开发AI运动小程序】十六、AI运动识别中,如何判断人体站位?
【云智AI运动识别小程序插件】提供人体、运动及姿态检测的AI能力,本地引擎无需后台支持,具备快速、体验好、易集成等优势。本文介绍如何利用插件的`camera-view`功能,通过检测人体站位视角(前、后、左、右),确保运动时的最佳识别率和用户体验。代码示例展示了如何实现视角检查,确保用户正或背对摄像头,为后续运动检测打下基础。
|
12天前
|
人工智能 小程序 API
【一步步开发AI运动小程序】十三、自定义一个运动分析器,实现计时计数02
本文介绍如何利用“云智AI运动识别小程序插件”开发AI运动小程序,详细解析了俯卧撑动作的检测规则构建与执行流程,涵盖卧撑和撑卧两个姿态的识别规则,以及如何通过继承`sports.SportBase`类实现运动分析器,适用于小程序开发者。
|
12天前
|
人工智能 小程序 API
【一步步开发AI运动小程序】十二、自定义一个运动分析器,实现计时计数01
随着AI技术的发展,AI运动APP如雨后春笋般涌现,如“乐动力”、“天天跳绳”等,推动了云上运动会、线上健身等热潮。本文将指导你从零开始开发一个AI运动小程序,利用“云智AI运动识别小程序插件”,介绍运动识别原理、计量方式及运动分析器基类的使用,帮助你在小程序中实现运动计时和计数功能。下篇将继续探讨运动姿态检测规则的编写。
|
2天前
|
人工智能 小程序 数据处理
uni-app开发AI康复锻炼小程序,帮助肢体受伤患者康复!
近期,多家康复机构咨询AI运动识别插件是否适用于肢力运动受限患者的康复锻炼。本文介绍该插件在康复锻炼中的应用场景,包括康复运动指导、运动记录、恢复程度记录及过程监测。插件集成了人体检测、姿态识别等功能,支持微信小程序平台,使用便捷,安全可靠,帮助康复治疗更加高效精准。
|
8天前
|
人工智能 小程序 JavaScript
【一步步开发AI运动小程序】十四、主包超出2M大小限制,如何将插件分包发布?
本文介绍了如何从零开始开发一个AI运动小程序,重点讲解了通过分包技术解决程序包超过2M限制的问题。详细步骤包括在uni-app中创建分包、配置`manifest.json`和`pages.json`文件,并提供了分包前后代码大小对比,帮助开发者高效实现AI运动功能。
|
13天前
|
人工智能 小程序 开发者
【一步步开发AI运动小程序】十一、人体关键点跳跃追踪
本文介绍如何利用“云智AI运动识别小程序插件”开发AI运动小程序,涵盖云上运动会、健身打卡等热门应用场景。通过示例代码展示如何调用插件功能,实现动作追踪与分析,助力开发者快速上手。
|
13天前
|
存储 人工智能 并行计算
【AI系统】算子开发编程语言 Ascend C
本文详细介绍了昇腾算子开发编程语言 Ascend C,旨在帮助开发者高效完成算子开发与模型调优。Ascend C 原生支持 C/C++标准,通过多层接口抽象、自动并行计算等技术,简化开发流程,提高开发效率。文章还探讨了并行计算的基本原理及大模型并行加速策略,结合 Ascend C 的 SPMD 编程模型和流水线编程范式,为读者提供了深入理解并行计算和 AI 开发的重要工具和方法。
30 2