## 3. 重点模块介绍

### 3.0 数据结构

Python 字典是无序的，但是可以通过 ​​collections.OrderedDict()​​ 方法构建有序字典，之所以需要有序，是因为该字典保存了落子双方的顺序，有序的保证是必须的。有序字典会严格保证遍历顺序和添加顺序一致。

>>> import collections>>> x = collections.OrderedDict()>>> x[1] = 'a'>>> x[2] = 'b'>>> x[3] = 'c'>>> xOrderedDict([(1, 'a'), (2, 'b'), (3, 'c')])

>>> for k, v in x.items():...     print(k, v)...1 a2 b3 c

### 3.1 绘制棋子模块

rate_piece = 0.45 # 棋子占格子大小的百分比grid = 40 # 每个格子的大小

def drawPiece(canvas, coordinate:tuple)->None:    """    coordinate: (x, y)    WB: white/black    需要完成坐标映射    """    global user    if coordinate[0] % grid >= rate_piece*grid or coordinate[1] % grid >= rate_piece*grid or coordinate[0] >= 16*grid or coordinate[1] >= 16*grid or coordinate[0] < grid or coordinate[1] < grid:        return None    x = coordinate[0] // grid    y = coordinate[1] // grid        if len(chessBoardDict) == 0:        user = 'white'        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid,  width=1, fill="black")        print("落子: %s (%d, %d)" % ("black", x, y))        return [(x, y), "black"]    color = -1    for k, v in chessBoardDict.items():        _, color = k, v    if color == "black":        user = 'black'        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="white")        print("落子: %s (%d, %d)" % ("white", x, y))        return [(x, y), "white"]    else:        user = 'white'        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="black")        print("落子: %s (%d, %d)" % ("black", x, y))        return [(x, y), "black"]

### 3.2 绘制棋盘模块

def drawBoard():    # 界面对象的基本参数设置    root = tk.Tk()    root.title("五子棋")    # root.geometry('335x265+250+250')    # 设置界面是否可以随意拉伸    root.resizable(False, False)    canvas = tk.Canvas(root, bg='#F9D65B', height=grid*16, width=grid*16)    canvas.grid(row=0, column=0)    label = tk.Label(root, text=user, font=('Times', 16)).grid(row=1, column=0)    # 绘制线    canvas.create_rectangle(grid/2, grid/2, 16*grid-grid/2, 16*grid-grid/2, width=2)    for i in range(1, 16):        canvas.create_line(grid, i*grid, 15*grid, i*grid, fill='black')        canvas.create_line(i*grid, grid, i*grid, 15*grid, fill='black')    # 绘制点    canvas.create_oval(8*grid+rate*grid, 8*grid+rate*grid, 8*grid-rate*grid, 8*grid-rate*grid, fill="black")    canvas.create_oval(12*grid+rate*grid, 12*grid+rate*grid, 12*grid-rate*grid, 12*grid-rate*grid, fill="black")    canvas.create_oval(4*grid+rate*grid, 4*grid+rate*grid, 4*grid-rate*grid, 4*grid-rate*grid, fill="black")    canvas.create_oval(12*grid+rate*grid, 4*grid+rate*grid, 12*grid-rate*grid, 4*grid-rate*grid, fill="black")    canvas.create_oval(4*grid+rate*grid, 12*grid+rate*grid, 4*grid-rate*grid, 12*grid-rate*grid, fill="black")    # 鼠标事件    def mouseEvent(event):        # print(f"({event.x}, {event.y})")        value = drawPiece(canvas, (event.x, event.y))        tk.Label(root, text=user, font=('Times', 16)).grid(row=1,column=0)        if value != None:            k, v = value            chessBoardDict[k] = v            judge()            # print(chessBoardDict)            # global k            # k += 1    # canvas.bind("<Button-1>", lambda event:mouseEvent(event, "white" if k % 2 == 0 else "black"))    canvas.bind("<Button-1>", lambda event:mouseEvent(event))        root.mainloop()

### 3.3. 胜负判定模块

def judge():    global chessBoardDict    # chessBoardDict.pop()    for k, v in chessBoardDict.items():        coordinate, color = k, v    # print("color", color)    if color == "black":        anti_color = "white"    else:        anti_color = "black"    # print("判断：", chessBoardDict)    points = [0, 0, 0, 0, 0, 0, 0, 0]    for k in range(5):        if (coordinate[0], coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] - k)] == color:            points[0] += 1        else:            break    for k in range(5):        if (coordinate[0] + k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] - k)] == color:            points[1] += 1        else:            break    for k in range(5):        if (coordinate[0] + k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1])] == color:            points[2] += 1        else:            break    for k in range(5):        if (coordinate[0] + k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] + k)] == color:            points[3] += 1        else:            break    for k in range(5):        if (coordinate[0], coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] + k)] == color:            points[4] += 1        else:            break    for k in range(5):        if (coordinate[0] - k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] + k)] == color:            points[5] += 1        else:            break    for k in range(5):        if (coordinate[0] - k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1])] == color:            points[6] += 1        else:            break    for k in range(5):        if (coordinate[0] - k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] - k)] == color:            points[7] += 1        else:            break    if 5 in points:        messagebox.showinfo(title="结果", message="%s 获胜！" % color)        print(color, "win")

### 3.4 tkinter 知识点

1. 布局

canvas = tk.Canvas(root, bg='#F9D65B', height=grid*16, width=grid*16)canvas.grid(row=0, column=0)label = tk.Label(root, text=user, font=('Times', 16)).grid(row=1,column=0)

from tkinter import *tk=Tk()#标签控件，显示文本和位图，展示在第一行Label(tk,text="First").grid(row=0,sticky=E)#靠右Label(tk,text="Second").grid(row=2,sticky=W)#第二行，靠左#输入控件Entry(tk).grid(row=0,column=1)Entry(tk).grid(row=2,column=1)#主事件循环mainloop()

grid 样例

2. 鼠标事件

# 鼠标事件    def mouseEvent(event):        print(f"({event.x}, {event.y})")    canvas.bind("<Button-1>", lambda event:mouseEvent(event))

'''鼠标点击事件<Button-1>  鼠标左键<Button-2>   鼠标中间键（滚轮）<Button-3>  鼠标右键<Double-Button-1>   双击鼠标左键<Double-Button-3>   双击鼠标右键<Triple-Button-1>   三击鼠标左键<Triple-Button-3>   三击鼠标右键'''

3. canvas 画布操作

import tkinter as tk root = tk.Tk() w = tk.Canvas(root, width =200, height = 100)w.pack() #画一条黄色的横线w.create_line(0, 50, 200, 50, fill = "yellow")#画一条红色的竖线（虚线）w.create_line(100, 0, 100, 100, fill = "red", dash = (4, 4))#中间画一个蓝色的矩形w.create_rectangle(50, 25, 150, 75, fill = "blue") root.mainloop()

import tkinter as tk root = tk.Tk() w = tk.Canvas(root, width =200, height = 100)w.pack() w.create_rectangle(40, 20, 160, 80, dash = (4, 4))w.create_oval(40, 20, 160, 80, fill = "pink") w.create_text(100, 50, text = "Python") root.mainloop()

## 4. 开发运行环境

### 4.1 开发环境

PyCharm 2020.2 (Community Edition)Build #PC-202.6397.98, built on July 28, 2020Runtime version: 11.0.7+10-b944.20 amd64VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.Windows 10 10.0GC: ParNew, ConcurrentMarkSweepMemory: 1902MCores: 12

### 4.2 软件所涉及到的开源库

import tkinter as tkfrom tkinter import messageboximport collections

 开源库 说明 tkinter Python3提供的界面设计库 collections Python内建的一个集合模块,提供了许多有用的集合类

## 源码

# 五子棋# @author: jiamingimport tkinter as tkfrom tkinter import messageboximport collectionsrate = 0.1 # 黑点占格子大小的百分比rate_piece = 0.45 # 棋子占格子大小的百分比grid = 40 # 每个格子的大小color = (249, 214, 91) # 棋盘颜色user = 'black'# k = 0chessBoardDict = collections.OrderedDict()  #将普通字典转换为有序字典{} {(x, y):"black"}def judge():    global chessBoardDict    # chessBoardDict.pop()    for k, v in chessBoardDict.items():        coordinate, color = k, v    # print("color", color)    if color == "black":        anti_color = "white"    else:        anti_color = "black"    # print("判断：", chessBoardDict)    points = [0, 0, 0, 0, 0, 0, 0, 0]    for k in range(5):        if (coordinate[0], coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] - k)] == color:            points[0] += 1        else:            break    for k in range(5):        if (coordinate[0] + k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] - k)] == color:            points[1] += 1        else:            break    for k in range(5):        if (coordinate[0] + k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1])] == color:            points[2] += 1        else:            break    for k in range(5):        if (coordinate[0] + k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] + k)] == color:            points[3] += 1        else:            break    for k in range(5):        if (coordinate[0], coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] + k)] == color:            points[4] += 1        else:            break    for k in range(5):        if (coordinate[0] - k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] + k)] == color:            points[5] += 1        else:            break    for k in range(5):        if (coordinate[0] - k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1])] == color:            points[6] += 1        else:            break    for k in range(5):        if (coordinate[0] - k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] - k)] == color:            points[7] += 1        else:            break    if 5 in points:        messagebox.showinfo(title="结果", message="%s 获胜！" % color)        print(color, "win")def drawPiece(canvas, coordinate:tuple)->None:    """    coordinate: (x, y)    WB: white/black    需要完成坐标映射    """    global user    if coordinate[0] % grid >= rate_piece*grid or coordinate[1] % grid >= rate_piece*grid or coordinate[0] >= 16*grid or coordinate[1] >= 16*grid or coordinate[0] < grid or coordinate[1] < grid:        return None    x = coordinate[0] // grid    y = coordinate[1] // grid        if len(chessBoardDict) == 0:        user = 'white'        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid,  width=1, fill="black")        print("落子: %s (%d, %d)" % ("black", x, y))        return [(x, y), "black"]    color = -1    for k, v in chessBoardDict.items():        _, color = k, v    if color == "black":        user = 'black'        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="white")        print("落子: %s (%d, %d)" % ("white", x, y))        return [(x, y), "white"]    else:        user = 'white'        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="black")        print("落子: %s (%d, %d)" % ("black", x, y))        return [(x, y), "black"]def drawBoard():    # 界面对象的基本参数设置    root = tk.Tk()    root.title("五子棋")    # root.geometry('335x265+250+250')    # 设置界面是否可以随意拉伸    root.resizable(False, False)    canvas = tk.Canvas(root, bg='#F9D65B', height=grid*16, width=grid*16)    canvas.grid(row=0, column=0)    label = tk.Label(root, text=user, font=('Times', 16)).grid(row=1, column=0)    # 绘制线    canvas.create_rectangle(grid/2, grid/2, 16*grid-grid/2, 16*grid-grid/2, width=2)    for i in range(1, 16):        canvas.create_line(grid, i*grid, 15*grid, i*grid, fill='black')        canvas.create_line(i*grid, grid, i*grid, 15*grid, fill='black')    # 绘制点    canvas.create_oval(8*grid+rate*grid, 8*grid+rate*grid, 8*grid-rate*grid, 8*grid-rate*grid, fill="black")    canvas.create_oval(12*grid+rate*grid, 12*grid+rate*grid, 12*grid-rate*grid, 12*grid-rate*grid, fill="black")    canvas.create_oval(4*grid+rate*grid, 4*grid+rate*grid, 4*grid-rate*grid, 4*grid-rate*grid, fill="black")    canvas.create_oval(12*grid+rate*grid, 4*grid+rate*grid, 12*grid-rate*grid, 4*grid-rate*grid, fill="black")    canvas.create_oval(4*grid+rate*grid, 12*grid+rate*grid, 4*grid-rate*grid, 12*grid-rate*grid, fill="black")    # 鼠标事件    def mouseEvent(event):        # print(f"({event.x}, {event.y})")        value = drawPiece(canvas, (event.x, event.y))        tk.Label(root, text=user, font=('Times', 16)).grid(row=1,column=0)        if value != None:            k, v = value            chessBoardDict[k] = v            judge()            # print(chessBoardDict)            # global k            # k += 1    # canvas.bind("<Button-1>", lambda event:mouseEvent(event, "white" if k % 2 == 0 else "black"))    canvas.bind("<Button-1>", lambda event:mouseEvent(event))        root.mainloop()if __name__ == "__main__":    drawBoard()'''鼠标点击事件<Button-1>  鼠标左键<Button-2>   鼠标中间键（滚轮）<Button-3>  鼠标右键<Double-Button-1>   双击鼠标左键<Double-Button-3>   双击鼠标右键<Triple-Button-1>   三击鼠标左键<Triple-Button-3>   三击鼠标右键'''