井字棋游戏

1. 游戏创建

1.1导包

from tkinter import *
import numpy as np
import math
import tkinter.messagebox

1.2 窗口内容

1.2.1创建一个窗口

root = Tk()  # 窗口名称
root.title("井字棋 from Sun")

1.2.2 创建一个框架,将其放置在窗口中

Frame1 = Frame(root)  # 框架
Frame1.pack()

1.2.3 创建一个用来绘制九宫格的画布w1

w1 = Canvas(Frame1, width=580, height=580, bg="white")  # 创建一个画布(Canvas),设置大小
w1.pack()    # w1:画布

1.3 绘制九宫格

  使用create_line在画布上绘制九宫格。

for i in range(0, 4):

    w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560)  # 绘制竖线

    w1.create_line(20, i * 180 + 20, 560, i * 180 + 20)  # 绘制横线

运行结果:

1.4 定义一个全局变量

# 定义全局变量num

num = 0 # 记录点击的次数,用来决定点击后该画哪种图形

# 定义一个3X3的数组A

A = np.full((3, 3), 0) # 记录每个位置的图形

# 0表示空,1表示叉号,2表示圆圈。

1.5 定义一个鼠标事件

根据鼠标的点击在网格中绘制“X”和“O”

def dawn(event):

    global w1

    global num, A

    for i in range(0, 3):  # 确定被单击的网格单元格的行号。

        for j in range(0, 3):  # 确定被单击的网格单元格的行号。

            if 20 + j * 180 < event.y and event.y <= 20 + (j+1) * 180:

                break

        if 20 + i * 180 <= event.x and event.x <= 20 + (i+1) * 180:

            break

    if num % 2 == 0 and A[i][j] == 0:   # 如果当前玩家是 X并且该单元格为空,则绘制叉号。

         A[i][j] = 1   

1.6 创建图形“×”和“○”

1.6.1 创建“×”

# 使用create_line方法在指定位置绘制叉号。

        w1.create_line(110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),

                       110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)

        w1.create_line(110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),

                       110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)

        num += 1  # 增加点击次数。

1.6.2 创建“○”

# 使用create_oval方法在指定位置绘制圆圈。

  w1.create_oval(20 + 180 * i + 10, 20 + 180 * j + 10, 20 + 180 * (i + 1) - 10, 20 + 180 * (j + 1) - 10, width=5)

   num += 1

1.7 对弈结果:①“X”获胜  ②“O获胜”③ 平局

1.7.1 “O”获胜的所有可能性

  • 所有可能性:  ① 横向三个相邻单元格都包含 O。
  •                         ② 纵向三个相邻单元格都包含 O。
  •                         ③ 从左上角到右下角的对角线上的所有单元格都包含 O。
  •                         ④ 从右上角到左下角的对角线上的所有单元格都包含 O。

    

if (A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2):

     tkinter.messagebox.showinfo('Warning', '恭喜O获胜啦')

1.7.2 “X”获胜的所有可能性

  • 所有可能性:  ① 横向三个相邻单元格都包含 X。
    •                         ② 纵向三个相邻单元格都包含 X。
      •                         ③ 从左上角到右下角的对角线上的所有单元格都包含 X。
        •                         ④ 从右上角到左下角的对角线上的所有单元格都包含 X。
elif (A[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][2] == 1 or A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] ==A[2][2] == 1 or  [0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] == 1):

    tkinter.messagebox.showinfo('Warning', '恭喜X获胜啦')

1.7.3 平局的所有可能性

          每个棋子最多能走5步,当X走了5步时,则O只走了4步,所以XO加一起只能走9步,所以当没有棋子连在一起的时候,就该考虑是否已经走了9次,如果走了就此还没达到获胜条件时,那么这时候就是平局

    elif num == 9 and not (

        A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2 orA[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][2] == 1 or A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] == A[2][2] == 1 orA[0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] ==1):

     tkinter.messagebox.showinfo('Warning', 'woo平局啦!')

1.8 “退出”

1.8.1 退出的函数

def quit():

    root.quit()

1.8.2 退出的按钮

# 退出按钮

button1 = Button(root, text="退出", font=('微软雅黑', 15), command=quit)

button1.pack()

1.9 “重新开始”

1.9.1 重新开始的函数

def restart():

    global w1, num, A

    w1.delete("all")  # 清除画布上所有的东西

    for i in range(0, 4):

        w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560)

        w1.create_line(20, i * 180 + 20, 560, i * 180 + 20)

    num = 0

    A = np.full((3, 3), 0)



w1.bind("<Button -1>", dawn)

1.9.1 从新开始的按钮

# 重新开始按钮

button2 = Button(root, text="重新开始", font=('微软雅黑', 15), command=restart)

button2.pack()

2. 完整代码

from tkinter import *
import numpy as np
import math
import tkinter.messagebox

root = Tk()  # 窗口名称
root.title("井字棋 from Sun")
# root.geometry("600x600")
Frame1 = Frame(root)  # 框架
Frame1.pack()
w1 = Canvas(Frame1, width=580, height=580, bg="white")  # 创建一个画布(Canvas),设置大小
w1.pack()    # w1:画布

for i in range(0, 4):
    w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560)  # 绘制竖线
    w1.create_line(20, i * 180 + 20, 560, i * 180 + 20)  # 绘制横线

# 定义全局变量num
num = 0							# 记录点击的次数,用来决定点击后该画哪种图形
# 定义一个3X3的数组A
A = np.full((3, 3), 0)			# 记录每个位置的图形
# 0表示空,1表示叉号,2表示圆圈。

def dawn(event):
    global w1
    global num, A
    for i in range(0, 3):  # 确定被单击的网格单元格的行号。
        for j in range(0, 3):  # 确定被单击的网格单元格的行号。
            if 20 + j * 180 < event.y and event.y <= 20 + (j+1) * 180:
                break
        if 20 + i * 180 <= event.x and event.x <= 20 + (i+1) * 180:
            break
    if num % 2 == 0 and A[i][j] == 0:   # 如果当前玩家是 X并且该单元格为空,则绘制叉号。
        # 网格中的行 i 和列 j
        A[i][j] = 1   # 二维数组:A[i][j]
        # 使用create_line方法在指定位置绘制叉号。
        w1.create_line(110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),
                       110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)
        w1.create_line(110 + 180 * i + 45 * math.sqrt(2), 110 + 180 * j - 45 * math.sqrt(2),
                       110 + 180 * i - 45 * math.sqrt(2), 110 + 180 * j + 45 * math.sqrt(2), width=5)
        num += 1  # 增加点击次数。
    if num % 2 != 0 and A[i][j] == 0:   # 如果当前玩家是 O 并且该单元格为空,则绘制圆圈。
        A[i][j] = 2
        # 使用create_oval方法在指定位置绘制圆圈。
        w1.create_oval(20 + 180 * i + 10, 20 + 180 * j + 10, 20 + 180 * (i + 1) - 10, 20 + 180 * (j + 1) - 10, width=5)
        num += 1
# 0表示空,1表示叉号,2表示圆圈  # \ :换行
    if (A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][
        2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==
            A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2):
            # 从左上角到右下角的对角线上的所有单元格都包含 O or 从右上角到左下角的对角线上的所有单元格都包含 O
        tkinter.messagebox.showinfo('Warning', '恭喜O获胜啦')

    elif (A[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][
        2] == 1 or A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] ==
          A[2][2] == 1 or
            A[0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] == 1):
        tkinter.messagebox.showinfo('Warning', '恭喜X获胜啦')

    elif num == 9 and not (
        A[0][0] == A[0][1] == A[0][2] == 2 or A[1][0] == A[1][1] == A[1][2] == 2 or A[2][0] == A[2][1] == A[2][
        2] == 2 or A[0][0] == A[1][0] == A[2][0] == 2 or A[0][1] == A[1][1] == A[2][1] == 2 or A[0][2] == A[1][2] ==
        A[2][2] == 2 or A[0][0] == A[1][1] == A[2][2] == 2 or A[2][0] == A[1][1] == A[0][2] == 2 or
        A[0][0] == A[0][1] == A[0][2] == 1 or A[1][0] == A[1][1] == A[1][2] == 1 or A[2][0] == A[2][1] == A[2][2] == 1 or
        A[0][0] == A[1][0] == A[2][0] == 1 or A[0][1] == A[1][1] == A[2][1] == 1 or A[0][2] == A[1][2] == A[2][2] == 1 or
        A[0][0] == A[1][1] == A[2][2] == 1 or A[2][0] == A[1][1] == A[0][2] == 1
    ):
        tkinter.messagebox.showinfo('Warning', 'woo平局啦!')

def restart():
    global w1, num, A
    w1.delete("all")  # 清除画布上所有的东西
    for i in range(0, 4):
        w1.create_line(i * 180 + 20, 20, i * 180 + 20, 560)
        w1.create_line(20, i * 180 + 20, 560, i * 180 + 20)
    num = 0
    A = np.full((3, 3), 0)

w1.bind("<Button -1>", dawn)
def quit():
    root.quit()
# 退出按钮
button1 = Button(root, text="退出", font=('微软雅黑', 15), command=quit)
button1.pack()
# 重新开始按钮
button2 = Button(root, text="重新开始", font=('微软雅黑', 15), command=restart)
button2.pack()

root.mainloop()

3. 运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/577916.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何进行域名解析?如何清理DNS缓存?(附源码)

目录 1、什么是域名&#xff1f; 2、为什么使用域名&#xff1f; 3、域名解析的完整流程 4、调用gethostbyname系统接口将域名解析成IP地址 5、为什么需要清理系统DNS缓存&#xff1f; 6、使用cmd命令清理DNS缓存 7、通过代码去清除系统DNS缓存 C软件异常排查从入门到精…

图像分类导论:从模型设计到端到端

书籍&#xff1a;An Introduction to Image Classification&#xff1a;From Designed Models to End-to-End Learning 作者&#xff1a;Klaus D. Toennies 出版&#xff1a;Springer Singapore 书籍下载-《图像分类导论》图像分类的传统方法包括在特征空间中进行特征提取和…

怎么提高职场辩论的口才能力的方法

提高职场辩论的口才能力是一个综合而复杂的过程&#xff0c;涉及知识积累、技巧学习、实践锻炼等多个方面。以下是关于如何提高职场辩论口才能力的详细分析和建议。 一、引言 在职场中&#xff0c;良好的口才能力对于个人职业发展具有重要意义。优秀的口才不仅能够提升个人的…

日志分析简单总结

1、分析日志的目的 误报&#xff1a;不是攻击而上报成攻击 漏报&#xff1a;是攻击而没有防御的情况 日志分析可以判断是否误判或者漏判&#xff0c;可以溯源攻击行为 在护网作为防守方必备的技能&#xff08;分析NGAF和态势感知&#xff0c;发现异常&#xff09; 2、攻击出现…

C++进阶--智能指针

智能指针的概念 智能指针是C中的一个重要概念&#xff0c;用于管理动态分配的对象内存。它是一个类模板&#xff0c;通过封装原始指针&#xff0c;并在对象生命周期结束时自动释放内存&#xff0c;从而避免了内存泄漏和资源管理的繁琐工作。 C标准库提供了多种常见的智能指针…

el-date-picker 禁用时分秒选择(包括禁用下拉框展示)

2024.04.26今天我学习了对el-date-picker进行禁用时分秒&#xff0c; 在使用el-date-picker组件的时候&#xff0c;我们有可能遇到需要把时分秒的时间固定&#xff0c;然后并且不能让他修改&#xff1a; 1714120999296 比如右上角的这个时间&#xff0c;我们要给它固定是‘08:…

Open3D(C++) 最小二乘拟合多项式曲线

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 多项式曲线表示为: p ( x ) =

使用Screenshots安装Fedora 40版本详细教程

Fedora 40是Fedora操作系统的最新版本&#xff0c;于 2024 年 4 月 23 日发布&#xff0c;是一个社区支持的 Linux 发行版&#xff0c;以其创新功能、领先技术和活跃的社区支持而闻名。 在本指南中&#xff0c;我们将引导您完成安装Fedora 40 Server的分步过程&#xff0c;确保…

SystemUI KeyButtonView setDarkIntensity 解析

继承自 ImageView KeyButtonDrawable intensity为0时按键颜色为白色。 intensity为1时黑色为的调用堆栈&#xff1a; java.lang.NullPointerException: Attempt to invoke virtual method int java.lang.String.length() on a null object referenceat com.android.systemui.…

Linux网络编程---多路I/O转接服务器(一)

多路I/O转接服务器 多路IO转接服务器也叫做多任务IO服务器。该类服务器实现的主旨思想是&#xff0c;不再由应用程序自己监视客户端连接&#xff0c;取而代之由内核替应用程序监视文件。 主要使用的方法有三种&#xff1a;select、poll、epoll 一、select多路IO转接 让内核去…

Java 网络编程之TCP(三):基于NIO实现服务端,BIO实现客户端

前面的文章&#xff0c;我们讲述了BIO的概念&#xff0c;以及编程模型&#xff0c;由于BIO中服务器端的一些阻塞的点&#xff0c;导致服务端对于每一个客户端连接&#xff0c;都要开辟一个线程来处理&#xff0c;导致资源浪费&#xff0c;效率低。 为此&#xff0c;Linux 内核…

边缘计算在视频监控领域的应用

一、边缘计算在视频监控领域的应用 运用边缘计算解决视频监控问题&#xff0c;可以带来许多优势。以下是一些具体的应用示例&#xff1a; 实时分析与处理&#xff1a;在视频监控系统中&#xff0c;边缘计算盒子可以实时处理和分析视频流&#xff0c;实现对监控画面的智能识别…

BGP选路实验(锐捷)---AS-PATH选路

实验拓扑图 基本配置如图所示 要求&#xff1a;R8上利用loopback口建立多个分段ip&#xff0c;利用bgp选路原则让双网段数据通过R6转发&#xff0c;单网段数据通过R7转发&#xff0c;这里添加as-path号建议添加自己的bgp所属的as号&#xff0c;以防止修改as-path后影响as-path…

❤️新版Linux零基础快速入门到精通——第二部分❤️

❤️新版Linux零基础快速入门到精通——第二部分❤️ 非科班的我&#xff01;Ta&#xff01;还是来了~~~2. Linux基础命令2.1 类Unix系统目录结构2.2 Linux目录结构2.2.1 Linux用户目录2.2.2 Linux目录练习 2.3 Linux 命令入门2.3.1 命令基础2.3.1.1 help2.3.1.2 man(manual)2.…

Windows Vscode ModuleNotFoundError: No module named

故障现象&#xff1a; Windows Vscode 经常会遇到模块路径查找失败的异常。 如运行2_from_import_test.py后&#xff0c;报错&#xff1a; 发生异常: ModuleNotFoundError No module named programmer File "D:\leolab\programmer\2_from_import_test.py", line 8…

虚拟机VMware下ROS Neotic(Ubuntu 20.04)下安装OpenCV

一、ROS安装 ROS的官方安装步骤&#xff1a; 1、noetic / Ubuntu 20.04 &#xff1a; http://wiki.ros.org/noetic/Installation/Ubuntu 2、melodic / Ubuntu 18.04&#xff1a; http://wiki.ros.org/melodic/Installation/Ubuntu 3、kinetic / Ubuntu 16.04&#xff1a; http:…

C语言:一维数组、二维数组、字符数组介绍

数组 介绍一维数组定义应用方法初始化 举例示例结果 二维数组定义应用方法初始化 举例示例结果 字符数组定义应用方法初始化 举例示例结果分析 介绍 在C语言中&#xff0c;数组是一种基本的数据结构&#xff0c;用于存储一系列相同类型的数据。数组可以是多维的&#xff0c;最…

phpstorm 设置变量,自动补全代码

效果 进入设置->实时模板->PHP->添加 添加动态模板->完善写法 定义->选择PHP->应用就行

什么是宏观经济的先行指标、同步指标与滞后指标

宏观经济波动是一种周期性的繁荣、衰退、萧条、复苏循环变化过程&#xff0c;在这种变动中&#xff0c;不同经济指标的变动并非总与宏观经济运行步调一致。按统计指标变动轨迹与宏观经济变动轨迹的时间关系,可以将其划分为先行指标、同步指标和滞后指标。 一、概念和作用 先行…

JetBrains CLion v2023.3.4 激活版 (C/C++ 集成开发IDE)

前言 JetBrains CLion是一款跨平台的C/C集成开发环境&#xff0c;由JetBrains公司推出。其最新版本支持C14几乎完全&#xff0c;并初步支持C17&#xff0c;使得编写代码更加便捷。CLion还提供了Disassembly view&#xff08;反汇编视图&#xff09;&#xff0c;即使没有源代码…