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

最后展现界面:

目录
打赏
0
0
0
0
7
分享
相关文章
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
DeepSite是基于DeepSeek-V3模型的在线开发工具,无需配置环境即可通过自然语言描述快速生成游戏、网页和应用代码,并支持实时预览效果,显著降低开发门槛。
343 93
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
怎么开发Python第三方库?手把手教你参与开源项目!
大家好,我是程序员晚枫。本文将分享如何开发Python第三方库,并以我维护的开源项目 **popdf** 为例,指导参与开源贡献。Popdf是一个PDF操作库,支持PDF转Word、转图片、合并与加密等功能。文章涵盖从fork项目、本地开发、单元测试到提交PR的全流程,适合想了解开源贡献的开发者。欢迎访问[popdf](https://gitcode.com/python4office/popdf),一起交流学习!
83 21
怎么开发Python第三方库?手把手教你参与开源项目!
基于Python+Vue开发的美容预约管理系统源码+运行
基于Python+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的美容诊所预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
42 9
基于Python+Vue开发的体育场馆预约管理系统源码+运行
本项目为大学生课程设计作业,采用Python和Vue技术构建了一个体育场馆预约管理系统(实现前后端分离)。系统的主要目标在于帮助学生理解和掌握Python编程知识,同时培养其项目规划和开发能力。参与该项目的学习过程,学生能够在实际操作中锻炼技能,为未来的职业发展奠定良好的基础。
50 3
基于Python+Vue开发的摄影网上预约管理系统源码+运行
基于Python+Vue开发的摄影网上预约管理系统(前后端分离),影楼婚纱摄影,这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的在线摄影预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
39 8
【AI大模型】使用Python调用DeepSeek的API,原来SDK是调用这个,绝对的一分钟上手和使用
本文详细介绍了如何使用Python调用DeepSeek的API,从申请API-Key到实现代码层对话,手把手教你快速上手。DeepSeek作为领先的AI大模型,提供免费体验机会,帮助开发者探索其语言生成能力。通过简单示例代码与自定义界面开发,展示了API的实际应用,让对接过程在一分钟内轻松完成,为项目开发带来更多可能。
基于Python+Vue开发的新闻管理系统源码+运行
基于Python+Vue开发的新闻管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的新闻管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
49 5
基于Python+Vue开发的民宿客房预订管理系统源码运行
基于Python+Vue开发的民宿客房预订管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的民宿客房预订管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
54 8
基于Python+Vue开发的房产销售管理系统源码+运行
基于Python+Vue开发的房产销售管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的房产销售管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
38 2
基于Python+Vue开发的鲜牛奶订购管理系统源码+运行
基于Python+Vue开发的鲜牛奶订购管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的牛奶订购管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
35 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等