【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()

最后展现界面:

相关文章
|
1月前
|
人工智能 安全 API
20 万奖金池就位!Higress AI 网关开发挑战赛参赛指南
本次赛事共设三大赛题方向,参赛者可以任选一个方向参赛。本文是对每个赛题方向的参赛指南。
240 13
|
1月前
|
人工智能 运维 安全
加速智能体开发:从 Serverless 运行时到 Serverless AI 运行时
在云计算与人工智能深度融合的背景下,Serverless 技术作为云原生架构的集大成者,正加速向 AI 原生架构演进。阿里云函数计算(FC)率先提出并实践“Serverless AI 运行时”概念,通过技术创新与生态联动,为智能体(Agent)开发提供高效、安全、低成本的基础设施支持。本文从技术演进路径、核心能力及未来展望三方面解析 Serverless AI 的突破性价值。
|
1月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
2887 43
|
人工智能 自然语言处理 前端开发
产品经理也能“开发”需求?淘宝信息流从需求到上线的AI端到端实践
淘宝推荐信息流业务,常年被“需求多、技术栈杂、协作慢”困扰,需求上线周期动辄一周。WaterFlow——一套 AI 驱动的端到端开发新实践,让部分需求两天内上线,甚至产品经理也能“自产自销”需求。短短数月,已落地 30+ 需求、自动生成 5.4 万行代码,大幅提升研发效率。接下来,我们将揭秘它是如何落地并改变协作模式的。
334 37
产品经理也能“开发”需求?淘宝信息流从需求到上线的AI端到端实践
|
1月前
|
人工智能 IDE 开发工具
从6人日到1人日:一次AI驱动的客户端需求开发实战
从6人日到1人日:一次AI驱动的客户端需求开发实战
从6人日到1人日:一次AI驱动的客户端需求开发实战
|
1月前
|
人工智能 小程序 开发者
【一步步开发AI运动APP】十二、自定义扩展新运动项目03
继【一步步开发AI运动小程序】后,我们推出新系列【一步步开发AI运动APP】,助开发者打造高性能、优体验的AI运动应用。本文详解自定义扩展运动分析器的统一管理实现,提升代码复用性与可维护性,涵盖APP与小程序插件差异及完整代码示例,助力AI运动场景深度拓展。
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
python编写AI生常用匡架及使用指令集
本文介绍Python中常用AI框架,包括TensorFlow、PyTorch、Scikit-learn、Hugging Face、spaCy、OpenCV及XGBoost等,涵盖安装指令与基础代码示例,适用于机器学习、深度学习、自然语言处理与计算机视觉等领域,助力快速入门与应用开发。(238字)
299 7
|
1月前
|
人工智能 自然语言处理 数据可视化
smardaten AI + 无代码开发实践:基于自然语言交互快速开发【苏超赛事管理系统】
苏超赛事管理系统基于smardaten无代码平台,通过AI生成与可视化配置,实现球队、赛程、积分等全流程数字化管理,提升效率、优化体验、支持数据可视化,助力赛事高效运营。
smardaten AI + 无代码开发实践:基于自然语言交互快速开发【苏超赛事管理系统】
|
1月前
|
人工智能 Cloud Native 自然语言处理
拔俗AI智能体服务开发:你的7x24小时数字员工,让企业效率飙升的秘密武器
在“人效为王”时代,企业面临服务响应慢、成本高、协同难等痛点。阿里云AI智能体以自主决策、多模态交互、持续学习三大引擎,打造永不疲倦的“数字员工”,实现7×24小时高效服务,助力企业降本增效、驱动创新增长。(238字)
|
1月前
|
人工智能 小程序 搜索推荐
【一步步开发AI运动APP】十二、自定义扩展新运动项目2
本文介绍如何基于uni-app运动识别插件实现“双手并举”自定义扩展运动,涵盖动作拆解、姿态检测规则构建及运动分析器代码实现,助力开发者打造个性化AI运动APP。

热门文章

最新文章

推荐镜像

更多