1625-5 王子昂 总结《2017年2月16日》 【连续第139天总结】
A.python 五子棋
B.昨天绘制好了背景棋盘,准备再添加15x15个棋子控件,当它们被点击时视为下棋事件
pack布局默认是从上到下的,可以自选fill=x选项来填充全部的横向空间,再在这个控件内新建若干个子控件来横向排列
这样就比较麻烦了,想起来了grid布局。它是通过网格管理的,自动调节网格大小,只需要输入row和column即可
注意使用grid方法是没有返回值的,因此不可以使用C=Tkinter.Canvas(top).grid()
并且此时新建的Canvas控件没有名字来称呼
新建15x15个控件并用grid布局放上以后,发现Tk的控件的背景是有颜色的……百度发现很多人也有类似问题,并且没有得到解决
那就回到原始思路,把背景棋盘绘制在每个小控件中,当被点击时在上面绘制棋子
绘制好了显示的时候发现控件与控件之间总是有空隙,虽然可以用ipadx/ipady来增大,但即使参数为0空隙也仍然存在,即不可避免
这样的棋盘看起来非常难受,找了半天也没有看到有如何消除间隙的方法
不能在每个事件点建立控件的话如何捕捉点击位置呢……
百度发现应该使用Tkinter的bind和event机制,可以获取当鼠标点击时的坐标……
重新写完了五子棋的大致框架以后,表层下子已经实验完毕,但当与记录数据的抽象二维数组连接起来以后就开始疯狂出错
纠结了几个小时以后突然想起来,我的二维数组创建方法是list=[[0]*15]*15,这似乎是一种浅拷贝方法,因为子列表的地址实际上仍然是相同的
p = [[]] * 20 for i in range(20): p[i] = [0] * 20这样才是真正的二维数组
之后只要加上判定胜负机制和换手即可
在判定游戏结束以后,应该进入“无法响应”的状态并等待用户确认是否重新开始
但是在进入mainloop循环以后,本质上每次下子都是被“单击”这个事件驱动的,并不是循环,这与C++是完全不同的。因此要中断事件驱动,就一定要停止这个过程。
但是没查到如何解除bind,对state属性赋值disabled也没有用,估计只是对文本框一类的输入有用,而绑定属于自定义
突发奇想试试对同一个事件重新bind,是会覆盖还是会并列呢
操作以后发现是覆盖,那就很简单了:结束以后覆盖掉原下子函数,等到确认重新开始后再次初始化并绑定上下子函数即可
#encoding:utf- import Tkinter UNIT=25#单位像素 #p = [[0] * 15] * 15 p = [[]] * 20 for i in range(20): p[i] = [0] * 20 u=1 top = Tkinter.Tk() board = Tkinter.Canvas(top, height=UNIT * 15, width=UNIT * 15,bg='white') hint=Tkinter.Label(top) def is_win(x,y): #判断是否胜利 print x,y for i in range(-4,1): #左下 for j in range(i,i+5): if(p[x+j][y+j]!=u): break else: return 1 for i in range(-4,1): #左 for j in range(i,i+5): if(p[x+j][y]!=u): break else: return 1 for i in range(-4,1): #左上 for j in range(i,i+5): if(p[x+j][y-j]!=u): break else: return 1 for i in range(-4,1): #下 for j in range(i,i+5): if(p[x][y+j]!=u): break else: return 1 return 0 def judge(x,y): if(p[x][y]!=0): return 2 else: p[x][y]=u return is_win(x,y) def restart(event): start() def call_back(event): global u x=(event.x)//UNIT*UNIT+13 y=(event.y)//UNIT*UNIT+13 flag=judge((x-13)/UNIT,(y-13)/UNIT) if(u==1): COLOR='black' else: COLOR='white' if(flag==0): board.create_oval(x-5,y-5,x+5,y+5,fill=COLOR) hint["text"]="" u = u * (-1) elif(flag==1): board.create_oval(x-5,y-5,x+5,y+5,fill=COLOR) print '结束'#结束游戏 hint["text"]=COLOR+"赢啦,游戏结束\n单击可重新开始" board.bind('<Button -1>',restart) elif(flag==2): print '占用'#提示:本点已被占用 hint["text"]="不可以在已经下过的点上再下了哟,请重新下子" def start(): global p global u hint["text"] = "" p = [[]] * 20 for i in range(20): p[i] = [0] * 20 u = 1 # 玩家1 board.create_rectangle(0,0,500,500,fill='white') for i in range(16):#绘制棋盘 board.create_line(UNIT*(i)-13,13,UNIT*(i)-13,UNIT*15-13) board.create_line(13,UNIT*(i)-13,UNIT*15-13,UNIT*(i)-13) for i,j in (4,12),(4,4),(12,4),(12,12),(8,8):#辅助点 board.create_oval((i)*UNIT-3-13,(j)*UNIT-3-13,(i)*UNIT+3-13,(j)*UNIT+3-13,fill='black') board.bind('<Button -1>', call_back) hint.grid(row=3, column=0) board.grid(row=0, column=0, rowspan=3) start() Tkinter.mainloop()
至此,本地五子棋程序已完全完成
下一步是对其的网络化。在那之前需要考虑一下是否要将其封装入一个类中呢
网络化的任务包括:服务器与客户端的连接;下子数据的传输;聊天系统;悔棋
C. 明日计划
python 五子棋网络化