170216

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 五子棋网络化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值