这个栏目将会总结我在学习过程中阅读过的项目代码的总结和记录。
文章目录项目代码阅读记录一、全局变量二、主函数main二、runGame()三、余下函数1. getNewBoard()2.def isBoardFull(board)3.def getHumanMove(board, isFirstMove):4.def isValidMove(board, column)5.def animateDroppingToken(board, column, color)6.def getLowestEmptySpace(board, column)7.def isWinner(board, tile)8、def getComputerMove(board)9.def getPotentialMoves(board, tile, depth)10.def animateComputerMoving(board, column)11.def drawBoard(board, extraToken=None)12.def makeMove(board, player, column)
一、全局变量
BOARDWIDTH = 7 # 棋子盘的宽度栏数BOARDHEIGHT = 6 # 棋子盘的高度栏数assert BOARDWIDTH >= 4 and BOARDHEIGHT >= 4, 'Board must be at least 4x4.'#if not Expression:# raise AssertionError(arguments)#assert语句可以等价为此#python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。#可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常。DIFFICulTY = 2 # 难度系数,计算机能够考虑的移动级别 #这里2表示,考虑对手走棋的7种可能性及如何应对对手的7种走法SPACESIZE = 50 # 棋子的大小FPS = 30 # 屏幕的更新频率,即30/s#所谓的FPS其实就是指游戏画面刷新帧频(游戏画面刷新频率),也就是说游戏中每秒钟能够绘制多少次图像。# 我们看到的动画其实就是一系列的图片快速的刷新产生的,每秒钟帧数越多,所显示的动作就会越流畅WINDOWWIDTH = 640 # 游戏屏幕的宽度像素WINDOWHEIGHT = 480 # 游戏屏幕的高度像素Xmargin = int((WINDOWWIDTH - BOARDWIDTH * SPACESIZE) / 2)#X边缘坐标量,即格子栏的最左边Ymargin = int((WINDOWHEIGHT - BOARDHEIGHT * SPACESIZE) / 2)#Y边缘坐标量,即格子栏的最上边BRIGHTBLUE = (0, 50, 255)#蓝色WHITE = (255, 255, 255)#白色BGcolor = BRIGHTBLUETEXTcolor = WHITERED = 'red'BLACK = 'black'EMPTY = NoneHUMAN = 'human'COmpuTER = 'computer'
在这里定义了一些游戏框架的基本变量,如棋子盘的参数,棋子的参数,边缘坐标参数,颜色,游戏的难度等等…
二、主函数maindef main(): global FPSCLOCK, disPLAYSURF, REDPILERECT, BLACKPILERECT, REDTOKENimg global BLACKTOKENimg, BOARDimg, ARROWimg, ARROWRECT, HUMANWINNERimg global COmpuTERWINNERimg, WINNERRECT, TIEWINNERimg pygame.init() FPSCLOCK = pygame.time.Clock() #初始化游戏窗口,创建一个对象来帮助跟踪时间 disPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) #游戏窗口标题, 初始化一个准备显示的窗口或屏幕 pygame.display.set_caption('Four in a Row') #设置窗口说明文字 REDPILERECT = pygame.Rect(int(SPACESIZE / 2), WINDOWHEIGHT - int(3 * SPACESIZE / 2), SPACESIZE, SPACESIZE) #创建窗口左下和右下角的棋子 #Rect 是用于存储矩形坐标的 Pygame 对象。 BLACKPILERECT = pygame.Rect(WINDOWWIDTH - int(3 * SPACESIZE / 2), WINDOWHEIGHT - int(3 * SPACESIZE / 2), SPACESIZE, SPACESIZE) #载入红色棋子图片 REDTOKENimg = pygame.image.load('images/4rowred.png') #将红色棋子图片缩放为SPACESIZE #pygame.transform.smoothscale - 平滑地将曲面缩放到任意大小 REDTOKENimg = pygame.transform.smoothscale(REDTOKENimg, (SPACESIZE, SPACESIZE)) #黑色棋子 BLACKTOKENimg = pygame.image.load('images/4rowblack.png') #将黑色棋子图片缩放为SPACESIZE BLACKTOKENimg = pygame.transform.smoothscale(BLACKTOKENimg, (SPACESIZE, SPACESIZE)) #载入棋子面板图片 BOARDimg = pygame.image.load('images/4rowboard.png') #将棋子面板图片缩放为SPACESIZE BOARDimg = pygame.transform.smoothscale(BOARDimg, (SPACESIZE, SPACESIZE)) #载入人胜利时图片 HUMANWINNERimg = pygame.image.load('images/4rowhumanwinner.png') #载入AI胜利时图片 COmpuTERWINNERimg = pygame.image.load('images/4rowcomputerwinner.png') #载入平局图片 TIEWINNERimg = pygame.image.load('images/4rowtIE.png') #返回Rect实例 WINNERRECT = HUMANWINNERimg.get_rect() #游戏窗口中间位置坐标 WINNERRECT.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) #载入 *** 作提示图片 ARROWimg = pygame.image.load('images/4rowarrow.png') #返回Rect实例 ARROWRECT = ARROWimg.get_rect() # *** 作提示的左位置 ARROWRECT.left = REDPILERECT.right + 10 #将 *** 作提示与下方红色棋子实例在纵向对齐 ARROWRECT.centery = REDPILERECT.centery isFirstGame = True while True: runGame(isFirstGame) isFirstGame = False
在主函数中,大部分的代码都是在描述设置一些实体信息,例如载入图片,设置Rect对象等等。在最后设置了一个isFirstGame,根据是否是第一局游戏的判断对接下来的游戏步骤产生影响,运行rungame(),由此可见,rungame()函数才是游戏得以运行的实体程序。
二、runGame()def runGame(isFirstGame): if isFirstGame: turn = COmpuTER #先手 showHelp = True #提示图片 else: if random.randint(0, 1) == 0: #在零和一之间随机选取一个数字 turn = COmpuTER #若随机数是零则电脑是先手 else: turn = HUMAN showHelp = False #第二局不展示帮助 mainBoard = getNewBoard() while True: if isBoardFull(mainBoard): winnerimg = TIEWINNERimg break if turn == HUMAN: getHumanMove(mainBoard, showHelp) if showHelp: showHelp = False if isWinner(mainBoard, RED): winnerimg = HUMANWINNERimg break turn = COmpuTER else: column = getComputerMove(mainBoard) animateComputerMoving(mainBoard, column) makeMove(mainBoard, BLACK, column) if isWinner(mainBoard, BLACK): winnerimg = COmpuTERWINNERimg break turn = HUMAN while True: drawBoard(mainBoard) disPLAYSURF.blit(winnerimg, WINNERRECT) pygame.display.update() FPSCLOCK.tick() for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE): #如果用户按到这些键,游戏停止 pygame.quit() sys.exit() elif event.type == MOUSEbuttonUP: #松开鼠标键 return
三、余下函数1. getNewBoard()产生值为空的BOARDHEIGHT*BOARDWIDTH的矩阵
def getNewBoard(): board = [] for x in range(BOARDWIDTH): board.append([EMPTY] * BOARDHEIGHT) return board #返回board列表,其值为BOARDHEIGHT数量的None #产生值为空的BOARDHEIGHT*BOARDWIDTH的矩阵
2.def isBoardFull(board)逐个检查矩阵的每一个以便于判断矩阵有没有放满
def isBoardFull(board): for x in range(BOARDWIDTH): for y in range(BOARDHEIGHT): if board[x][y] == EMPTY: return False return True #逐个检查矩阵的每一个以便于判断矩阵有没有放满
3.def getHumanMove(board, isFirstMove):判断人对棋子所做的事件并作出一系列反应。
def getHumanMove(board, isFirstMove): draggingToken = False #拖动 tokenx, tokeny = None, None while True: # pygame.event.get()来处理所有的事件 for event in pygame.event.get(): #停止,退出 if event.type == QUIT: pygame.quit() sys.exit() #如果事件类型为鼠标按下,notdraggingToken为True,鼠标点击的位置在REDPILERECT里面 elif event.type == MOUSEbuttonDOWN and not draggingToken and REDPILERECT.collIDepoint(event.pos): #evebt.pos 鼠标坐标 draggingToken = True tokenx, tokeny = event.pos #如果开始拖动了红色棋子 elif event.type == MOUSEMOTION and draggingToken: #更新被拖拽的棋子的位置 tokenx, tokeny = event.pos elif event.type == MOUSEbuttonUP and draggingToken: #如果棋子被拖拽在board的正上方 if tokeny < Ymargin and tokenx > Xmargin and tokenx < WINDOWWIDTH - Xmargin: #根据棋子的x坐标确定棋子会落的列(0,1...6) column = int((tokenx - Xmargin) / SPACESIZE) if isValIDMove(board, column): #棋子掉落,显示掉落效果 animateDropPingToken(board, column, RED) #将空格中最下面的格子设为红色 board[column][getLowestemptySpace(board, column)] = RED #落入的格子中划红色棋子 drawBoard(board) #窗口更新 pygame.display.update() return tokenx, tokeny = None, None draggingToken = False if tokenx != None and tokeny != None: #如果拖动了棋子,则显示拖动的棋子,并且通过调整x,y的坐标使拖动时,鼠标始终位于棋子的中心位置。 drawBoard(board, {'x':tokenx - int(SPACESIZE / 2), 'y':tokeny - int(SPACESIZE / 2), 'color':RED}) else: #当为无效移动时,鼠标松开后,因为此时board中所有格子的值均为none #调用drawBoard时,进行的 *** 作是显示下面的两个棋子,相当于棋子回到到开始拖动的地方 drawBoard(board) if isFirstMove: #AI先走,显示提示 *** 作图片 disPLAYSURF.blit(ARROWimg, ARROWRECT) pygame.display.update() FPSCLOCK.tick()
4.def isValIDMove(board, column)判断此步的移动是否是有效的。
def isValIDMove(board, column): if column < 0 or column >= (BOARDWIDTH) or board[column][0] != EMPTY: return False return True
5.def animateDropPingToken(board, column, color)显示掉落的动画。
def animateDropPingToken(board, column, color): x = Xmargin + column * SPACESIZE #定位掉落位置的坐标,此时默认为第n列最下面 y = Ymargin - SPACESIZE dropSpeed = 1.0#棋子降落的速度 lowestemptySpace = getLowestemptySpace(board, column)#获得此时最低的空位置 while True: y += int(dropSpeed)#y的坐标以dropSpeed叠加 dropSpeed += 0.5#dropSpeed也在加速,即棋子下落的加速度为0.5 #判断到达最下面的空格 if int((y - Ymargin) / SPACESIZE) >= lowestemptySpace: return #y不断变化,不断绘制红色棋子,形成不断降落的效果 drawBoard(board, {'x':x, 'y':y, 'color':color}) pygame.display.update() FPSCLOCK.tick()
6.def getLowestemptySpace(board, column)循环查找最低的空格子。
def getLowestemptySpace(board, column): for y in range(BOARDHEIGHT-1, -1, -1): if board[column][y] == EMPTY: return y return -1
7.def isWinner(board, tile)暴力扫描棋盘中的棋子判断是否是四种获胜方法的其中一种。
def isWinner(board, tile): for x in range(BOARDWIDTH - 3): for y in range(BOARDHEIGHT): if board[x][y] == tile and board[x+1][y] == tile and board[x+2][y] == tile and board[x+3][y] == tile: return True for x in range(BOARDWIDTH): for y in range(BOARDHEIGHT - 3): if board[x][y] == tile and board[x][y+1] == tile and board[x][y+2] == tile and board[x][y+3] == tile: return True for x in range(BOARDWIDTH - 3): for y in range(3, BOARDHEIGHT): if board[x][y] == tile and board[x+1][y-1] == tile and board[x+2][y-2] == tile and board[x+3][y-3] == tile: return True for x in range(BOARDWIDTH - 3): for y in range(BOARDHEIGHT - 3): if board[x][y] == tile and board[x+1][y+1] == tile and board[x+2][y+2] == tile and board[x+3][y+3] == tile: return True return False
8、def getComputerMove(board)获取电脑的移动。
def getComputerMove(board): potentialMoves = getpotentialMoves(board, BLACK, DIFFICulTY) bestMoves = [] bestMovefitness = -BOARDWIDTH for i in range(len(potentialMoves)): if potentialMoves[i]>bestMovefitness and isValIDMove(board,i): bestMovefitness = potentialMoves[i] for i in range(len(potentialMoves)): if potentialMoves[i] == bestMovefitness and isValIDMove(board, i): bestMoves.append(i) return random.choice(bestMoves)
9.def getpotentialMoves(board, tile, depth)分析对手潜在的移动轨迹。
def getpotentialMoves(board, tile, depth): if depth == 0 or isBoardFull(board): return [0] * BOARDWIDTH #确定对手棋子颜色 if tile == RED: enemyTile = BLACK else: enemyTile = RED #初始一个潜在的移动列表,其数值全部为0 potentialMoves = [0] * BOARDWIDTH for firstMove in range(BOARDWIDTH): #对每一栏进行遍历,将双方中的任一方的移动称为firstMove #则另外一方的移动就称为对手,counterMove。 #这里我们的firstMove为AI,对手为玩家。 dupeBoard = copy.deepcopy(board)#可换成回溯的方式,那样就不用每次都深拷贝了 #这里用深复制是为了让board和dupeBoard不互相影响 if not isValIDMove(dupeBoard, firstMove): continue #如果是有效移动,则设置相应的格子颜色 makeMove(dupeBoard, tile, firstMove) if isWinner(dupeBoard, tile): potentialMoves[firstMove] = 1 #获胜的棋子自动获得一个很高的数值来表示其获胜的几率 #数值越大,获胜可能性越大,对手获胜可能性越小。 break #不要干扰计算其他的移动 else: if isBoardFull(dupeBoard): #如果dupeBoard中没有空格,无法移动 potentialMoves[firstMove] = 0 else: for counterMove in range(BOARDWIDTH): #考虑对手移动 dupeBoard2 = copy.deepcopy(dupeBoard) if not isValIDMove(dupeBoard2, counterMove): continue makeMove(dupeBoard2, enemyTile, counterMove) #玩家获胜 if isWinner(dupeBoard2, enemyTile): potentialMoves[firstMove] = -1 break else: #递归调用 results = getpotentialMoves(dupeBoard2, tile, depth - 1) potentialMoves[firstMove] += (sum(results)*1.0 / BOARDWIDTH) / BOARDWIDTH #求适应度fitness return potentialMoves
10.def animateComputerMoving(board, column)def animateComputerMoving(board, column): x = BLACKPILERECT.left y = BLACKPILERECT.top speed = 1.0 while y > (Ymargin - SPACESIZE): y -= int(speed) speed += 0.5 drawBoard(board, {'x':x, 'y':y, 'color':BLACK}) pygame.display.update() FPSCLOCK.tick() y = Ymargin - SPACESIZE speed = 1.0 while x > (Xmargin + column * SPACESIZE): x -= int(speed) speed += 0.5 drawBoard(board, {'x':x, 'y':y, 'color':BLACK}) pygame.display.update() FPSCLOCK.tick() animateDropPingToken(board, column, BLACK)
11.def drawBoard(board, extraToken=None)def drawBoard(board, extraToken=None): #disPLAYSURF 是我们的界面,在初始化变量模块中有定义 disPLAYSURF.fill(BGcolor)#将游戏窗口背景色填充为蓝色 spaceRect = pygame.Rect(0, 0, SPACESIZE, SPACESIZE)#创建Rect实例 for x in range(BOARDWIDTH): #确定每一列中每一行中的格子的左上角的位置坐标 for y in range(BOARDHEIGHT): spaceRect.topleft = (Xmargin + (x * SPACESIZE), Ymargin + (y * SPACESIZE)) #x =0,y =0时,即第一列第一行的格子。 if board[x][y] == RED:#如果格子值为红色 #则在在游戏窗口的spaceRect中画红色棋子 disPLAYSURF.blit(REDTOKENimg, spaceRect) elif board[x][y] == BLACK: #否则画黑色棋子 disPLAYSURF.blit(BLACKTOKENimg, spaceRect) # extraToken 是包含了位置信息和颜色信息的变量 # 用来显示指定的棋子 if extraToken != None: if extraToken['color'] == RED: disPLAYSURF.blit(REDTOKENimg,(extraToken['x'], extraToken['y'], SPACESIZE, SPACESIZE)) elif extraToken['color'] == BLACK: disPLAYSURF.blit(BLACKTOKENimg, (extraToken['x'], extraToken['y'], SPACESIZE, SPACESIZE)) # 画棋子面板 for x in range(BOARDWIDTH): for y in range(BOARDHEIGHT): spaceRect.topleft = (Xmargin + (x * SPACESIZE), Ymargin + (y * SPACESIZE)) disPLAYSURF.blit(BOARDimg, spaceRect) # 画游戏窗口中左下角和右下角的棋子 disPLAYSURF.blit(REDTOKENimg, REDPILERECT) # 左边的红色棋子 disPLAYSURF.blit(BLACKTOKENimg, BLACKPILERECT) # 右边的黑色棋子
12.def makeMove(board, player, column)移动。
def makeMove(board, player, column): lowest = getLowestemptySpace(board, column) if lowest != -1: board[column][lowest] = player
望给予建议并指正。 总结
以上是内存溢出为你收集整理的python项目阅读记录——四子棋全部内容,希望文章能够帮你解决python项目阅读记录——四子棋所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)