让电脑变得更聪明——用python实现五子棋游戏

作为经典的棋类游戏,五子棋深受大众喜爱,但如果仅实现人与人的博弈,那程序很简单,如果要实现人机对战,教会计算机如何战胜人类,那就不是十分容易的事了。本文我们先从简单入手,完成五子棋游戏的基本操作,然后再尝试引入一些实现人工智能的编程方法和技巧,从而实现人机博弈。

1.创建棋盘和棋子

对于棋类游戏来说,游戏的场景就是下棋的棋盘,而游戏的主要角色就是棋子。接下来我们开始创建棋盘和棋子。

1.1绘制棋盘

五子棋的棋盘可以看成是一个1818的网格,他由19条竖线和19条横线(包含边界)构成,直线的交叉处就下棋子的位置。这里,我们用1818个棕色格子来填满棋盘,每个格子的间距就是棋盘的纵横交错的线条,python可以实现该功能的库有pgzero、tkinter。这里我们用pygame


    # 创建窗口,背景为棕色
 screen = pygame.display.set_mode((615, 615))
 pygame.display.set_caption('五子棋')
 screen.fill("#DD954F")
#创建外边框

 a = pygame.Surface((603, 603), flags=pygame.HWSURFACE)
 a.fill(color='#121010')
 b = pygame.Surface((585, 585), flags=pygame.HWSURFACE)
 b.fill(color="#DD954F")
 c = pygame.Surface((579, 579), flags=pygame.HWSURFACE)
 c.fill(color='#121010')

 #
 # d = pygame.Surface((576, 576), flags=pygame.HWSURFACE)
 # d.fill(color="#DD954F")
 #棋盘格子
 e = pygame.Surface((31, 31), flags=pygame.HWSURFACE)
 e.fill(color="#DD954F")
 screen.blit(a, (6.5, 6.5))
 screen.blit(b, (15, 15))
 screen.blit(c, (18, 18))
 for j in range(18):
     for i in range(18):
         #起点是20,间隔是32,每个格子大小31,所以格子间距1
         screen.blit(e, (20 + 32 * i, 20 + 32 * j))
 #存储棋盘状态
 alist  = np.zeros((19, 19))
 #星位
 pygame.draw.circle(screen, '#121010', [307.5, 307.5], 5)
 pygame.draw.circle(screen, '#121010', [115.5, 307.5], 5)
 pygame.draw.circle(screen, '#121010', [499.5, 307.5], 5)
 pygame.draw.circle(screen, '#121010', [115.5, 499.5], 5)
 pygame.draw.circle(screen, '#121010', [499.5, 499.5], 5)
 pygame.draw.circle(screen, '#121010', [115.5, 115.5], 5)
 pygame.draw.circle(screen, '#121010', [499.5, 115.5], 5)
 pygame.draw.circle(screen, '#121010', [307.5, 499.5], 5)
 pygame.draw.circle(screen, '#121010', [307.5, 115.5], 5)
#刷新窗口
 pygame.display.flip()

1.2创建棋子

本来打算直接上图片,后来参考了别的博主的做法,其实可以通过多个半径颜色不同的同心圆叠加来绘制圆滑的棋子

    def black(x, y):
        a = 20
        b =20
        c =20
        d = 0.01
        #循环50次,每次绘制50个半径颜色不同的同心圆
        for i in range(50):
            pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16/(d-5)+16))
            a += 1
            b += 1
            c += 1
            d += 0.08
        pygame.display.update()

    def white(x, y):
        a = 170
        b = 170
        c = 170
        d = 0.02
        for i in range(50):
            pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y],(16/(d-5)+16))
            a += 1
            b += 1
            c += 1
            d += 0.08
        pygame.display.update()

在这里插入图片描述

2.完成走棋操作

棋盘和棋子都准备好了,下面来实现下棋的功能,看看如何把棋子摆放在棋盘上。

五子棋的规则如下

1.对局双方各执一色棋子。 空棋盘开局。 黑先、白后,交替下子,每次只能下一子。
2.棋子下在棋盘的空白点上,棋子下定后,不得向其它点移动,不得从棋盘上拿掉或拿起另落别处。
3.五颗连续的同色棋子先连城一条线的那方赢。

人可以通过眼睛来判断那个位置能下棋和何时输赢,那计算机怎么判断这些呢。计算不像人那样有聪明的大脑,想要让计算机能做出这些判断,就必须把这些操作转换成计算机能理解的数据。

怎么让计算机知道棋盘的情况呢?我们用一个二维数组来模拟棋盘,棋盘上每个位置都有三种状态(无子、黑子、白子)那我们就用(0、1、2)来表示这三种情况。用wb来表示当前棋子,如果该位置为0则,更新该位置的值和wb的值,然后调用对用绘画函数来更新窗口

    #存储棋盘状态
    alist  = np.zeros((19, 19))
    if event.type == pygame.MOUSEBUTTONDOWN:
               x, y = pygame.mouse.get_pos()
               # 棋盘边界线的中点是19.5, 通过计算得到当前坐标在棋盘的行号和列号(x,y)
               x = round((x - 19.5) / 32)
               y = round((y - 19.5) / 32)
               if x < 0:
                   x = 0
               if x > 18:
                   x = 18
               if y < 0:
                   y = 0
               if y > 18:
                   y = 18
               z = False
               if alist[x][y] == 0:
               #这步相当于black(x,y)或者是white(x,y)取决于wb
                   eval(wb + "({},{})".format(x, y))

3.判断输赢

怎么判断赢了没?我们通过鼠标左机屏幕来下棋子,pygame也给我们提供了获取鼠标坐标的函数,每次鼠标点击后就进行check()操做
分别检查四个方向上是否有连子的情况,先找到该方向的第一个棋子然后向后统计同色数量,判断输赢。


def check(x,y):
        xx = x
        yy = y
        while True:
            #从最上边的棋子开始检查,记录颜色相同得棋子数量

            #先找到最同一条线上最上边的同色棋子
            if xx == 0:
                break
            elif alist[xx][yy] != alist[x][y]:
                xx += 1
                break
            else:
                xx -= 1
        num = 0
        while True:
            if xx == 18:
                break
            elif alist[xx][yy] != alist[x][y]:
                break
            else:
                xx += 1
                num += 1
        if num >= 5:

            win(wb1)

        # 从最边的棋子开始检查,记录颜色相同得棋子数量

        # 先找到最同一条线上最左边的同色棋子
        xx = x
        yy = y
        while True:
            if yy == 0:
                break
            elif alist[xx][yy] != alist[x][y]:
                yy += 1
                break
            else:
                yy -= 1
        num = 0
        while True:
            if yy == 18:
                break
            elif alist[xx][yy] != alist[x][y]:
                break
            else:
                yy += 1
                num += 1
        if num >= 5:
         win(wb1)
        
        # 从左上方的棋子开始检查,记录颜色相同得棋子数量

         # 先找到最同一条线上左上方的同色棋子
        xx = x
        yy = y
        while True:
            if xx == 0:
                break
            elif yy == 0:
                break
            elif alist[xx][yy] != alist[x][y]:
                xx += 1
                yy += 1
                break
            else:
                xx -= 1
                yy -= 1
        num = 0
        while True:
            if xx == 18:
                break
            elif yy == 18:
                break
            elif alist[xx][yy] != alist[x][y]:
                break
            else:
                xx += 1
                yy += 1
                num += 1
        if num >= 5:
            win(wb1)


        # 从右上方的棋子开始检查,记录颜色相同得棋子数量

        # 先找到最同一条线上右上方的同色棋子
        xx = x
        yy = y
        while True:
            if xx == 0:
                break
            elif yy == 18:
                break
            elif alist[xx][yy] != alist[x][y]:
                xx += 1
                yy -= 1
                break
            else:
                xx -= 1
                yy += 1
        num = 0
        while True:
            if xx == 18:
                break
            elif yy == 0:
                break
            elif alist[xx][yy] != alist[x][y]:
                break
            else:
                xx += 1
                yy -= 1
                num += 1
        if num >= 5:
            pygame.font.init()
            win(wb1)
     


def win(wb1):
    font = pygame.font.Font(None, 36)
    text = font.render("{}赢了".format(wb1), True, (255, 255, 255))
    screen.blit(text, ((665 - text.get_width()) / 2, (665 - text.get_height()) / 2))
    pygame.display.update()
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                do()

完成了这些步骤后,五子棋的基本规则已经实现,敲了几十行代码,终于能得到点反馈了。
下面是初级版的完整代码


import random
import sys
import pygame

import numpy as np

def init():
    pygame.init()
    # 创建窗口,背景为棕色
    global screen
    screen = pygame.display.set_mode((615, 615))
    pygame.display.set_caption('五子棋')
    screen.fill("#DD954F")
    # 创建外边框

    a = pygame.Surface((603, 603), flags=pygame.HWSURFACE)
    a.fill(color='#121010')
    b = pygame.Surface((585, 585), flags=pygame.HWSURFACE)
    b.fill(color="#DD954F")
    c = pygame.Surface((579, 579), flags=pygame.HWSURFACE)
    c.fill(color='#121010')

    e = pygame.Surface((31, 31), flags=pygame.HWSURFACE)
    e.fill(color="#DD954F")
    screen.blit(a, (6.5, 6.5))
    screen.blit(b, (15, 15))
    screen.blit(c, (18, 18))
    # 棋盘格子
    for j in range(18):
        for i in range(18):
            # 起点是20,间隔是32,每个格子大小31,所以格子间距1
            screen.blit(e, (20 + 32 * i, 20 + 32 * j))
    # 存储棋盘状态
    global alist
    alist = np.zeros((19, 19))
    # 星位
    pygame.draw.circle(screen, '#121010', [307.5, 307.5], 5)
    pygame.draw.circle(screen, '#121010', [115.5, 307.5], 5)
    pygame.draw.circle(screen, '#121010', [499.5, 307.5], 5)
    pygame.draw.circle(screen, '#121010', [115.5, 499.5], 5)
    pygame.draw.circle(screen, '#121010', [499.5, 499.5], 5)
    pygame.draw.circle(screen, '#121010', [115.5, 115.5], 5)
    pygame.draw.circle(screen, '#121010', [499.5, 115.5], 5)
    pygame.draw.circle(screen, '#121010', [307.5, 499.5], 5)
    pygame.draw.circle(screen, '#121010', [307.5, 115.5], 5)
    # 刷新窗口
    pygame.display.flip()


# 绘制棋子
def black(x, y):
    a = 20
    b = 20
    c = 20
    d = 0.01
    # 循环50次,每次绘制50个半径颜色不同的同心圆
    for i in range(50):
        pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16 / (d - 5) + 16))
        a += 1
        b += 1
        c += 1
        d += 0.08
    pygame.display.update()


def white(x, y):
    a = 170
    b = 170
    c = 170
    d = 0.02
    for i in range(50):
        pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16 / (d - 5) + 16))
        a += 1
        b += 1
        c += 1
        d += 0.08
    pygame.display.update()


pygame.font.init()
font1 = pygame.font.Font(None, 250)


# 主要操作
def do(wb):
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                # 棋盘边界线的中点是19.5, 通过计算得到当前坐标在棋盘的行号和列号(x,y)
                x = round((x - 19.5) / 32)
                y = round((y - 19.5) / 32)
                if x < 0:
                    x = 0
                if x > 18:
                    x = 18
                if y < 0:
                    y = 0
                if y > 18:
                    y = 18
                if alist[x][y] == 0:
                    eval(wb + "({},{})".format(x, y))
                    if wb == "black":
                        alist[x][y] = 1
                        wb1 = "black"
                        wb = "white"
                    elif wb == "white":
                        alist[x][y] = 2
                        wb1 = "white"
                        wb = "black"
                    check(x, y, wb1)
def check(x, y, wb1):
    xx = x
    yy = y
    while True:
        # 从最上边的棋子开始检查,记录颜色相同得棋子数量
        # 先找到最同一条线上最上边的同色棋子
        if xx == 0:
            break
        elif alist[xx][yy] != alist[x][y]:
            xx += 1
            break
        else:
            xx -= 1
    num = 0
    while True:
        if xx == 18:
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            xx += 1
            num += 1
    if num >= 5:
        win(wb1)
    # 从最边的棋子开始检查,记录颜色相同得棋子数量
    # 先找到最同一条线上最左边的同色棋子
    xx = x
    yy = y
    while True:
        if yy == 0:
            break
        elif alist[xx][yy] != alist[x][y]:
            yy += 1
            break
        else:
            yy -= 1
    num = 0
    while True:
        if yy == 18:
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            yy += 1
            num += 1
    if num >= 5:
        win(wb1)

    # 从左上方的棋子开始检查,记录颜色相同得棋子数量

    # 先找到最同一条线上左上方的同色棋子
    xx = x
    yy = y
    while True:
        if xx == 0:
            break
        elif yy == 0:
            break
        elif alist[xx][yy] != alist[x][y]:
            xx += 1
            yy += 1
            break
        else:
            xx -= 1
            yy -= 1
    num = 0
    while True:
        if xx == 18:
            break
        elif yy == 18:
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            xx += 1
            yy += 1
            num += 1
    if num >= 5:
        win(wb1)

    # 从右上方的棋子开始检查,记录颜色相同得棋子数量

    # 先找到最同一条线上右上方的同色棋子
    xx = x
    yy = y
    while True:
        if xx == 0:
            break
        elif yy == 18:
            break
        elif alist[xx][yy] != alist[x][y]:
            xx += 1
            yy -= 1
            break
        else:
            xx -= 1
            yy += 1
    num = 0
    while True:
        if xx == 18:
            break
        elif yy == 0:
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            xx += 1
            yy -= 1
            num += 1
    if num >= 5:
        pygame.font.init()
        win(wb1)


def win(wb1):
    pygame.font.init()
    font = pygame.font.Font(None, 70)

    text = font.render(f"{wb1}  won", True, (255, 255, 255))
    screen.blit(text, ((655 - text.get_width()) / 2, (665 - text.get_height()) / 2))
    pygame.display.update()

    pygame.display.flip()
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                init()
                do("black")


if __name__ == "__main__":
    init()
    do('black')

4.实现人机对弈

现在五子棋的基本公能已经实现了,但这种充满策略与博弈的棋类游戏,猜测并应对对手可能的布局,相互之间进行激烈的智力对决才是游戏最好玩的部分,一个人玩也太无聊了,要是电脑能像人一样可以思考该多好呀,就像近几年的特别火的“阿尔法狗”一样,我很期待被自己的程序打败。那么怎样实现人机对弈呢?

随着人工智能的快速发展,其在许多领域都得到了广泛应用,其中就包括游戏人工智能。游戏人工智能分为两大类,
一类叫做确定性人工智能,另一类叫做非确定性人工智能。
确定性人工智能,是指电脑按照确定的规则进行判断和抉择。非确定性人工智能是指电脑根据已有的规则来学习新的规则,例如神经网络、遗传算法、决策树和概率方法等。
因为五子棋的规则是确定的,所以我们只用让电脑记住规则,并按照规则来决策和判断。在棋类游戏中,如果把棋子的每一种布局都当作是一种状态,那对局中所有的可能局面的集合被称为状态空间,状态空间搜素就是根据某种规则,在所有的局面中找到最有利的局面,并以此来决定下一步走法。由于五子棋的规则简单,不同状态的最优解比较少,不必采用耗费空间的状态空间搜素法,只用让电脑记住所有的最优解即可。

4.1列举最优解

回想一下自己下棋的思考过程,决策和判断的依据无非就那几种,进过权衡后选择最有利的走法。模仿人的思考过程,我们可以告诉电脑所有的走法,然后将这些走法按等级排序,电脑每次决策的时候就在这些走法集合中按照等级由高到低的顺序依次搜素,没有找到最优解则随机下子。

为了让电脑能识别走法,首先要对棋局的各种走法进行描述和储存,这里我们用一个cdata列表实现,0表示空棋、1表示黑棋、 2表示白棋、3表示将要下棋的位置。


# 0表示空棋
# 1表示黑棋
# 2表示白棋
# 3表示下棋的位置

cdata = [
    # 一颗棋子的情况

    [1, 3, 0, 0, 0], [0, 1, 3, 0, 0], [0, 0, 1, 3, 0], [0, 0, 0, 1, 3], [0, 0, 0, 3, 1],
    [2, 3, 0, 0, 0], [0, 2, 3, 0, 0], [0, 0, 2, 3, 0], [0, 0, 0, 2, 3], [0, 0, 0, 3, 2],
    # 二颗棋子的情况
    [0, 1, 3, 1, 0], [1, 1, 3, 0, 0], [0, 0, 3, 1, 1],
    [2, 2, 3, 0, 0], [0, 0, 3, 2, 2], [0, 2, 3, 2, 0],
    # 三颗棋子的情况
    [1, 1, 1, 3, 0], [0, 3, 1, 1, 1], [1, 1, 3, 1, 0], [1, 3, 1, 1, 0],
    [2, 2, 0, 3, 2], [2, 3, 0, 2, 2], [0, 3, 2, 2, 2], [2, 2, 3, 2, 0],
    [2, 3, 2, 2, 0], [0, 2, 3, 2, 2], [0, 2, 2, 3, 2], [2, 2, 2, 3, 0], [3, 2, 2, 2, 0],
    # 四颗棋子情况
    [1, 1, 1, 1, 3], [3, 1, 1, 1, 1], [1, 1, 1, 3, 1], [1, 3, 1, 1, 1], [1, 1, 3, 1, 1],
    [2, 2, 2, 2, 3], [3, 2, 2, 2, 2], [2, 2, 3, 2, 2], [2, 3, 2, 2, 2], [2, 2, 2, 3, 2]
]

4.2匹配最优解

现在电脑已经掌握各种走法了,决胜秘籍在手,电脑改怎么用呢?接下来我们定义三个全局变量,用来辅助匹配算法的执行。 用ai_col 下棋位置列号, ai_row下棋位置行号,max_level走法等级

  global ai_col, ai_row, max_level
    ai_col = -1
    ai_row = -1
    max_level = -1

接着我们来定义auto_match()函数

def auto_mach(row, col, level, dx, dy):
    global ai_col, ai_row, max_level
    col_sel = -1  # 暂存棋子列号
    row_sel = -1  # 暂存棋子行号
    isfind = True  # 匹配成功的标记

    for j in range(5):
        cs = alist[row + j * dx][col + j * dy]
        if cs == 0:
            if cdata[level][j] == 3:
                row_sel = row + j * dx
                col_sel = col + j * dy
            elif cdata[level][j] == 1:
                isfind = False
                break
            elif cdata[level][j] == 2:
                isfind = False
                break
        elif cs != cdata[level][j]:
            isfind = False
            break
    if isfind:
        ai_row = row_sel
        ai_col = col_sel
        max_level = level
        return True
    return False

函数需要4个参数row和col是棋子的位置,level是走法等级,dx,dy是下一步方向,用row_sel,col_sel来存储匹配过程中棋子的位值,棋子按照dx,dy的方向一次往后匹配,
如果棋盘布局和走法列表匹配成功则发挥True,反正返回False。

4.3自主操作

完成了匹配操作后,电脑就有了判断的能力了,接下来我们来实现电脑的自主操作。下面定义ai_play()


def ai_play():
    global ai_col, ai_row, max_level
    ai_col = -1
    ai_row = -1
    max_level = -1
    # 搜素棋盘每个位置
    for i in range(19):
        for j in range(19):
            # 从高到低搜索
            for level in range(len(cdata) - 1, -1, -1):
                if level > max_level:
                    if i + 4 < 19:
                        if auto_mach(i, j, level, 1, 0):
                            break
                    if j + 4 < 19:
                        if auto_mach(i, j, level, 0, 1):
                            break

                    if i + 4 < 19 and j + 4 < 19:
                        if auto_mach(i, j, level, 1, 1):
                            break

                    if i + 4 < 19 and j - 4 > 0:
                        if auto_mach(i, j, level, 1, -1):
                            break
    if ai_row!=-1 and ai_row!=-1:
        alist[ai_row][ai_col]=2
        return True
    while True:
        col = random.randint(0,18)
        row = random.randint(0, 18)
        if alist[row][col]==0:
            alist[row][col]=2
            ai_row=row
            ai_col=col

            return True
    return False

该函数首先将全局变量max_level,ai_row,ai_col重置为-1,清除上次结果的影响,然后从棋盘第一个位置开始匹配,max_level记录最高等级,凡是等级比其低的走法直接不考虑,这样能减少不必要的操作,加快程序运行速率,匹配结束后,若找到最优解了就更新ai_row,ai_col,没找到就随机选一个符合要求的位置。

完整代码

至此程序全部编写完成,现在运行游戏玩一下,看看你和计算机谁更厉害,如果被打败了这就是你肝了半天的代码最好的反馈。


import random
import sys
import pygame

import numpy as np

# 0表示空棋
# 1表示黑棋
# 2表示白棋
# 3表示下棋的位置

cdata = [
    # 一颗棋子的情况

    [1, 3, 0, 0, 0], [0, 1, 3, 0, 0], [0, 0, 1, 3, 0], [0, 0, 0, 1, 3], [0, 0, 0, 3, 1],
    [2, 3, 0, 0, 0], [0, 2, 3, 0, 0], [0, 0, 2, 3, 0], [0, 0, 0, 2, 3], [0, 0, 0, 3, 2],
    # 二颗棋子的情况
    [0, 1, 3, 1, 0], [1, 1, 3, 0, 0], [0, 0, 3, 1, 1],
    [2, 2, 3, 0, 0], [0, 0, 3, 2, 2], [0, 2, 3, 2, 0],
    # 三颗棋子的情况
    [1, 1, 1, 3, 0], [0, 3, 1, 1, 1], [1, 1, 3, 1, 0], [1, 3, 1, 1, 0],
    [2, 2, 0, 3, 2], [2, 3, 0, 2, 2], [0, 3, 2, 2, 2], [2, 2, 3, 2, 0],
    [2, 3, 2, 2, 0], [0, 2, 3, 2, 2], [0, 2, 2, 3, 2], [2, 2, 2, 3, 0], [3, 2, 2, 2, 0],
    # 四颗棋子情况
    [1, 1, 1, 1, 3], [3, 1, 1, 1, 1], [1, 1, 1, 3, 1], [1, 3, 1, 1, 1], [1, 1, 3, 1, 1],
    [2, 2, 2, 2, 3], [3, 2, 2, 2, 2], [2, 2, 3, 2, 2], [2, 3, 2, 2, 2], [2, 2, 2, 3, 2]
]


def auto_mach(row, col, level, dx, dy):
    global ai_col, ai_row, max_level
    col_sel = -1  # 暂存棋子列号
    row_sel = -1  # 暂存棋子行号
    isfind = True  # 匹配成功的标记

    for j in range(5):
        cs = alist[row + j * dx][col + j * dy]
        if cs == 0:
            if cdata[level][j] == 3:
                row_sel = row + j * dx
                col_sel = col + j * dy
            elif cdata[level][j] == 1:
                isfind = False
                break
            elif cdata[level][j] == 2:
                isfind = False
                break
        elif cs != cdata[level][j]:
            isfind = False
            break
    if isfind:
        ai_row = row_sel
        ai_col = col_sel
        max_level = level
        return True
    return False


def ai_play():
    global ai_col, ai_row, max_level
    ai_col = -1
    ai_row = -1
    max_level = -1
    # 搜素棋盘每个位置
    for i in range(19):
        for j in range(19):
            # 从高到低搜索
            for level in range(len(cdata) - 1, -1, -1):
                if level > max_level:
                    if i + 4 < 19:
                        if auto_mach(i, j, level, 1, 0):
                            break
                    if j + 4 < 19:
                        if auto_mach(i, j, level, 0, 1):
                            break

                    if i + 4 < 19 and j + 4 < 19:
                        if auto_mach(i, j, level, 1, 1):
                            break

                    if j + 4 < 19 and i - 4 > 0:
                        if auto_mach(i, j, level, -1, 1):
                            break
    if ai_row!=-1 and ai_row!=-1:
        alist[ai_row][ai_col]=2
        return True
    while True:
        col = random.randint(0,18)
        row = random.randint(0, 18)
        if alist[row][col]==0:
            alist[row][col]=2
            ai_row=row
            ai_col=col

            return True
    return False


def init():
    pygame.init()
    # 创建窗口,背景为棕色
    global screen
    screen = pygame.display.set_mode((615, 615))
    pygame.display.set_caption('五子棋')
    screen.fill("#DD954F")
    # 创建外边框

    a = pygame.Surface((603, 603), flags=pygame.HWSURFACE)
    a.fill(color='#121010')
    b = pygame.Surface((585, 585), flags=pygame.HWSURFACE)
    b.fill(color="#DD954F")
    c = pygame.Surface((579, 579), flags=pygame.HWSURFACE)
    c.fill(color='#121010')

    e = pygame.Surface((31, 31), flags=pygame.HWSURFACE)
    e.fill(color="#DD954F")
    screen.blit(a, (6.5, 6.5))
    screen.blit(b, (15, 15))
    screen.blit(c, (18, 18))
    # 棋盘格子
    for j in range(18):
        for i in range(18):
            # 起点是20,间隔是32,每个格子大小31,所以格子间距1
            screen.blit(e, (20 + 32 * i, 20 + 32 * j))
    # 存储棋盘状态
    global alist
    alist = np.zeros((19, 19))
    # 星位
    pygame.draw.circle(screen, '#121010', [307.5, 307.5], 5)
    pygame.draw.circle(screen, '#121010', [115.5, 307.5], 5)
    pygame.draw.circle(screen, '#121010', [499.5, 307.5], 5)
    pygame.draw.circle(screen, '#121010', [115.5, 499.5], 5)
    pygame.draw.circle(screen, '#121010', [499.5, 499.5], 5)
    pygame.draw.circle(screen, '#121010', [115.5, 115.5], 5)
    pygame.draw.circle(screen, '#121010', [499.5, 115.5], 5)
    pygame.draw.circle(screen, '#121010', [307.5, 499.5], 5)
    pygame.draw.circle(screen, '#121010', [307.5, 115.5], 5)
    # 刷新窗口
    pygame.display.flip()


# 绘制棋子
def black(x, y):
    a = 20
    b = 20
    c = 20
    d = 0.01
    # 循环50次,每次绘制50个半径颜色不同的同心圆
    for i in range(50):
        pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16 / (d - 5) + 16))
        a += 1
        b += 1
        c += 1
        d += 0.08
    pygame.display.update()


def white(x, y):
    a = 170
    b = 170
    c = 170
    d = 0.02
    for i in range(50):
        pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16 / (d - 5) + 16))
        a += 1
        b += 1
        c += 1
        d += 0.08
    pygame.display.update()


pygame.font.init()
font1 = pygame.font.Font(None, 250)


# 主要操作
def do(wb):
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                # 棋盘边界线的中点是19.5, 通过计算得到当前坐标在棋盘的行号和列号(x,y)
                x = round((x - 19.5) / 32)
                y = round((y - 19.5) / 32)
                if x < 0:
                    x = 0
                if x > 18:
                    x = 18
                if y < 0:
                    y = 0
                if y > 18:
                    y = 18
                if alist[x][y] == 0:
                    black(x, y)
                    alist[x][y] = 1
                    wb1 = "You"
                    wb = "white"
                    check(x, y, wb1)
                    pygame.time.wait(100)
                    if ai_play():
                        white(ai_row, ai_col)
                        wb1 = "AI"
                        wb = "black"
                        check(ai_row, ai_col, wb1)

def check(x, y, wb1):
    xx = x
    yy = y
    while True:
        # 从最上边的棋子开始检查,记录颜色相同得棋子数量
        # 先找到最同一条线上最上边的同色棋子
        if xx == 0:
            if alist[xx][yy] != alist[x][y]:
                xx += 1
            break
        elif alist[xx][yy] != alist[x][y]:
            xx += 1
            break
        else:
            xx -= 1
    num = 0
    while True:
        if xx == 18:
            if alist[xx][yy] == alist[x][y]:
                num += 1
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            xx += 1
            num += 1
    if num >= 5:
        win(wb1)
    # 从最边的棋子开始检查,记录颜色相同得棋子数量
    # 先找到最同一条线上最左边的同色棋子
    xx = x
    yy = y
    while True:
        if yy == 0:
            if alist[xx][yy] != alist[x][y]:
                yy += 1

            break
        elif alist[xx][yy] != alist[x][y]:
            yy += 1
            break
        else:
            yy -= 1
    num = 0
    while True:
        if yy == 18:
            if alist[xx][yy] == alist[x][y]:
                num += 1
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            yy += 1
            num += 1
    if num >= 5:
        win(wb1)

    # 从左上方的棋子开始检查,记录颜色相同得棋子数量

    # 先找到最同一条线上左上方的同色棋子
    xx = x
    yy = y
    while True:
        if xx == 0:
            if alist[xx][yy] != alist[x][y]:
                xx += 1
                yy += 1
            break
        elif yy == 0:
            if alist[xx][yy] != alist[x][y]:
                xx += 1
                yy += 1
            break
        elif alist[xx][yy] != alist[x][y]:
            xx += 1
            yy += 1
            break
        else:
            xx -= 1
            yy -= 1
    num = 0
    while True:
        if xx == 18:
            if alist[xx][yy] == alist[x][y]:
                num += 1

            break
        elif yy == 18:
            if alist[xx][yy] == alist[x][y]:
                num += 1
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            xx += 1
            yy += 1
            num += 1
    if num >= 5:
        win(wb1)

    # 从右上方的棋子开始检查,记录颜色相同得棋子数量

    # 先找到最同一条线上右上方的同色棋子
    xx = x
    yy = y
    while True:
        if xx == 0:
            if alist[xx][yy] != alist[x][y]:
                xx += 1
                yy -= 1
            break
        elif yy == 18:
            if alist[xx][yy] != alist[x][y]:
                xx += 1
                yy -= 1
            break
        elif alist[xx][yy] != alist[x][y]:
            xx += 1
            yy -= 1
            break
        else:
            xx -= 1
            yy += 1
    num = 0
    while True:
        if xx == 18:
            if alist[xx][yy] == alist[x][y]:
                num += 1
            break
        elif yy == 0:
            if alist[xx][yy] == alist[x][y]:
                num += 1
            break
        elif alist[xx][yy] != alist[x][y]:
            break
        else:
            xx += 1
            yy -= 1
            num += 1
    if num >= 5:
        win(wb1)


def win(wb1):
    pygame.font.init()
    font = pygame.font.Font(None, 70)

    text = font.render(f"{wb1}  won", True, (255, 255, 255))
    screen.blit(text, ((655 - text.get_width()) / 2, (665 - text.get_height()) / 2))
    pygame.display.update()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                init()
                text = font.render("Start the game", True, (255, 255, 255))
                screen.blit(text, ((655 - text.get_width()) / 2, (665 - text.get_height()) / 2))
                pygame.display.update()
                pygame.time.wait(500)
                init()
                do("black")


if __name__ == "__main__":
    init()
    do('black')



在这里插入图片描述

参考资料《趣学python游戏编程》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294052.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ES两个小时没连接竟然会出现bug,为此老板给我夹了个鸡腿。。。

前言 前段时间上线了个项目&#xff0c;测试每天早上来摸鱼之前会点一点&#xff0c;发现第一次点会报错&#xff0c;然后一天都没问题&#xff0c;刚开始没在意&#xff0c;后来每天上班来摸鱼前点第一次都会出错&#xff0c;发现真的摸到鱼了&#xff0c;然后就给我提了个bu…

深耕汽车检测设备领域,引领行业技术革新

在汽车工业飞速发展的今天&#xff0c;汽车检测技术作为保障车辆安全、提升维修效率的重要手段&#xff0c;日益受到行业内外的高度关注。康士柏汽车检测线设备厂家&#xff0c;作为这一领域的佼佼者&#xff0c;凭借其深厚的技术积累和卓越的产品品质&#xff0c;正引领着行业…

CSS基础笔记-01CSS概述

文章目录 前言CSS是什么CSS的作用CSS语法添加CSS的方法 前言 CSS是什么&#xff1f;有什么作用&#xff1f;怎么编写CSS&#xff1f;怎样添加CSS&#xff1f;本文对CSS的四个方面作了学习并形成学习笔记。 CSS是什么 CSS &#xff08;Cascading Style Sheets&#xff0c;层叠…

java字节码

1. 字节码 1.1 什么是字节码&#xff1f; Java之所以可以“一次编译&#xff0c;到处运行”&#xff0c;一是因为JVM针对各种操作系统、平台都进行了定制&#xff0c;二是因为无论在什么平台&#xff0c;都可以编译生成固定格式的字节码&#xff08;.class文件&#xff09;供…

小寒节气吃什么?来一道烤排骨吧!

小寒节气是中国传统二十四节气中的第23个节气。 在寒冷的冬季&#xff0c;为了驱寒保暖&#xff0c;人们会选择一些具有温热性质的食物来进补。那么&#xff0c;小寒节气应该吃什么呢&#xff1f;羊肉是冬季进补的佳品。羊肉富含丰富的蛋白质和热量&#xff0c;能够帮助身体抵…

Go语言并发模式视角思考

犹记得2019年中旬进行知识点的学习和demo的练习&#xff0c;熟悉各种语法和并发调度的场景&#xff0c; 在2019年末开始参与项目实战开发和逻辑梳理 Go语言的接触也是更多探索和业务的拆件&#xff0c;做一些雏形工具&#xff0c;来慢慢的孵化业务生态 后来陆陆续续&#xff…

03- OpenCV:矩阵的掩膜操作

目录 1、矩阵的掩膜操作 简介 2、获取图像像素指针 3、掩膜操作解释 4、代码演示 1、矩阵的掩膜操作 简介 在OpenCV中&#xff0c;矩阵的掩膜操作是一种通过使用一个二进制掩膜来选择性地修改或提取图像或矩阵的特定区域的方法。 掩膜是一个与原始图像或矩阵具有相同大小的…

力扣题:高精度运算-1.3

力扣题-1.3 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;43. 字符串相乘 解题思想&#xff1a;类似计算时采用的竖式乘法。首先取得num2的低位&#xff0c;并补齐对应的0&#xff0c;然后与num1进行相乘&#xff0c;然后进行字符串的相加操作。…

【萤火虫系列教程】2/5-Adobe Firefly 文字​生成​图像

文字​生成​图像 登录账号后&#xff0c;在主页点击文字生成图像的【生成】按钮&#xff0c;进入到文字生成图像 查看图像 在文字生成图像页面&#xff0c;可以看到别人生成的图像。 点击某个图像&#xff0c;就可以进入图像详情&#xff0c;可以看到文字描述。 生成图像 我…

c++之迭代器

目录 一、迭代器 二、几种常见的迭代器类型 三、使用迭代器时注意事项 一、迭代器 在C中&#xff0c;迭代器是一种用于遍历容器元素的对象。迭代器提供了一种通用的方式来访问各种不同类型的容器&#xff0c;如数组、向量、列表、集合和映射等。 使用迭代器可以避免直接操作…

c++牛客总结

一、c/c语言基础 1、基础 1、指针和引用的区别 指针是一个新的变量&#xff0c;指向另一个变量的地址&#xff0c;我们可以通过这个地址来修改该另一个变量&#xff1b; 引用是一个别名&#xff0c;对引用的操作就是对变量本身进行操作&#xff1b;指针可以有多级 引用只有一…

python股票分析挖掘预测技术指标知识大全(1)

本人股市多年的老韭菜&#xff0c;各种股票分析书籍&#xff0c;技术指标书籍阅历无数&#xff0c;萌发想法&#xff0c;何不自己开发个股票预测分析软件&#xff0c;选择python因为够强大&#xff0c;它提供了很多高效便捷的数据分析工具包&#xff0c; 我们已经初步的接触与…

leetcode 每日一题 2024年01月01日 经营摩天轮的最大利润

题目 1599 经营摩天轮的最大利润 你正在经营一座摩天轮&#xff0c;该摩天轮共有 4 个座舱 &#xff0c;每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱&#xff0c;但每次轮转都需要支付一定的运行成本 runningCost 。摩天轮每次轮转都恰好转动 1 / 4 周。 给你…

LeetCode 2487. 从链表中移除节点:单调栈

【LetMeFly】2487.从链表中移除节点&#xff1a;单调栈 力扣题目链接&#xff1a;https://leetcode.cn/problems/remove-nodes-from-linked-list/ 给你一个链表的头节点 head 。 移除每个右侧有一个更大数值的节点。 返回修改后链表的头节点 head 。 示例 1&#xff1a; 输…

【RocketMQ每日一问】RocketMQ中raft的应用?

1.rocketmq中raft算法实现方式 RocketMQ 中实现 Raft 算法的模块是 DLedger&#xff0c;它是一种基于 Raft 协议的分布式日志存储模式&#xff0c;用于提供高可用性和数据一致性的保证&#xff0c;保证消息的可靠性和持久化存储。 在 DLedger 中&#xff0c;每个节点都维护着…

IDEA安装教程及使用

一、IDEA简介 ​ IDEA全称IntelliJ IDEA&#xff0c;是用于Java语言开发的集成环境&#xff0c;它是业界公认的目前用于Java程序开发最好的工具。 集成环境&#xff1a;把代码编写&#xff0c;编译&#xff0c;执行&#xff0c;调试等多种功能综合到一起的开发工具。 二、ID…

【软件系统架构设计】期末复习题目汇总:简答+应用

电子科技大学软件系统架构设计2023年秋期末考试复习题目汇总 目录 系统分析与设计概述 面向对象建模语言 系统规划 系统需求分析 系统架构设计 软件建模详细设计 设计模式 用户界面设计 系统分析与设计概述 信息系统的 6 种类型&#xff0c;举例说明&#xff1f; 信息…

一个人,2 年时间,每月赚 6w 美金,独立开发者故事丨 RTE 开发者日报 Vol.120

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

探讨芯片封装的技术、工艺以及与之相关的知识

芯片封装作为芯片技术中的重要环节&#xff0c;扮演着保护和连接芯片的关键角色。通过封装工艺&#xff0c;芯片能够与外界进行通信并在实际应用中发挥作用。本文将深入探讨芯片封装的技术、工艺以及与之相关的知识。 芯片封装的概念与意义 芯片封装是指将芯片封装在特定的封…