1 前言
在学习tkinter时打算开发一款井字棋游戏,之前试过利用pygame开发【利用pygame开发井字棋博客】。但是这个项目没有嵌入AI智能对战,只能由两个玩家操作。正好借此机会利用tkinter开发对战界面,并嵌入AI对战。
游戏界面如下:
为了读者对游戏由更好的了解,这里放操作视频:
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()
最后展现界面: