python3 井字棋 GUI - 人机对战、机器对战
功能
- GUI界面
- 人机对战(可选择机器先走)
- 机器对战(50局)
流程图
内核
棋盘
[0][1][2]
[3][4][5]
[6][7][8]
最佳下棋顺序:
best_way = [4,0,2,6,8,1,3,5,7]
估价函数(以X为对象)
- 可以赢的行数 +1
- 可以赢的行数上有自己的棋子 +2
- 可导致自己赢 +2
- 可导致对手赢 -2
判断赢局
win_chess = [[0,4,8],[2,4,6],[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8]]
人机对战流程
人(X)点击某个格子,触发绑定事件
- 判断该格子是否有子,无子继续
- 设置该格子为
1
- 判断X是否赢了,没有继续,有X赢
- 判断棋盘是否无子可下,有继续,没有平局
- 轮到机器下棋
- 判断O是否差一子便可赢,有则对应格子,无则继续
- 判断O是否处于危险状态,即对方只差一子赢棋,有则选择该格子,无则继续
- 机器选择最佳格子
- 判断输赢并判断是有无子可下,循环
机器对战流程
- 随机产生先下棋者
- 第一颗棋子随机下
- 各自判断最佳走法
- 判断输赢即棋盘是否无子可下
- 循环
总结
1. 学习了python threading库的用法
线程的使用:
id = 1
th = []
for i in range(50):
id = id * -1
try:
th.append(threading.Thread(target=run,args=(i,id)))
th[i].start()
except Exception as e:
print(e)
i = i - 1
2. 学习了python tkinter库的用法
tkinter的mianloop做为主线程尽量避免被阻塞,以免界面卡死
创建窗口:
top = tk.Tk()#创建窗口
top.title('井字棋 -> Fighting')#标题
top.geometry("300x300")#大小
top.resizable()#可改变大小
创建Frame:
frame_top = tk.Frame(top)#top是上层
创建按钮:
tk.Button(frame_top,text='人机对决',command=but1).pack(side=tk.LEFT)
创建labe:
label1 = tk.Label(frame_cont,justify=tk.CENTER,textvariable=show_str,font=("幼圆",30))
显示可刷新变量:
tips = tk.StringVar(top) #提示信息
tips.set("")#设置显示内容
label_bottom = tk.Label(frame_bot,justify=tk.CENTER,textvariable=tips,font=("幼圆",20),padx=0)#设置显示的值为tips
绑定事件及解绑:
l0.bind("<Button-1>", touch_l0)#绑定
l0.unbind("<Button-1>")#解绑
布局:
l0.pack(side=tk.LEFT)
frame_top.pack()
开启消息循环:
top.mainloop()
代码
运行截图
待修复问题
若产生平局会导致该线程卡死 , 即count_z无法计算,并造成卡顿- 程序优化不够,代码较为杂乱
上一个问题导致通过GUI关闭程序会有进程仍在跑,需要用任务管理器关闭- 先走角落易赢,机器走法单一,即下面情况
X _ O
O O _
X X X
补充:之前之所以会卡,是因为在