让电脑变得更聪明——用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…

Head First Design Patterns - 观察者模式

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

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…

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

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

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;也能通过绘画模型生成想…

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

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

go slice源码探索(切片、copy、扩容)和go编译源码分析

文章目录 概要一、数据结构二、初始化2.1、字面量2.2、下标截取2.2.1、截取原理 2.3、make关键字2.3.1、编译时 三、复制3.1、copy源码 四、扩容4.1、append源码 五&#xff1a;切片使用注意事项六&#xff1a;参考 概要 Go语言的切片&#xff08;slice&#xff09;是对数组的…

axios的使用及说明

目录 1.说明 2.直接使用 3.封装使用 4.注意 1.说明 官网&#xff1a;Axios 实例 | Axios中文文档 | Axios中文网 Axios 是一个基于 promise 网络请求库&#xff0c;作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使…

Java超高精度无线定位技术--UWB (超宽带)人员定位系统源码

UWB室内定位技术是一种全新的、与传统通信技术有极大差异的通信新技术。它不需要使用传统通信体制中的载波&#xff0c;而是通过发送和接收具有纳秒或纳秒级以下的极窄脉冲来传输数据&#xff0c;从而具有GHz量级的带宽。 UWB&#xff08;超宽带&#xff09;高精度定位系统是一…

java零拷贝zero copy MappedByteBuffer

目录 调用操作系统的 mmap 未使用 mmap 的文件通过网络传输的过程 使用 mmap 的文件通过网络传输的过程 使用例子 调用操作系统的 sendfile() 在 java 中的具体实现 mmap的优劣 mmap 的不足 mmap 的优点 mmap 的使用场景 对于零拷贝&#xff08;zero copy&#xff09…

C语言实验4:指针

目录 一、实验要求 二、实验原理 1. 指针的基本概念 1.1 指针的定义 1.2 取地址运算符&#xff08;&&#xff09; 1.3 间接引用运算符&#xff08;*&#xff09; 2. 指针的基本操作 2.1 指针的赋值 2.2 空指针 3. 指针和数组 3.1 数组和指针的关系 3.2 指针和数…

【Linux】内核编译 镜像制作

文章目录 一、Ubuntu内核编译1.1 为什么自己编译内核1.2 Ubuntu 内核源码下载1.21 内核的作用1.22 Linux内核与ubuntu内核1.23 Ubuntu内核源码获取 1.3 在Windows系统下编译ubuntu内核1.4 在Linux系统下编译ubuntu内核 二、镜像制作 一、Ubuntu内核编译 1.1 为什么自己编译内核…

用LCD循环右移显示“Welcome to China“

#include<reg51.h> //包含单片机寄存器的头文件 #include<intrins.h> //包含_nop_()函数定义的头文件 sbit RSP2^0; //寄存器选择位&#xff0c;将RS位定义为P2.0引脚 sbit RWP2^1; //读写选择位&#xff0c;将RW位定义为P2.1引脚 sbit EP2^2; //使能…

Debezium日常分享系列之:向 Debezium 连接器发送信号

Debezium日常分享系列之&#xff1a;向 Debezium 连接器发送信号 一、概述二、激活源信号通道三、信令数据集合的结构四、创建信令数据集合五、激活kafka信号通道六、数据格式七、激活JMX信号通道八、自定义信令通道九、Debezium 核心模块依赖项十、部署自定义信令通道十一、信…