让电脑变得更聪明——用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,所以格子间距1screen.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 = 20b =20c =20d = 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 += 1b += 1c += 1d += 0.08pygame.display.update()def white(x, y):a = 170b = 170c = 170d = 0.02for i in range(50):pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y],(16/(d-5)+16))a += 1b += 1c += 1d += 0.08pygame.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 = 0if x > 18:x = 18if y < 0:y = 0if y > 18:y = 18z = Falseif alist[x][y] == 0:#这步相当于black(x,y)或者是white(x,y)取决于wbeval(wb + "({},{})".format(x, y))

3.判断输赢

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


def check(x,y):xx = xyy = ywhile True:#从最上边的棋子开始检查,记录颜色相同得棋子数量#先找到最同一条线上最上边的同色棋子if xx == 0:breakelif alist[xx][yy] != alist[x][y]:xx += 1breakelse:xx -= 1num = 0while True:if xx == 18:breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1num += 1if num >= 5:win(wb1)# 从最边的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上最左边的同色棋子xx = xyy = ywhile True:if yy == 0:breakelif alist[xx][yy] != alist[x][y]:yy += 1breakelse:yy -= 1num = 0while True:if yy == 18:breakelif alist[xx][yy] != alist[x][y]:breakelse:yy += 1num += 1if num >= 5:win(wb1)# 从左上方的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上左上方的同色棋子xx = xyy = ywhile True:if xx == 0:breakelif yy == 0:breakelif alist[xx][yy] != alist[x][y]:xx += 1yy += 1breakelse:xx -= 1yy -= 1num = 0while True:if xx == 18:breakelif yy == 18:breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1yy += 1num += 1if num >= 5:win(wb1)# 从右上方的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上右上方的同色棋子xx = xyy = ywhile True:if xx == 0:breakelif yy == 18:breakelif alist[xx][yy] != alist[x][y]:xx += 1yy -= 1breakelse:xx -= 1yy += 1num = 0while True:if xx == 18:breakelif yy == 0:breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1yy -= 1num += 1if 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 pygameimport numpy as npdef init():pygame.init()# 创建窗口,背景为棕色global screenscreen = 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,所以格子间距1screen.blit(e, (20 + 32 * i, 20 + 32 * j))# 存储棋盘状态global alistalist = 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 = 20b = 20c = 20d = 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 += 1b += 1c += 1d += 0.08pygame.display.update()def white(x, y):a = 170b = 170c = 170d = 0.02for i in range(50):pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16 / (d - 5) + 16))a += 1b += 1c += 1d += 0.08pygame.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 = 0if x > 18:x = 18if y < 0:y = 0if y > 18:y = 18if alist[x][y] == 0:eval(wb + "({},{})".format(x, y))if wb == "black":alist[x][y] = 1wb1 = "black"wb = "white"elif wb == "white":alist[x][y] = 2wb1 = "white"wb = "black"check(x, y, wb1)
def check(x, y, wb1):xx = xyy = ywhile True:# 从最上边的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上最上边的同色棋子if xx == 0:breakelif alist[xx][yy] != alist[x][y]:xx += 1breakelse:xx -= 1num = 0while True:if xx == 18:breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1num += 1if num >= 5:win(wb1)# 从最边的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上最左边的同色棋子xx = xyy = ywhile True:if yy == 0:breakelif alist[xx][yy] != alist[x][y]:yy += 1breakelse:yy -= 1num = 0while True:if yy == 18:breakelif alist[xx][yy] != alist[x][y]:breakelse:yy += 1num += 1if num >= 5:win(wb1)# 从左上方的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上左上方的同色棋子xx = xyy = ywhile True:if xx == 0:breakelif yy == 0:breakelif alist[xx][yy] != alist[x][y]:xx += 1yy += 1breakelse:xx -= 1yy -= 1num = 0while True:if xx == 18:breakelif yy == 18:breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1yy += 1num += 1if num >= 5:win(wb1)# 从右上方的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上右上方的同色棋子xx = xyy = ywhile True:if xx == 0:breakelif yy == 18:breakelif alist[xx][yy] != alist[x][y]:xx += 1yy -= 1breakelse:xx -= 1yy += 1num = 0while True:if xx == 18:breakelif yy == 0:breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1yy -= 1num += 1if 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_levelai_col = -1ai_row = -1max_level = -1

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

def auto_mach(row, col, level, dx, dy):global ai_col, ai_row, max_levelcol_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 * dxcol_sel = col + j * dyelif cdata[level][j] == 1:isfind = Falsebreakelif cdata[level][j] == 2:isfind = Falsebreakelif cs != cdata[level][j]:isfind = Falsebreakif isfind:ai_row = row_selai_col = col_selmax_level = levelreturn Truereturn 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_levelai_col = -1ai_row = -1max_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):breakif j + 4 < 19:if auto_mach(i, j, level, 0, 1):breakif i + 4 < 19 and j + 4 < 19:if auto_mach(i, j, level, 1, 1):breakif i + 4 < 19 and j - 4 > 0:if auto_mach(i, j, level, 1, -1):breakif ai_row!=-1 and ai_row!=-1:alist[ai_row][ai_col]=2return Truewhile True:col = random.randint(0,18)row = random.randint(0, 18)if alist[row][col]==0:alist[row][col]=2ai_row=rowai_col=colreturn Truereturn False

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

完整代码

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


import random
import sys
import pygameimport 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_levelcol_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 * dxcol_sel = col + j * dyelif cdata[level][j] == 1:isfind = Falsebreakelif cdata[level][j] == 2:isfind = Falsebreakelif cs != cdata[level][j]:isfind = Falsebreakif isfind:ai_row = row_selai_col = col_selmax_level = levelreturn Truereturn Falsedef ai_play():global ai_col, ai_row, max_levelai_col = -1ai_row = -1max_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):breakif j + 4 < 19:if auto_mach(i, j, level, 0, 1):breakif i + 4 < 19 and j + 4 < 19:if auto_mach(i, j, level, 1, 1):breakif j + 4 < 19 and i - 4 > 0:if auto_mach(i, j, level, -1, 1):breakif ai_row!=-1 and ai_row!=-1:alist[ai_row][ai_col]=2return Truewhile True:col = random.randint(0,18)row = random.randint(0, 18)if alist[row][col]==0:alist[row][col]=2ai_row=rowai_col=colreturn Truereturn Falsedef init():pygame.init()# 创建窗口,背景为棕色global screenscreen = 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,所以格子间距1screen.blit(e, (20 + 32 * i, 20 + 32 * j))# 存储棋盘状态global alistalist = 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 = 20b = 20c = 20d = 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 += 1b += 1c += 1d += 0.08pygame.display.update()def white(x, y):a = 170b = 170c = 170d = 0.02for i in range(50):pygame.draw.circle(screen, (a, b, c), [19.5 + 32 * x, 19.5 + 32 * y], (16 / (d - 5) + 16))a += 1b += 1c += 1d += 0.08pygame.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 = 0if x > 18:x = 18if y < 0:y = 0if y > 18:y = 18if alist[x][y] == 0:black(x, y)alist[x][y] = 1wb1 = "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 = xyy = ywhile True:# 从最上边的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上最上边的同色棋子if xx == 0:if alist[xx][yy] != alist[x][y]:xx += 1breakelif alist[xx][yy] != alist[x][y]:xx += 1breakelse:xx -= 1num = 0while True:if xx == 18:if alist[xx][yy] == alist[x][y]:num += 1breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1num += 1if num >= 5:win(wb1)# 从最边的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上最左边的同色棋子xx = xyy = ywhile True:if yy == 0:if alist[xx][yy] != alist[x][y]:yy += 1breakelif alist[xx][yy] != alist[x][y]:yy += 1breakelse:yy -= 1num = 0while True:if yy == 18:if alist[xx][yy] == alist[x][y]:num += 1breakelif alist[xx][yy] != alist[x][y]:breakelse:yy += 1num += 1if num >= 5:win(wb1)# 从左上方的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上左上方的同色棋子xx = xyy = ywhile True:if xx == 0:if alist[xx][yy] != alist[x][y]:xx += 1yy += 1breakelif yy == 0:if alist[xx][yy] != alist[x][y]:xx += 1yy += 1breakelif alist[xx][yy] != alist[x][y]:xx += 1yy += 1breakelse:xx -= 1yy -= 1num = 0while True:if xx == 18:if alist[xx][yy] == alist[x][y]:num += 1breakelif yy == 18:if alist[xx][yy] == alist[x][y]:num += 1breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1yy += 1num += 1if num >= 5:win(wb1)# 从右上方的棋子开始检查,记录颜色相同得棋子数量# 先找到最同一条线上右上方的同色棋子xx = xyy = ywhile True:if xx == 0:if alist[xx][yy] != alist[x][y]:xx += 1yy -= 1breakelif yy == 18:if alist[xx][yy] != alist[x][y]:xx += 1yy -= 1breakelif alist[xx][yy] != alist[x][y]:xx += 1yy -= 1breakelse:xx -= 1yy += 1num = 0while True:if xx == 18:if alist[xx][yy] == alist[x][y]:num += 1breakelif yy == 0:if alist[xx][yy] == alist[x][y]:num += 1breakelif alist[xx][yy] != alist[x][y]:breakelse:xx += 1yy -= 1num += 1if 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游戏编程》

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DNS域名查询过程

目录 DNS&#xff08;Domain Names System&#xff09; 域名转IP IP转域名 域名 域名查询流程 浏览器DNS缓存 操作系统缓存 本地host文件 完整流程 递归查询 迭代查询 DNS&#xff08;Domain Names System&#xff09; 域名系统&#xff0c;将域名和 IP 地址进行转…

【Spring】AOP的AspectJ开发

AOP基础不了解可以阅读&#xff1a;【Spring】AOP原来如此-CSDN博客 AspectJ是一个居于JAVA开发的AOP框架 基于XML的声明式AspectJ 基于XML的声明式AspectJ是通过XML文件来定义切面&#xff0c;切入点及通知&#xff0c;所有的切面、切入点和通知必须定义在内&#xff0c; 元…

【SpringBoot】常用注解

RequestBody&#xff1a;自动将请求体中的 json 数据转换为实体类对象。 这个例子凑巧传入的json属性键名和User键名一致&#xff0c;可以直接使用User实体类对象&#xff0c;如果键名不一致则需要用一个Map 类接收参数&#xff1a; PutMapping("/update")public R…

给多行文本的每行添加指定的前缀textwrap.indent()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 给多行文本的每行添加指定的前缀 textwrap.indent() [太阳]选择题 请问以下代码输出的第一行结果是&#xff1f; import textwrap text welcome to China! print("【显示】text\n&quo…

基于单片机的公交车站自动报站器设计与实现

一、摘要 随着城市交通的快速发展&#xff0c;公交车作为城市公共交通的主要工具&#xff0c;其便捷性和高效性得到了广泛的认可。然而&#xff0c;由于公交车站的广播系统存在一定的局限性&#xff0c;如人工报站容易出现失误、音量大小不一等问题&#xff0c;给乘客带来了不…

Head First Design Patterns - 观察者模式

观察者模式 观察者模式定义了对象之间的一对多依赖&#xff0c;当一个对象改变状态时&#xff0c;它的所有依赖者都会收到通知并自动更新。观察者模式是一种对象行为型模式。 场景 很多用户都订阅了某一公众号&#xff0c;当该公众号更新时&#xff0c;所以用户都会收到消息…

【JS笔记】JavaScript语法 《基础+重点》 知识内容,快速上手(一)

JavaScript基础语法 HTML &#xff1a;标记语言JavaScript &#xff1a;编程语言&#xff08;脚本&#xff09; 序言 JavaScript发展历史&#xff08;JS&#xff09; 1. 1994年&#xff0c;网景公司(Netscape)发布了Navigator浏览器0.9版&#xff0c;这是世界上第一款比较成…

Mybatis Java API - SqlSessionFactoryBuilder

在MyBatis中&#xff0c;用于与数据库进行交互的主要Java接口是SqlSession。通过这个接口&#xff0c;您可以执行命令、获取映射器并管理事务。稍后我们将更详细地讨论SqlSession本身&#xff0c;但首先我们必须学习如何获取SqlSession的实例。SqlSession是由SqlSessionFactory…

C++17中的内联变量

在C11中&#xff1a; (1).声明为constexpr的函数隐式地是内联函数; (2).deleted函数隐式地是一个内联函数。 在内联函数中&#xff1a; 1.所有函数定义中的函数局部静态对象(function-local static object)在所有翻译单元之间共享(它们都引用一个翻译单…

【c++————————构造函数和析构函数】

【c————————构造函数和析构函数】 欢迎阅读新一期的c模块————构造函数和析构函数 ✒️个人主页&#xff1a;-Joker- &#x1f3f7;️专栏&#xff1a;C &#x1f4dc;代码仓库&#xff1a;c_code &#x1f339;&#x1f339;欢迎大佬们的阅读和三连关注&#xff0c…

软件集成测试

软件集成测试是将各个独立的软件模块组合起来&#xff0c;并测试它们之间的接口和交互是否正常工作的过程。下面是软件集成测试的一般步骤&#xff1a; 确定测试策略&#xff1a;确定集成测试的目标、范围和测试策略。确定要测试的软件模块和它们之间的依赖关系。 设计测试用例…

Dependency Track:智能组件分析平台。

Dependency Track:智能组件分析平台。 ############################# 免责声明:工具本身并无好坏,希望大家以遵守《网络安全法》相关法律为前提来使用该工具,支持研究学习,切勿用于非法犯罪活动,对于恶意使用该工具造成的损失,和本人及开发者无关。 ################…

基于关键点的人脸对齐方法

人脸旋转校正的一般步骤&#xff1a; 1.人脸检测&#xff1a;首先使用人脸检测算法来检测图像中的人脸位置。 2.人脸关键点检测&#xff1a;对于每张检测到的人脸&#xff0c;使用人脸关键点检测算法来检测人脸中的关键点&#xff0c;如眼睛、鼻子、嘴巴等。 &#xff08;项目…

【leetcode100-026】【链表/快慢指针】环形链表II

【题干】 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统…

Linux | 解决问题Ubuntu重启无法进入系统以及网络无法连接【图文详解】

Ubuntu18.04重启无法进入系统&#xff0c;重开后如图 一直在加载系统内核4.15.0-213-generic,无法加载 错误原因 原本的系统是Ubuntu16.04,使用命令升级到Ubuntu18.04版本&#xff0c;升级重启后&#xff0c;远程无法连接&#xff01; 错误解决 第一步&#xff1a;进入GRUB…

AIGC入门系列1:感性的认识扩散模型

1、序言 大家好&#xff0c;欢迎来到AI手工星的频道&#xff0c;我是专注AI领域的手工星。AIGC已经成为AI又一个非常爆火的领域&#xff0c;并且与之前的AI模型不同&#xff0c;AIGC更适合普通人使用&#xff0c;我们不仅可以与chatgpt对话&#xff0c;也能通过绘画模型生成想…

基于SpringBoot的线上学习资源智能推荐系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的线上学习资源智能推荐系…

使用ASP.NET MiniAPI 调试未匹配请求路径

本文将介绍如何在使用ASP.NET MiniAPI时调试未匹配到的请求路径。我们将详细讨论使用MapFallback方法、中间件等工具来解决此类问题。 1. 引言 ASP.NET MiniAPI是一个轻量级的Web API框架&#xff0c;它可以让我们快速地构建和部署RESTful服务。然而&#xff0c;在开发过程中如…

Hystrix相关面试题及答案

1、什么是Hystrix&#xff0c;它是如何工作的&#xff1f; Hystrix是一个由Netflix开源的库&#xff0c;主要用于在分布式系统中提供延迟和容错功能&#xff0c;通过阻止服务故障的蔓延和提供回退机制来保护系统。它在服务架构中扮演着重要的角色&#xff0c;特别是在微服务架…

PACC:数据中心网络的主动 CNP 生成方案

PACC&#xff1a;数据中心网络的主动 CNP 生成方案 文章目录 PACC&#xff1a;数据中心网络的主动 CNP 生成方案PACC算法CNP数据结构PACC参数仿真结果参考文献 PACC算法 CNP数据结构 PACC参数 仿真结果 PACC Hadoop Load0.2 的情况&#xff1a; PACC Hadoop Load0.4 的情况&a…