Python实现简单的井字棋/一字棋小游戏(带GUI界面)

一字棋的实现


利用tk库实现一字棋GUI界面的制作,导入tk库。

from tkinter import *  # 从tk库导入所有方法,制作GUI界面
import tkinter.messagebox as msq  # 消息框 tkinter.messagebox

创建游戏类GamePlay,包含游戏界面,玩家与电脑的操作等。

class GamePlay(object):
	def __init__(self, master=None):
	def create_page(self):
	def update_btn_text(self, digit):
	def getvalue(self):
	def computer_move(self):

初始化GamePlay类,需要初始化界面大小,创建两个列表分别用来纪录已进行的操作和按钮的序号,实时刷新按钮的text属性,变量记录已操作的按钮数,并执行界面绘制函数。

    def __init__(self, master=None):
        self.root = master  # 定义内部变量root
        self.page = Frame(self.root)  # 创建Frame
        self.root.geometry('%dx%d' % (600, 400))  # 设置窗口大小
        self.matrix = [[" "] * 3, [" "] * 3, [" "] * 3]  # matrix列表记录已进行的OX操作
        self.digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]  # digits列表包含按钮的序号,完善按钮操作逻辑
        
        self.btn_text1 = StringVar()  # 实时刷新9个按钮的text属性
        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.cnt = 0  # 记录已填充格数
        self.create_page()  # 执行界面绘制函数 create_page()

生成界面绘制函数,需要生成Buttun控件并分配位置,用command链接后续事件——text属性的刷新、胜负的判断以及电脑操作。

    def create_page(self):  # 界面绘制函数
        self.page.pack()  # 使本页面显示
        Label(self.page, text="").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))  
        # 创建按钮对象,属性textvariale绑定btn_text变量实例,使text以变量方法呈现
        # 利用command属性绑定lambda匿名函数,实现动态控制Button控件,同时传出对应的digit值
        button1.grid(row=1, column=1)  # 使用grid方法控制控件位置
        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)

在command属性链接的update_btn_text()函数中完成玩家按钮判断、text属性更新、玩家胜负判断,引出电脑操作。

    def update_btn_text(self, digit):  # 更新Button的text属性
        player_letter = "O"  # 玩家写'O'
        self.cnt += 1  # 占用格数加一
        if digit == 1 and digit in self.digits:  # 判断按下按钮位置,且确保该按钮未被按下过,以下通过9个if判断
            self.digits.remove(digit)  # remove方法将digits列表中的本次按下按钮的值删除,防止多次按下触发
            self.matrix[0][0] = player_letter  # 记录玩家选择的位置,将'O'写入matrix列表
            self.btn_text1.set(player_letter)  # 将player_letter的值传入btn_text变量中,完成操作更新

        if digit == 2 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[0][1] = player_letter
            self.btn_text2.set(player_letter)

        if digit == 3 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[0][2] = player_letter
            self.btn_text3.set(player_letter)

        if digit == 4 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[1][0] = player_letter
            self.btn_text4.set(player_letter)

        if digit == 5 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[1][1] = player_letter
            self.btn_text5.set(player_letter)

        if digit == 6 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[1][2] = player_letter
            self.btn_text6.set(player_letter)

        if digit == 7 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[2][0] = player_letter
            self.btn_text7.set(player_letter)

        if digit == 8 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[2][1] = player_letter
            self.btn_text8.set(player_letter)

        if digit == 9 and digit in self.digits:
            self.digits.remove(digit)
            self.matrix[2][2] = player_letter
            self.btn_text9.set(player_letter)

        if self.getvalue() == -100:  # 进行玩家获胜判断
            msq.showinfo("Result", "你获胜了!")  # 消息弹窗(标题,内容)
            exit()	# 关闭消息提示框后,程序退出 
        else:
            self.computer_move()  # 若玩家还未获胜,则电脑操作

        if (len(self.digits) == 1) and (self.getvalue != 100 and self.getvalue != -100):
            msq.showinfo("Result", "平局了!")  # 如果仅剩一格且两方都未获胜,即为平局
            exit()

对当前局面进行博弈判断,博弈得分值越高越利好电脑,当得分达到100时电脑获胜,得分达到-100时玩家获胜,游戏结束时若于两者之间,则平局。

    def getvalue(self):  # 博弈得分值函数,value值越大越利好电脑
        for i in range(0, 3):  # 判断游戏是否结束的value值,100、-100

            if self.matrix[0][i] == 'X' and self.matrix[1][i] == 'X' and self.matrix[2][i] == 'X':
                return 100
            if self.matrix[0][i] == 'O' and self.matrix[1][i] == 'O' and self.matrix[2][i] == 'O':
                return -100
            if self.matrix[i] == ['X', 'X', 'X']:
                return 100
            if self.matrix[i] == ['O', 'O', 'O']:
                return -100

        if self.matrix[0][0] == 'X' and self.matrix[1][1] == 'X' and self.matrix[2][2] == 'X':
            return 100
        if self.matrix[0][0] == 'O' and self.matrix[1][1] == 'O' and self.matrix[2][2] == 'O':
            return -100
        if self.matrix[0][2] == 'X' and self.matrix[1][1] == 'X' and self.matrix[2][0] == 'X':
            return 100
        if self.matrix[0][2] == 'O' and self.matrix[1][1] == 'O' and self.matrix[2][0] == 'O':
            return -100

        value = 0  # value置0,进行一般情况的value值计算

        for i in range(0, 3):

            if self.matrix[0][i] != 'O' and self.matrix[1][i] != 'O' and self.matrix[2][i] != 'O':
                value += 1
            if self.matrix[0][i] != 'X' and self.matrix[1][i] != 'X' and self.matrix[2][i] != 'X':
                value -= 1
            if self.matrix[0][i] != 'O' and self.matrix[1][i] != 'O' and self.matrix[2][i] != 'O':
                value += 1
            if self.matrix[0][i] != 'X' and self.matrix[1][i] != 'X' and self.matrix[2][i] != 'X':
                value -= 1
        if self.matrix[0][0] != 'O' and self.matrix[1][1] != 'O' and self.matrix[2][2] != 'O':
            value += 1
        if self.matrix[0][0] != 'X' and self.matrix[1][1] != 'X' and self.matrix[2][2] != 'X':
            value -= 1
        if self.matrix[0][2] != 'O' and self.matrix[1][1] != 'O' and self.matrix[2][0] != 'O':
            value += 1
        if self.matrix[0][2] != 'X' and self.matrix[1][1] != 'X' and self.matrix[2][0] != 'X':
            value -= 1

        return value

利用极小化极大算法建立value预估函数,借助函数递归进行博弈树运算

def dfs(now_maps, pre, step):  # 极小化极大算法
    if now_maps.cnt == 9 or now_maps.getvalue() == 100 or now_maps.getvalue() == -100:  
    # 删除后电脑不会对第一次按按钮作出反应(>.<)
        return now_maps.getvalue()

    if step % 2 == 0:
        value = 200

        for i in range(0, 3):
            for j in range(0, 3):
                if now_maps.matrix[i][j] == ' ':
                    now_maps.matrix[i][j] = 'O'
                    now_maps.cnt += 1
                    tmp = dfs(now_maps, value, step + 1)  # 函数递归调用,利用Minimax算法原理
                    now_maps.cnt -= 1
                    now_maps.matrix[i][j] = ' '
                    if tmp < value:
                        value = tmp
                    if value <= pre:
                        return value
    else:
        value = -200

        for i in range(0, 3):
            for j in range(0, 3):
                if now_maps.matrix[i][j] == ' ':
                    now_maps.matrix[i][j] = 'X'
                    now_maps.cnt += 1
                    tmp = dfs(now_maps, value, step + 1)
                    now_maps.cnt -= 1
                    now_maps.matrix[i][j] = ' '
                    if tmp > value:
                        value = tmp
                    if value >= pre:
                        return value
    return value

电脑执行操作函数,对未选择的点进行遍历,选择出value预估值最大的点,写入电脑的选择

    def computer_move(self):  # 电脑操作函数
        computer_letter = 'X'  # 电脑写'X'
        maxvalue = -200  # 设定一个较小值,后续执行冒泡操作

        for i in range(0, 3):  # 遍历、寻找一个合适的点,最大value预估值的点
            for j in range(0, 3):
                if self.matrix[i][j] == ' ':
                    self.cnt += 1
                    self.matrix[i][j] = 'X'
                    tmp = dfs(self, maxvalue, 0)
                    self.matrix[i][j] = ' '
                    self.cnt -= 1
                    if tmp > maxvalue:
                        maxvalue = tmp
                        x, y = i, j

        self.matrix[x][y] = 'X'  # 将'X'写入matrix列表,记录电脑选择的坐标
        self.cnt += 1  # 占用格数加一
        dit = x * 3 + y + 1  # 将矩阵坐标转换为一维坐标
        self.digits.remove(dit)  # 移除digits列表中电脑选择的坐标
        if dit == 1: self.btn_text1.set(computer_letter)  # 将'X'传入dit值对应的btn_text变量,同digit
        if dit == 2: self.btn_text2.set(computer_letter)
        if dit == 3: self.btn_text3.set(computer_letter)
        if dit == 4: self.btn_text4.set(computer_letter)
        if dit == 5: self.btn_text5.set(computer_letter)
        if dit == 6: self.btn_text6.set(computer_letter)
        if dit == 7: self.btn_text7.set(computer_letter)
        if dit == 8: self.btn_text8.set(computer_letter)
        if dit == 9: self.btn_text9.set(computer_letter)

        if self.getvalue() == 100:
            msq.showinfo("Result", "你失败了!")
            exit()

程序运行,进入主界面

if __name__ == "__main__":
    root = Tk()
    root.title('一字棋')
    GamePlay(root)
    root.mainloop()  # 进入到事件(消息)循环
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值