井字棋Tkinter 智能/智障

基于 Tkinter 制作出的井字棋游戏。

第一个版本是没有任何算法的纯随机电脑下棋方式(简称——智障):

import tkinter as tk 
from tkinter import messagebox #! 我单独导入了messagebox(信息盒子)
import random as r

window = tk.Tk() #!创建了一个叫 window 的窗口
window.title("井字棋") #!窗口名字叫 井字棋
 
#! Create board 创建棋盘
def create_board(): #! 创建棋盘的函数
    for i in range(3): #!同过双重给for循环实现创建棋盘上的9个盘格
        for j in range(3):
             #!通过给按钮添加点击事件实现点击后下棋的功能:command,又因为我们要知道点的是哪个按钮
             #!所以需要用到lambda将row行,col列传递进去
            button = tk.Button(window, text="", font=("Arial", 50), 
                               height=2, width=6, bg="lightblue", 
                               command=lambda row=i, col=j: handle_click(row, col))
            button.grid(row=i, column=j, sticky="nsew") #!布局到窗口中

create_board() #!调用 创建棋盘的函数

#! Initialize variables 创二维列表,表示整个棋盘的棋子
board = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
 
#! Handle button clicks 按钮点击事件
def handle_click(row, col): #!函数传递row(行)col(列)用来表示具体哪个按钮
 
    if board[row][col] == 0: #!判断点击的按钮是否为0,也就是这里是不是没有落过棋子
        board[row][col] = "X" #!符合条件就将棋盘放上X棋子
        button = window.grid_slaves(row=row, column=col)[0] #!找到对应的棋盘格子
        button.config(text=board[row][col])#!将棋画在棋盘上
        xx = check_for_winner()
        if xx != 0:
            PC_choice() #!你下完棋了,该电脑下棋了,调用电脑的下棋函数
        
               
def PC_choice():
    
    cnt = 0 #! 计数器 表示棋盘列表0的个数
    for row in board:
        cnt+=row.count(0) #!找到棋盘列表0的个数就让cnt加一  如果是0就相当于没选过的格子
    if cnt > 0: #! 如果cnt大于0说明棋盘上还有空格子
        while 1:#!随机选格子可能选到选过的,所以我们要一直选直到选到没选过的为止
            a = r.randint(0, 2) #!随机哪一行
            b = r.randint(0, 2) #!随机哪一列
            if board[a][b] == 0: #!如果选的那个等于0
                break #!退出循环,
        board[a][b] = "O" #!将棋子画在棋盘上
        button = window.grid_slaves(row=a, column=b)[0] #!找到对应的棋盘格子
        button.config(text=board[a][b]) #!将棋盘更新为O
        bb = check_for_winner() #!将选择胜利者的函数返回值赋值给bb
  
        if bb == 0: #!判断返回值是不是0 ,是的话相当于决定出输赢了
            return 0 #!决定出输赢了就返回0
    
        
  
#! Check for a winner or a tie 判断输赢平局的>>>
def check_for_winner(): 
    winner = None #!先将胜者赋值为None,表示没有呢
 
    #! Check rows 检查每一行
    for row in board:
        # print(row[0])
        #!如果一行中所有元素都相等,并且不是0,那么就将这个值赋值给胜利者
        if row.count(row[0]) == len(row) and row[0] != 0: 
            winner = row[0]
            break #!都有胜利者了,其他程序也没啥必要执行了,直接打破for循环
  
    #! Check columns 这个是检查列的,和行的类似
    for col in range(len(board)):
        if board[0][col] == board[1][col] == board[2][col] and board[0][col] != 0:
            winner = board[0][col]
            break
 
    #! Check diagonals #!这个是检查对角线的除了横竖连成三个能赢,还有斜着的
    if board[0][0] == board[1][1] == board[2][2] and board[0][0] != 0:
        winner = board[0][0]
    elif board[0][2] == board[1][1] == board[2][0] and board[0][2] != 0:
        winner = board[0][2]
    #!如果都判断完了,
    #!还没有找到胜利者,那么就判断是否平局
    if all([all(row) for row in board]) and winner is None:
        winner = "tie" #!tie : 平局
 
    if winner: #!之前我们学过,if 条件为真就会执行里面的程序,
        #!其中0,空都表示假,所以我们要判断一下胜利者是不是真
        #!在最开始我们不是设置了胜利者为None吗,None就是假.如果Winner为假
        #!我们就不执行这里的程序
        cc = declare_winner(winner) #!如果胜利者是真,那么调用胜利者函数
        if cc == 0: #!如果调用了胜利者函数说明我已经决定出输赢了,直接返回0
            return 0

    
 
#! Declare the winner and ask to restart the game 选择胜利者,或平局
def declare_winner(winner):
    if winner == "tie":
        message = "平局啦!"
    else:
        message = f"玩家 {winner} 胜利!"
    #!选择胜利者,或平局后,都会弹出消息框,询问是否重新开始游戏
    answer = messagebox.askyesno("游戏结束!", message + " 你想要重新开始吗?")

    if answer: #!如果胜利者点的是重新开始
        global board #!将全局变量board赋值给局部变量board
        #!将棋盘重新赋值,相当于重新开始游戏
        board = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
        #!重新开始游戏后,我们还要重新创建棋盘,调用create_board()函数
        create_board()
        return 0 #!都重新开始了就返回0

    else:
        window.quit() #!没选重新开始那不就是退出游戏吗?

window.mainloop()#!窗口一直显示的循环

第二个版本是电脑会通过算法来阻止你获胜,甚至能赢过你的(简称:智能)

import tkinter as tk
import numpy as np
import copy
 
 
#! 游戏结束
def game_over(B1, B2, B3, ):
    global B
    for i in range(3):
        for j in range(3):
            B[i][j]['state'] = 'disabled'  #! 设置为禁用
            B[i][j]['cursor'] = 'arrow'  #! 鼠标样式更改
    if B1['text'] == 'x':
        B1['text'] = '玩'
        B2['text'] = '家'
        B3['text'] = '胜'
    elif B1['text'] == 'o' or B2['text'] == 'o':
        B1['text'] = '电'
        B2['text'] = '脑'
        B3['text'] = '胜'
    else:
        global b2
        b2['text'] = '和棋'
 
 
#! 绝杀点/关键点
def Key_points(M, t):
    x = []
    s_r = M.sum(axis=1)  #! 各行的和
    s_c = M.sum(axis=0)  #! 各列的和
    m_d = M[0, 0] + M[1, 1] + M[2, 2]  #! 主对角线
    b_d = M[0, 2] + M[1, 1] + M[2, 0]  #! 反对角线
    for i in range(3):
        for j in range(3):
            if M[i][j] == 0:  #! 这是个空位
                c = 0  #! 行,列,或对角和为1的个数
                if i == j and m_d == t: c += 1  #! 如果是对角线或反对角线
                if i + j == 2 and b_d == t: c += 1
                if s_r[i] == t: c += 1
                if s_c[j] == t: c += 1
                if c >= 2:
                    x.append([i, j])  #! 能绝杀,放置
    return x
 
 
#! 电脑下棋+判断输赢
def aiplay():
    global B, b1, b2, b3
    mark = []  #! 记号,储存棋盘
    t = 0  #! 记录空位个数
    for i in range(3):
        mark.append([])
        for j in range(3):
            if B[i][j]['text'] == 'o':
                mark[i].append(1)
            elif B[i][j]['text'] == 'x':
                mark[i].append(-1)
            else:
                mark[i].append(0)
                t += 1
        if sum(mark[i]) == -3:  #! 如果某一排有三个x玩家赢
            game_over(B[i][0], B[i][1], B[i][2])
            return
    if not t:  #! 没有空位,和棋
        game_over(b1, b2, b3)
    mark = np.array(mark)
    sum_row = mark.sum(axis=1)  #! 各行的和
    sum_column = mark.sum(axis=0)  #! 各列的和
    main_diagonal = mark[0, 0] + mark[1, 1] + mark[2, 2]  #! 主对角线
    back_diagonal = mark[0, 2] + mark[1, 1] + mark[2, 0]  #! 反对角线
    for j in range(3):
        if sum_column[j] == -3:  #! 如果某一列有三个x玩家赢
            game_over(B[0][j], B[1][j], B[2][j])
            return
    if main_diagonal == -3:  #! 单独判断对角线
        game_over(B[0][0], B[1][1], B[2][2])
        return
    if back_diagonal == -3:  #! 单独判断反对角线
        game_over(B[0][2], B[1][1], B[2][0])
        return
    #! 电脑胜判断======================================================
    for i in range(3):  #! 有2个o电脑再下一个,电脑胜
        if sum_row[i] == 2:
            game_over(B[i][0], B[i][1], B[i][2])
            return
        if sum_column[i] == 2:
            game_over(B[0][i], B[1][i], B[2][i])
            return
    if main_diagonal == 2:  #! 单独判断对角线
        game_over(B[0][0], B[1][1], B[2][2])
        return
    if back_diagonal == 2:  #! 单独判断反对角线
        game_over(B[0][2], B[1][1], B[2][0])
        return
    #! 没法直接赢,看看有没有能堵住的==================================
    for i in range(3):  #! 有2个x电脑堵一下
        if sum_row[i] == -2:
            aiplace(B[i][0]), aiplace(B[i][1]), aiplace(B[i][2])
            return
        if sum_column[i] == -2:
            aiplace(B[0][i]), aiplace(B[1][i]), aiplace(B[2][i])
            return
    if main_diagonal == -2:  #! 单独判断对角线
        aiplace(B[0][0]), aiplace(B[1][1]), aiplace(B[2][2])
        return
    if back_diagonal == -2:  #! 单独判断反对角线
        aiplace(B[0][2]), aiplace(B[1][1]), aiplace(B[2][0])
        return
    #! 多想一步,如果有地方下了能有两个值为2的地方,就能绝杀================================
    K = Key_points(mark, 1)
    for i in K:
        aiplace(B[i[0]][i[1]])  #! 能绝杀,放置
        return
    #! 再多想一步,如果对方有能把自己绝杀的点,抢先堵住=======================================
    K = Key_points(mark, -1)
    for i in K:
        aiplace(B[i[0]][i[1]])  #! 能绝杀,放置
        return
    #! 多想两步,看有没有位置放了之后可以出现两个绝杀点
    for i in range(3):
        for j in range(3):
            if mark[i][j] == 0:  #! 这是个空位
                mark_new = copy.deepcopy(mark)  #! 深拷贝
                mark_new[i][j] = 1
                K = Key_points(mark_new, 1)
                if len(K) >= 2:
                    aiplace(B[i][j])  #! 或许能绝杀,放置
                    return
    #! 再多想两步,看对面有没有位置放了之后可以出现两个绝杀点
    for i in range(3):
        for j in range(3):
            if mark[i][j] == 0:  #! 这是个空位
                mark_new = copy.deepcopy(mark)  #! 深拷贝
                mark_new[i][j] = -1
                K = Key_points(mark_new, -1)
                if len(K) >= 2:
                    aiplace(B[i][j])  #! 或许能绝杀,放置
                    return
    #! 这还没办法,看哪有空位下在哪
    for i in range(3):
        for j in range(3):
            if mark[i][j] == 0:  #! 这是个空位
                aiplace(B[i][j])  #! 放置
                return
    #! 没有空位了,平局
    game_over(b1, b2, b3)
 
 
#! 电脑放置
def aiplace(Bu):
    if not Bu['text'] == 'x':
        Bu['text'] = 'o'  #! 打上o
        Bu['state'] = 'disabled'  #! 设置为禁用
        Bu['cursor'] = 'arrow'  #! 鼠标样式更改
 
 
#! 玩家放置
def place(Bu):
    Bu['text'] = 'x'  #! 打上x
    Bu['state'] = 'disabled'  #! 设置为禁用
    Bu['cursor'] = 'arrow'  #! 鼠标样式更改
    aiplay()
 
 
#! 重玩
def restart():
    global b1, b2, b3, B
    for i in range(3):
        for j in range(3):
            B[i][j]['text'] = ''  #! 棋盘重置
            B[i][j]['state'] = 'disabled'  #! 设置为禁用
            B[i][j]['cursor'] = 'arrow'  #! 鼠标样式更改
    b1['state'] = 'disabled'  #! 设置为禁用
    b1['cursor'] = 'arrow'  #! 鼠标样式更改
    b2['text'] = '开始'  #! 和棋时需要重置
    b2['state'] = 'normal'  #! 设置为启用
    b2['cursor'] = 'hand2'  #! 鼠标样式更改
    b3['state'] = 'normal'  #! 设置为启用
    b3['cursor'] = 'hand2'  #! 鼠标样式更改
 
 
#! 开始
def play():
    global b1, b2, b3, B, player_first
    for i in range(3):
        for j in range(3):
            B[i][j]['text'] = ''  #! 棋盘重置
            B[i][j]['state'] = 'normal'  #! 设置为启用
            B[i][j]['cursor'] = 'hand2'  #! 鼠标样式更改
    b1['state'] = 'normal'  #! 设置为启用
    b1['cursor'] = 'hand2'  #! 鼠标样式更改
    b2['state'] = 'disabled'  #! 设置为禁用
    b2['cursor'] = 'arrow'  #! 鼠标样式更改
    b3['state'] = 'disabled'  #! 设置为禁用
    b3['cursor'] = 'arrow'  #! 鼠标样式更改
    if not player_first:
        aiplay()  #! AI先下
 
 
#! 先手判断
def Go_first():
    global player_first
    if player_first:
        b3['text'] = '电脑先手'
    else:
        b3['text'] = '玩家先手'
    player_first = not player_first
 
 
global player_first, B, b1, b2, b3
player_first = True  #! 玩家先手
main_window = tk.Tk()  #! 调用Tk()创建主窗口
main_window.title("井字棋")  #! 给主窗口起一个名字
main_window.geometry("450x450")  #! 大小
#! main_window.resizable(0,0)  #! 不允许拉伸改变大小
#! 按钮 text:按钮文本,width、height:按钮大小,cursor:鼠标样式,command:调用函数
B = []  #! 棋盘按钮组
for i in range(3):
    B.append([])
    main_window.grid_rowconfigure(i, weight=1)  #! row为i,缩放比为1
    for j in range(3):
        main_window.grid_columnconfigure(j, weight=1)  #! column为i,缩放比为1
        B[i].append(tk.Button(main_window, text="", width=15, height=5, ))  #! 添加按钮
        B[i][j]['command'] = lambda i=i, j=j: place(B[i][j])  #! 增加点击函数
        B[i][j]['state'] = 'disabled'  #! 初始禁用
        B[i][j].grid(row=i, column=j, sticky=tk.N + tk.S + tk.W + tk.E)  #! 添加到主窗口显示
b1 = tk.Button(main_window, text="重玩", width=15, height=5, command=restart)  #! 添加按钮,点击调用重启函数
b2 = tk.Button(main_window, text="开始", width=15, height=5, cursor='hand2', command=play)  #! 添加按钮,点击调用开始函数
b3 = tk.Button(main_window, text='玩家先手', width=15, height=5, cursor='hand2', command=Go_first)  #! 添加按钮,点击调用先手函数
b1['state'] = 'disabled'  #! 初始为禁用
b1.grid(row=3, column=0, sticky=tk.N + tk.S + tk.W + tk.E)
b2.grid(row=3, column=1, sticky=tk.N + tk.S + tk.W + tk.E)
b3.grid(row=3, column=2, sticky=tk.N + tk.S + tk.W + tk.E)
main_window.mainloop()  #! 开启主循环,让窗口处于显示状态
  • Avatar photo

    宁妄

    一个热爱自然却被困在代码世界的“人”

    Related Posts

    pygame,填充效果

    纯色实心圆 再来个矩形的渐变

    函数的实际应用

    函数 格式: 关键字 函数名(): 举个例子,我要做一个小猫…

    One thought on “井字棋Tkinter 智能/智障

    1. import tkinter as tk
      from tkinter import *
      import random as r

      win=tk.Tk()
      win.geometry(‘490×545’)

      def start():
      d.grid_forget()
      c.grid_forget()
      for i in range(3):
      for j in range(3):
      button= tk.Button(win, text=””, height=10, width=22, command=lambda row=i, col=j:(row, col))
      button.grid(row=i, column=j)

      d=tk.Button(win,text=”开始”,height=13,width=26,command=start)
      c=tk.Button(win,text=”退出”,height=13,width=26,command=win.quit)

      d.grid(row=0, column=1)
      c.grid(row=0,column=2)
      e=[[0,0,0],[0,0,0],[0,0,0]]
      def zjxq(row,col):
      if e[row][col]==0:
      e[row][col]=”x”
      button = win.grid_slaves(row=row, column=col)[0]
      button.config(text=e[row][col])
      f=slz()
      if f!=0:
      dnxq()

      def dnxq():
      x=0
      for row in e:
      x+=row.count(0)
      if x > 0:
      while True:
      a = r.randint(0, 2)
      b = r.randint(0, 2)
      if e[a][b] == 0:
      break
      e[a][b] = “O”
      button = win.grid_slaves(row=a, column=b)[0]
      button.config(text=e[a][b])
      s =slz()
      if s==0:
      return 0
      def slz():
      w=None
      for row in e:
      if row.
      win.mainloop()

    回复 郑译 取消回复

    您的邮箱地址不会被公开。 必填项已用 * 标注