python+pygame实现五子棋人机对战之三

上回讲过:

python+pygame实现五子棋人机对战之一

python+pygame实现五子棋人机对战之二

界面已经有了,并且可以支持鼠标操作选择菜单和人机对战开始下棋了,那电脑是如何应手落子呢?以下内容是通用的类,全部放在utils.py中

四、

最常见的基本棋型大体有以下几种:连五,活四,冲四,活三,眠三,活二,眠二了,下面简要讲解一下:

4.1 连五:五颗同色棋子连在一起

4.2 活四:由4枚同色棋子形成的两端没有对方棋子的四枚棋子

4.3 冲四一(连四):由4枚同色棋子形成的一端有对方棋子的四枚棋子

4.4 冲四二(跳四):由4枚同色棋子形成的中间没有对方棋子的四枚棋子。

4.5 眠四:由4枚同色棋子形成的两端有对方棋子的4枚棋子。  不能成五的四连。

相对比活四来说,冲四的威胁性就小了很多,此时,防守方只要跟着防守在那个唯一的连五点上,冲四就没法形成连五。

4.6 活三一(连三):由3枚同色棋子形成连三、跳三。  再走一着可以形成活四的三。 两端都是威胁的活三。简称“连三”。

4.7 活三二(跳三):由3枚同色棋子形成的中间没有对方棋子的三枚棋子。中间夹有一个威胁的活三。简称“跳三”。

4.8 眠三:由3枚同色棋子形成的两端有对方棋子的3枚棋子。  即再走一着可以形成冲四的三。眠三的形状是很丰富的。眠三的棋型与活三的棋型相比,危险系数下降不少,因为眠三棋型即使不去防守,下一手它也只能形成冲四,而对于单纯的冲四棋型,我们是可以防守住的。

活三可以形成眠三,但也能够形成活四。眠三只能够形成冲四。

4.9 活二 :由2枚同色棋子形成的连二(由2枚同色棋子连在一起形成的两头没有对方棋子的2枚棋子。)、跳二(由2枚同色棋子形成的中间没有对方棋子的2枚棋子。)、大跳二(中间有两个空白位置的跳二)。

4.10 眠二 :由2枚同色棋子形成的两端有对方棋子的2枚棋子。是能够形成眠三的二。

               

对于棋盘上每一个交叉点,会有8个方向连成五子的可能性,那么我们就利用算法算出所有的可能性,并根据它成五的概率给它打分,这样,得分最高的就是最好的落子点。

如何去实现呢?首先我们在8个方向上将其抽象成坐标的加减,例如水平向右,那么x+1,y不变,向右上,则x+1,y+1 .按正下方开始,逆时针8个方向就形成下面的数据结构:

directions = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]

 获取当前坐标的各个方向上棋子属性,返回1代表白棋,返回2代表黑棋,返回0代表没有棋,返回5表示在棋盘外。

from params import Params

rows = int(Params.get('ROWS'))
blocksize = int(Params.get('blockSize'))
width = int(Params.get('WIDTH'))
height = int(Params.get('HEIGHT'))

# 获取当前坐标的各个方向上棋子属性,返回1代表白棋,返回2代表黑棋,返回0代表没有棋,返回5表示在棋盘外
def getpointpiece(_mapchess,pos, src, offset):
    # 8个方向
    directions = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]
    x1, y1 = pos
    x1 = x1 + directions[src - 1][0] * offset * blocksize
    y1 = y1 + directions[src - 1][1] * offset * blocksize
    if x1 > 588 or y1 > 588 or x1 < 28 or y1 < 28:
        return 5
    else:
        return _mapchess[str(x1) + ',' + str(y1)]

再加上刚才分析的五子棋的基本棋型,可以设计出一个打分算法:

from params import Params

rows = int(Params.get('ROWS'))
blocksize = int(Params.get('blockSize'))
width = int(Params.get('WIDTH'))
height = int(Params.get('HEIGHT'))

# 判断每个点的value,用来排序该点下棋的可行性
def pointvalue(_mapchess, pos, flag1, flag2):
    value = 0    #加权值
    for i in range(1, 9):  #8个方向
        # 11111   连五
        if getpointpiece(_mapchess,pos, i, 1) == flag1 and \
                getpointpiece(_mapchess,pos, i, 2) == flag1 and \
                getpointpiece(_mapchess,pos, i, 3) == flag1 and \
                getpointpiece(_mapchess,pos, i, 4) == flag1 and \
                getpointpiece(_mapchess,pos, i, 5) == flag1:
            value += 1000000
        # *1111_ 活四
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == flag1 and \
                getpointpiece(_mapchess, pos, i, 5) == 0:
            value += 50000
        # *11112 冲四1,冲四指加一个点就是连五,比活四威力小得多
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == flag1 and \
                getpointpiece(_mapchess, pos, i, 5) == flag2:
            value += 30000
        # 1*111 冲四2
        if getpointpiece(_mapchess, pos, i, -1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1:
            value += 30000
        # 11*11 冲四3
        if getpointpiece(_mapchess, pos, i, -2) == flag1 and \
                getpointpiece(_mapchess, pos, i, -1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1:
            value += 30000
        # *111_ 活三1,活三可以形成活四的三
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == 0:
            value += 20000
        # *1_11_ 活三2
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == flag1 and \
                getpointpiece(_mapchess, pos, i, 5) == 0:
            value += 20000
        # *1112 眠三1  眠三是只能形成冲四的三
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == flag2:
            value += 15000
        # _1_112 眠三2
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == flag1 and \
                getpointpiece(_mapchess, pos, i, 5) == flag2:
            value += 15000
        # _11_12 眠三3
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == 0 and \
                getpointpiece(_mapchess, pos, i, 4) == flag1 and \
                getpointpiece(_mapchess, pos, i, 5) == flag2:
            value += 15000
        # 1__11 眠三4
        if getpointpiece(_mapchess, pos, i, -1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 1) == 0 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1:
            value += 15000
        # 1_1_1 眠三5
        if getpointpiece(_mapchess, pos, i, -1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1:
            value += 15000
        # 2_111_2 眠三6
        if getpointpiece(_mapchess, pos, i, -1) == flag2 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == 0 and \
                getpointpiece(_mapchess, pos, i, 5) == flag2:
            value += 15000
        # __11__ 活二1  活二能够形成活三的二
        if getpointpiece(_mapchess, pos, i, -1) == 0 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == 0 and \
                getpointpiece(_mapchess, pos, i, 4) == 0:
            value += 10000
        # _1_1_ 活二2
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == 0:
            value += 10000
        # 211__ 眠二1 ,能够形成眠三的二
        if getpointpiece(_mapchess, pos, i, -1) == flag2 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == flag1 and \
                getpointpiece(_mapchess, pos, i, 3) == 0 and \
                getpointpiece(_mapchess, pos, i, 4) == 0 and \
                getpointpiece(_mapchess, pos, i, 5) == 0:
            value += 1000
        #21_1__ 眠二2
        if getpointpiece(_mapchess, pos, i, -1) == flag2 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == flag1 and \
                getpointpiece(_mapchess, pos, i, 4) == 0 and \
                getpointpiece(_mapchess, pos, i, 5) == 0:
            value += 1000
        #21__1_ 眠二3
        if getpointpiece(_mapchess, pos, i, -1) == flag2 and \
                getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == 0 and \
                getpointpiece(_mapchess, pos, i, 4) == flag1 and \
                getpointpiece(_mapchess, pos, i, 5) == 0:
            value += 1000
        #*1___1 眠二4
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == 0 and \
                getpointpiece(_mapchess, pos, i, 4) == 0 and \
                getpointpiece(_mapchess, pos, i, 5) == flag1:
            value += 1000
        # *1__
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0 and \
                getpointpiece(_mapchess, pos, i, 3) == 0:
            value += 30
        # *1_
        if getpointpiece(_mapchess, pos, i, 1) == flag1 and \
                getpointpiece(_mapchess, pos, i, 2) == 0:
            value += 20
        # *1
        if getpointpiece(_mapchess, pos, i, 1) == flag1:
            value += 10
    return value

# 获取当前坐标的各个方向上棋子属性,返回1代表白棋,返回2代表黑棋,返回0代表没有棋,返回5表示在棋盘外
def getpointpiece(_mapchess,pos, src, offset):
    # 8个方向
    directions = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]
    x1, y1 = pos
    x1 = x1 + directions[src - 1][0] * offset * blocksize
    y1 = y1 + directions[src - 1][1] * offset * blocksize
    if x1 > 588 or y1 > 588 or x1 < 28 or y1 < 28:
        return 5
    else:
        return _mapchess[str(x1) + ',' + str(y1)]

这样就可以实现:当人下了棋后,电脑通过这个算法找出最有利的落子点,然后就在那里下棋。

注:本程序只是提供一个思路而已,并不是最优解。代码中value值可以自行修改,算法可以自己再设计,例如可以假如双活三之类的必须防御的应手。

如何判断胜负呢?待续。。。

python+pygame实现五子棋人机对战之四

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值