Python游戏编程(八)Reversegam

Reversegam是一款在格子上玩的游戏版游戏,所以我们将使用带有XY坐标的一个笛卡尔坐标系。

主要内容

  • 如何玩Reversegam游戏
  • bool函数
  • 模拟在Reversegam游戏版上移动
  • 编写一个Reversegam AI程序

目录

如何玩Reversegam

导入模块和设置常量

游戏板的数据结构

自定义函数分析

(一)drawBoard(board):

(二)getNewBoard():

(三)def isValidMove(board, tile, xstart, ystart):

(四)isOnBoard(x, y):

(五)getBoardWithValidMoves(board, tile):

(六)getValidMoves(board, tile):

(七)getScoreOfBoard(board):

(八)enterPlayerTile():

(九)whoGoesFirst():

(十)makeMove(board, tile, xstart, ystart):

(十一)getBoardCopy(board):

(十二)isOnCorner(x, y):

(十三)getPlayerMove(board, playerTile):

(十四)getComputerMove(board, computerTile):

(十五)playGame(playerTile, computerTile):

(十六)游戏循环


如何玩Reversegam

Reversegam有一个8*8的游戏版,一方的棋子是黑色,另一方的棋子是白的(我们使用O和X来代替这两种颜色),开始的时候游戏版如图所示:

Python游戏编程(八)Reversegam_第1张图片

假设白子先走,那么可能的结果

Python游戏编程(八)Reversegam_第2张图片

Python游戏编程(八)Reversegam_第3张图片

Python游戏编程(八)Reversegam_第4张图片

轮流落子,一直到任意一位玩家不能落子或游戏板填满了的时候,游戏就结束了。剩下的棋子多的获胜。

 

导入模块和设置常量

# Reversegam: a clone of Othello/Reversi
# 导入random模块以便使用randint()函数和chice()函数。
import random
# 导入sys模块,以便使用exit()函数
import sys
# 定义两个常量用于设置游戏版
WIDTH = 8 # Board is 8 spaces wide.
HEIGHT = 8 # Board is 8 spaces tall.

 

游戏板的数据结构

这个数据结构是列表的列表,就像之前Sonar游戏中的游戏版一样。创建列表的列表,以便使用board[x][y]来表示坐落于X坐标轴(向左/向右)上的x位置和坐落于Y坐标轴(向上/向下)上的y位置的格子上的字符。

尽管游戏版的X坐标和Y坐标的范围是1到8,但列表数据结构的范围将会是从0到7,注意到这一点很重要。我们的代码将需要根据这一点来做一些调整。

 

 

 

自定义函数分析

Reversegam游戏通过自定义了16个函数来实现相关功能和计算机AI,下面将详细分析每一个自定义的函数中所涉及的Python语法以及在Reversegam游戏中所扮演的角色。

 

 

(一)drawBoard(board):

 

# 在屏幕上绘制游戏版数据结构
def drawBoard(board):
   # Print the board passed to this function. Return None.
    print('  12345678')
    print(' +--------+')
    for y in range(HEIGHT):
        print('%s|' % (y+1), end='')
        for x in range(WIDTH):
            print(board[x][y], end='')
        print('|%s' % (y+1))
    print(' +--------+')
    print('  12345678')

涉及的主要Python语法:

  • def定义函数
  • 函数形参
  • print()函数
  • for循环迭代   
  • range()函数
  • 格式化字符串

以上所涉及到的语法都是我们之前所使用过的。

drawBoard()函数接受一个列表值,并且将其显示到屏幕上,以便玩家知道在哪里下棋子。通过for循环迭代将board列表的列表打印到屏幕上,注意print()函数中(y + 1)实现游戏版左边和右边的标签是从1到8,end=' '实现打印完一个字符之后不换行。

 

(二)getNewBoard():

 

# 创建一个新的游戏版数据结构
def getNewBoard():
  # Create a brand-new, blank board data structure.
    board = []
    for i in range(WIDTH):
        board.append([' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '])
    return board

涉及的主要Python语法:

  • 无形参函数
  • 列表append()方法
  • return关键字

该函数返回一个列表的列表。

 

(三)def isValidMove(board, tile, xstart, ystart):

 

这个函数有点儿长

通过流程图来理解函数作用:

Python游戏编程(八)Reversegam_第5张图片

涉及的主要Python语法:

  • 比较操作符
  • 布尔运算
  • 复合赋值操作符
  • while循环
  • len()函数
  • if语句

给定了一个游戏版数据结构(board)、玩家的棋子(tile)以及玩家落子地XY坐标(xstart, ystart),如果Reversegam游戏规则允许在该坐标上落子,isValidMove()函数应该返回True;否则,它返回False。

对于一次有效地移动,必须满足:

  1. 它必须位于游戏版之上;
  2. 至少能够反转对手的一个棋子。

确定玩家(人类玩家和计算机玩家)棋子的类型

最后,如果给定的X坐标和Y坐标最终是一个有效位置,那么isValidMove()函数返回这一步落子可能导致反转的对手的所有棋子的一个列表。我们创建了一个新的、空的列表tilesToFlip,并且用它来存储所有这些棋子的坐标。

 

# 判断一次落子是否有效
def isValidMove(board, tile, xstart, ystart):
    # Return False if the player's move on space xstart, ystart is invalid.
    # If it is a valid move, return a list of spaces that would 
    # become the player's if they made a move here.
    # 检查坐标是否在游戏版上、是否为空
    if board[xstart][ystart] != ' ' or not isOnBoard(xstart, ystart):
        return False
    
    # 确定玩家棋子的类型
    if tile == 'X':
        otherTile = 'O'
    else:
        otherTile = 'X'

    tilesToFlip = []

    # 遍历两元素列表中的每一个,以便对每个方向都进行检查。
    for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1],
           [0, -1], [-1, -1], [-1, 0], [-1, 1]]:
        x, y = xstart, ystart       # 多变量赋值
        x += xdirection # First step in the x direction
        y += ydirection # First step in the y direction
        while isOnBoard(x, y) and board[x][y] == otherTile:
            # Keep moving in this x & y direction.
            x += xdirection
            y += ydirection
            if isOnBoard(x, y) and board[x][y] == tile:
                
                # There are pieces to flip over. Go in the reverse direction 
                # until we reach the original space, noting all the tiles along the way.
                while True:
                
                    x -= xdirection
                    y -= ydirection
                    if x == xstart and y == ystart:
                        break
                    tilesToFlip.append([x, y])
    if len(tilesToFlip) == 0: # If no tiles were flipped, this is not a valid move.
        return False
    return tilesToFlip

为了检查一次落子是否有效,它使用当前玩家的新的棋子,将对手的棋子夹在这个新的棋子和玩家的一个旧的棋子之间,从而至少能够反转对手的一个棋子。这意味着,新的棋子必须紧挨着对手的一个棋子。

for循环遍历了列表的一个列表,表示了程序将要检查对手的一个棋子的方向:

    for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1],
            [0, -1], [-1, -1], [-1, 0], [-1, 1]]:

游戏板使用X坐标和Y坐标表示的笛卡尔坐标系。这里有8个可以移动的方向:上下左右和四个对角线方向。通过Y坐标不变、X坐标加减1实现向右向左移动;通过X坐标不变、Y坐标加减1实现向下上移动;对于四个对角线方向,需要XY坐标同时加减实现。下图表示了元素列表中的哪一项表示哪一个方向:

Python游戏编程(八)Reversegam_第6张图片

for循环遍历了两元素列表中的每一个,以便对每个方向都进行检查。在for循环中使用了多变量赋值。

    for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1],
           [0, -1], [-1, -1], [-1, 0], [-1, 1]]:
        x, y = xstart, ystart
        x += xdirection # First step in the x direction
        y += ydirection # First step in the y direction

变量xstart、ystart保持不变,以便程序可以记住最初是从哪个格子开始的。

 

为了让移动成为有效的移动,必须满足:

  1. 在游戏板上
  2. 必须被对手玩家的棋子所占据,因为要保证我方能够反转对方的棋子
        while isOnBoard(x, y) and board[x][y] == otherTile:
            # Keep moving in this x & y direction.
            x += xdirection
            y += ydirection

如果满足以上条件,则继续执行。继续判断是否有相邻的棋子可以反转。

            if isOnBoard(x, y) and board[x][y] == tile:
                
                # There are pieces to flip over. Go in the reverse direction 
                # until we reach the original space, noting all the tiles along the way.
                while True:
                
                    x -= xdirection
                    y -= ydirection
                    if x == xstart and y == ystart:
                        break
                    tilesToFlip.append([x, y])

 

如果满足条件,则将位置记录到tilesToFlip列表中。

 

 

 

(四)isOnBoard(x, y):

 

# 检查X坐标和Y坐标是否在游戏版上。
def isOnBoard(x, y):
    # Return True if the coordinates are located on the board.
    return x >= 0 and x <= WIDTH - 1 and y >= 0 and y <= HEIGHT - 1

isOnBoard()是isValidMove()调用的一个函数。它简单地检查了X坐标和Y坐标是否在游戏版上。通过给定地坐标值来返回布尔值。

(五)getBoardWithValidMoves(board, tile):

该数据板作为提示用。getBoardWithValidMoves()返回一个游戏版数据结构,所有有效移动的格子都使用字符'.'表示。这个函数创建了board数据结构的一个副本,用来返回标记了有效移动的点。

# 返回一个游戏版数据结构
def getBoardWithValidMoves(board, tile):
    # Return a new board with periods marking the valid moves the player can make.
    boardCopy = getBoardCopy(board)

    for x, y in getValidMoves(boardCopy, tile):
        boardCopy[x][y] = '.'
    return boardCopy

 

(六)getValidMoves(board, tile):

getValidMoves()函数返回了包含两元素列表的一个列表,这些列表保存了给定的tile可以在参数board中的游戏板数据结构中进行的所有的有效移动的XY坐标。

# 得到所有有效移动的一个列表
def getValidMoves(board, tile):
    # Return a list of [x,y] lists of valid moves for the given player      on the given board.
    validMoves = []
    for x in range(WIDTH):
        for y in range(HEIGHT):
            if isValidMove(board, tile, x, y) != False:
                validMoves.append([x, y])
    return validMoves

其中 isValidMove(board, tile, x, y) != False: 可以看出某些值是可以做布尔比较并且返回布尔值的。

对于bool()函数

>>> bool(0)
False
>>> bool(0.0)
False
>>> bool('')
False
>>> bool([])
False
>>> bool({})
False
>>> bool(1)
True
>>> bool('Hello')
True
>>> bool([1, 2, 3, 4])
True
>>> bool({'spam':'cheese', 'fizz':'buzz'})
True

 

(七)getScoreOfBoard(board):

getScoreOfBoard()函数使用嵌套for循环检查给定的游戏板上的所有64个格子(8行8列)对格子上的X和O进行计数并保存到字典中。该函数返回这个字典。

def getScoreOfBoard(board):
     # Determine the score by counting the tiles. Return a dictionary with keys 'X' and 'O'.
    xscore = 0
    oscore = 0
    for x in range(WIDTH):
        for y in range(HEIGHT):
            if board[x][y] == 'X':
                xscore += 1
            if board[x][y] == 'O':
                oscore += 1
    return {'X':xscore, 'O':oscore}

 

(八)enterPlayerTile():

询问玩家想要什么棋子,是X还是O。这个while循环将一直循环,知道玩家输入'X'或'O'。返回两元素的一个列表,第一个元素是玩家玩家棋子,第二个元素是计算机棋子。

# 获取玩家的棋子选择
def enterPlayerTile():
    # Let the player enter which tile they want to be.
    # Return a list with the player's tile as the first item and the computer's tile as the second.
    tile = ''
    while not (tile == 'X' or tile == 'O'):
        print('Do you want to be X or O?')
        tile = input().upper()

     # The first element in the list is the player's tile, and the second is the computer's tile.
    if tile == 'X':
        return ['X', 'O']
    else:
        return ['O', 'X']

 

(九)whoGoesFirst():

决定谁先走,返回字符串。

# 决定谁先走
def whoGoesFirst():
    # Randomly choose who goes first.
    if random.randint(0, 1) == 0:
        return 'computer'
    else:
        return 'player'

 

(十)makeMove(board, tile, xstart, ystart):

这个函数根据用户输入的位置,判断该位置是否满足游戏要求,如果满足则在这个位置落子,如果不满足,则返回False.

# 在游戏版上落下一个棋子
def makeMove(board, tile, xstart, ystart):
    # Place the tile on the board at xstart, ystart and flip any of the      opponent's pieces.
    # Return False if this is an invalid move; True if it is valid.
    tilesToFlip = isValidMove(board, tile, xstart, ystart)

    if tilesToFlip == False:
        return False

    board[xstart][ystart] = tile
    for x, y in tilesToFlip:
        board[x][y] = tile
    return True

 

(十一)getBoardCopy(board):

这个函数将创建一个空白的游戏版数据结构,然后将board中的参数赋值过来存储在boardCopy中,从而的到一个board的副本。

# 复制游戏版的数据结构
def getBoardCopy(board):
    # Make a duplicate of the board list and return it.
    boardCopy = getNewBoard()

    for x in range(WIDTH):
        for y in range(HEIGHT):
            boardCopy[x][y] = board[x][y]

    return boardCopy

 

(十二)isOnCorner(x, y):

如果坐标是(0,0)、(7,0)、(0,7)和(7,7),那么这个格子位于游戏版的角落之上,isOnCorner()函数就返回True,否则返回False。

在后面的AI中将会使用这个函数。

# 判断一个格子是否在角落上
def isOnCorner(x, y):
    # Return True if the position is in one of the four corners.
    return (x == 0 or x == WIDTH - 1) and (y == 0 or y == HEIGHT - 1)

 

(十三)getPlayerMove(board, playerTile):

获取用户输入,如果输入quit或者hints直接返回输入,如果输入坐标值的话,则通过isValidMove()函数判断是否为有效移动,是则返回该坐标值,不是则继续获取用户输入。

# 获取玩家的移动
def getPlayerMove(board, playerTile):
    # Let the player enter their move.
    # Return the move as [x, y] (or return the strings 'hints' or      'quit').
    DIGITS1TO8 = '1 2 3 4 5 6 7 8'.split()
    while True:
        print('Enter your move, "quit" to end the game, or "hints" to toggle hints.')
        move = input().lower()
        if move == 'quit' or move == 'hints':
            return move

        if len(move) == 2 and move[0] in DIGITS1TO8 and move[1] in DIGITS1TO8:
            x = int(move[0]) - 1
            y = int(move[1]) - 1
            if isValidMove(board, playerTile, x, y) == False:
                continue
            else:
                break
        else:
            print('That is not a valid move. Enter the column (1-8) and then the row (1-8).')
            print('For example, 81 will move on the top-right corner.')

    return [x, y]

 

(十四)getComputerMove(board, computerTile):

这里先调用getValidMoves()函数,来判断计算机下一步优选的动作,并将顺序打乱,来防止玩家发现规律。

继续判断possibleMoves中位于角落中的位置,如果有,则函数返回这个坐标。如果没有,则继续:遍历possibleMoves列表,计算列表中每一步后的得分情况,筛选出来最高分坐标,函数返回这个坐标。

 

# 获取计算机的移动
def getComputerMove(board, computerTile):
    # Given a board and the computer's tile, determine where to
    # move and return that move as an [x, y] list.
    possibleMoves = getValidMoves(board, computerTile)
    random.shuffle(possibleMoves) # Randomize the order of the moves.

    # Always go for a corner if available.
    for x, y in possibleMoves:
        if isOnCorner(x, y):
            return [x, y]

    # Find the highest-scoring move possible.
    bestScore = -1
    for x, y in possibleMoves:
        boardCopy = getBoardCopy(board)
        makeMove(boardCopy, computerTile, x, y)
        score = getScoreOfBoard(boardCopy)[computerTile]
        if score > bestScore:
            bestMove = [x, y]
            bestScore = score
    return bestMove

 

(十五)playGame(playerTile, computerTile):

 

开始游戏:

# 游戏开始
def playGame(playerTile, computerTile):
    showHints = False
    turn = whoGoesFirst()
    print('The ' + turn + ' will go first.')
    
    # Clear the board and place starting pieces.
    board = getNewBoard()
    board[3][3] = 'X'
    board[3][4] = 'O'
    board[4][3] = 'O'
    board[4][4] = 'X'
    while True:
        playerValidMoves = getValidMoves(board, playerTile)
        computerValidMoves = getValidMoves(board, computerTile)
        
        if playerValidMoves == [] and computerValidMoves == []:
            return board # No one can move, so end the game.

        elif turn == 'player': # Player's turn
            if playerValidMoves != []:
                if showHints:
                    validMovesBoard = getBoardWithValidMoves(board, playerTile)
                    drawBoard(validMovesBoard)
                else:
                    drawBoard(board)
                printScore(board, playerTile, computerTile)

                move = getPlayerMove(board, playerTile)
                if move == 'quit':
                    print('Thanks for playing!')
                    sys.exit() # Terminate the program.
                elif move == 'hints':
                    showHints = not showHints
                    continue
                else:
                    makeMove(board, playerTile, move[0], move[1])
            turn = 'computer'

        elif turn == 'computer': # Computer's turn
            if computerValidMoves != []:
                drawBoard(board)
                printScore(board, playerTile, computerTile)

                input('Press Enter to see the computer\'s move.')
                move = getComputerMove(board, computerTile)
                makeMove(board, computerTile, move[0], move[1])
            turn = 'player'

 

(十六)游戏循环

 

print('Welcome to Reversegam!')

playerTile, computerTile = enterPlayerTile()

# 游戏循环
while True:
    finalBoard = playGame(playerTile, computerTile)

    # Display the final score.
    drawBoard(finalBoard)
    scores = getScoreOfBoard(finalBoard)
    print('X scored %s points. O scored %s points.' % (scores['X'], scores['O']))
    if scores[playerTile] > scores[computerTile]:
        print('You beat the computer by %s points! Congratulations!' % (scores[playerTile] - scores[computerTile]))
    elif scores[playerTile] < scores[computerTile]:
        print('You lost. The computer beat you by %s points.' % (scores[computerTile] - scores[playerTile]))
    else:
        print('The game was a tie!')

    print('Do you want to play again? (yes or no)')
    if not input().lower().startswith('y'):
        break

 

 

 

 

 

整个游戏的源代码:

 

# Reversegam: a clone of Othello/Reversi
import random
import sys
WIDTH = 8 # Board is 8 spaces wide.
HEIGHT = 8 # Board is 8 spaces tall.

# 在屏幕上绘制游戏版数据结构
def drawBoard(board):
   # Print the board passed to this function. Return None.
    print('  12345678')
    print(' +--------+')
    for y in range(HEIGHT):
        print('%s|' % (y+1), end='')
        for x in range(WIDTH):
            print(board[x][y], end='')
        print('|%s' % (y+1))
    print(' +--------+')
    print('  12345678')

# 创建一个新的游戏版数据结构
def getNewBoard():
  # Create a brand-new, blank board data structure.
    board = []
    for i in range(WIDTH):
        board.append([' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '])
    return board

# 判断一次落子是否有效
def isValidMove(board, tile, xstart, ystart):
    # Return False if the player's move on space xstart, ystart is invalid.
    # If it is a valid move, return a list of spaces that would 
    # become the player's if they made a move here.
    if board[xstart][ystart] != ' ' or not isOnBoard(xstart, ystart):
        return False

    if tile == 'X':
        otherTile = 'O'
    else:
        otherTile = 'X'

    tilesToFlip = []
    for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1],
           [0, -1], [-1, -1], [-1, 0], [-1, 1]]:
        x, y = xstart, ystart
        x += xdirection # First step in the x direction
        y += ydirection # First step in the y direction
        while isOnBoard(x, y) and board[x][y] == otherTile:
            # Keep moving in this x & y direction.
            x += xdirection
            y += ydirection
            if isOnBoard(x, y) and board[x][y] == tile:
                
                # There are pieces to flip over. Go in the reverse direction 
                # until we reach the original space, noting all the tiles along the way.
                while True:
                
                    x -= xdirection
                    y -= ydirection
                    if x == xstart and y == ystart:
                        break
                    tilesToFlip.append([x, y])
    if len(tilesToFlip) == 0: # If no tiles were flipped, this is not a valid move.
        return False
    return tilesToFlip

# 检查X坐标和Y坐标是否在游戏版上。
def isOnBoard(x, y):
    # Return True if the coordinates are located on the board.
    return x >= 0 and x <= WIDTH - 1 and y >= 0 and y <= HEIGHT - 1

# 返回一个游戏版数据结构
def getBoardWithValidMoves(board, tile):
    # Return a new board with periods marking the valid moves the player can make.
    boardCopy = getBoardCopy(board)

    for x, y in getValidMoves(boardCopy, tile):
        boardCopy[x][y] = '.'
    return boardCopy

# 得到所有有效移动的一个列表
def getValidMoves(board, tile):
    # Return a list of [x,y] lists of valid moves for the given player      on the given board.
    validMoves = []
    for x in range(WIDTH):
        for y in range(HEIGHT):
            if isValidMove(board, tile, x, y) != False:
                validMoves.append([x, y])
    return validMoves

# 计算游戏版的得分
def getScoreOfBoard(board):
     # Determine the score by counting the tiles. Return a dictionary     with keys 'X' and 'O'.
    xscore = 0
    oscore = 0
    for x in range(WIDTH):
        for y in range(HEIGHT):
            if board[x][y] == 'X':
                xscore += 1
            if board[x][y] == 'O':
                oscore += 1
    return {'X':xscore, 'O':oscore}

# 获取玩家的棋子选择
def enterPlayerTile():
    # Let the player enter which tile they want to be.
    # Return a list with the player's tile as the first item and the computer's tile as the second.
    tile = ''
    while not (tile == 'X' or tile == 'O'):
        print('Do you want to be X or O?')
        tile = input().upper()

     # The first element in the list is the player's tile, and the second is the computer's tile.
    if tile == 'X':
        return ['X', 'O']
    else:
        return ['O', 'X']

# 决定谁先走
def whoGoesFirst():
    # Randomly choose who goes first.
    if random.randint(0, 1) == 0:
        return 'computer'
    else:
        return 'player'

# 在游戏版上落下一个棋子
def makeMove(board, tile, xstart, ystart):
    # Place the tile on the board at xstart, ystart and flip any of the      opponent's pieces.
    # Return False if this is an invalid move; True if it is valid.
    tilesToFlip = isValidMove(board, tile, xstart, ystart)

    if tilesToFlip == False:
        return False

    board[xstart][ystart] = tile
    for x, y in tilesToFlip:
        board[x][y] = tile
    return True

# 复制游戏版的数据结构
def getBoardCopy(board):
    # Make a duplicate of the board list and return it.
    boardCopy = getNewBoard()

    for x in range(WIDTH):
        for y in range(HEIGHT):
            boardCopy[x][y] = board[x][y]

    return boardCopy

# 判断一个格子是否在角落上
def isOnCorner(x, y):
    # Return True if the position is in one of the four corners.
    return (x == 0 or x == WIDTH - 1) and (y == 0 or y == HEIGHT - 1)

# 获取玩家的移动
def getPlayerMove(board, playerTile):
    # Let the player enter their move.
    # Return the move as [x, y] (or return the strings 'hints' or      'quit').
    DIGITS1TO8 = '1 2 3 4 5 6 7 8'.split()
    while True:
        print('Enter your move, "quit" to end the game, or "hints" to toggle hints.')
        move = input().lower()
        if move == 'quit' or move == 'hints':
            return move

        if len(move) == 2 and move[0] in DIGITS1TO8 and move[1] in DIGITS1TO8:
            x = int(move[0]) - 1
            y = int(move[1]) - 1
            if isValidMove(board, playerTile, x, y) == False:
                continue
            else:
                break
        else:
            print('That is not a valid move. Enter the column (1-8) and then the row (1-8).')
            print('For example, 81 will move on the top-right corner.')

    return [x, y]

# 获取计算机的移动
def getComputerMove(board, computerTile):
    # Given a board and the computer's tile, determine where to
    # move and return that move as an [x, y] list.
    possibleMoves = getValidMoves(board, computerTile)
    random.shuffle(possibleMoves) # Randomize the order of the moves.

    # Always go for a corner if available.
    for x, y in possibleMoves:
        if isOnCorner(x, y):
            return [x, y]

    # Find the highest-scoring move possible.
    bestScore = -1
    for x, y in possibleMoves:
        boardCopy = getBoardCopy(board)
        makeMove(boardCopy, computerTile, x, y)
        score = getScoreOfBoard(boardCopy)[computerTile]
        if score > bestScore:
            bestMove = [x, y]
            bestScore = score
    return bestMove

# 在屏幕打印分数
def printScore(board, playerTile, computerTile):
    scores = getScoreOfBoard(board)
    print('You: %s points. Computer: %s points.' % (scores[playerTile],scores[computerTile]))

# 游戏开始
def playGame(playerTile, computerTile):
    showHints = False
    turn = whoGoesFirst()
    print('The ' + turn + ' will go first.')
    
    # Clear the board and place starting pieces.
    board = getNewBoard()
    board[3][3] = 'X'
    board[3][4] = 'O'
    board[4][3] = 'O'
    board[4][4] = 'X'
    while True:
        playerValidMoves = getValidMoves(board, playerTile)
        computerValidMoves = getValidMoves(board, computerTile)
        
        if playerValidMoves == [] and computerValidMoves == []:
            return board # No one can move, so end the game.

        elif turn == 'player': # Player's turn
            if playerValidMoves != []:
                if showHints:
                    validMovesBoard = getBoardWithValidMoves(board, playerTile)
                    drawBoard(validMovesBoard)
                else:
                    drawBoard(board)
                printScore(board, playerTile, computerTile)

                move = getPlayerMove(board, playerTile)
                if move == 'quit':
                    print('Thanks for playing!')
                    sys.exit() # Terminate the program.
                elif move == 'hints':
                    showHints = not showHints
                    continue
                else:
                    makeMove(board, playerTile, move[0], move[1])
            turn = 'computer'

        elif turn == 'computer': # Computer's turn
            if computerValidMoves != []:
                drawBoard(board)
                printScore(board, playerTile, computerTile)

                input('Press Enter to see the computer\'s move.')
                move = getComputerMove(board, computerTile)
                makeMove(board, computerTile, move[0], move[1])
            turn = 'player'



print('Welcome to Reversegam!')

playerTile, computerTile = enterPlayerTile()

# 游戏循环
while True:
    finalBoard = playGame(playerTile, computerTile)

    # Display the final score.
    drawBoard(finalBoard)
    scores = getScoreOfBoard(finalBoard)
    print('X scored %s points. O scored %s points.' % (scores['X'], scores['O']))
    if scores[playerTile] > scores[computerTile]:
        print('You beat the computer by %s points! Congratulations!' % (scores[playerTile] - scores[computerTile]))
    elif scores[playerTile] < scores[computerTile]:
        print('You lost. The computer beat you by %s points.' % (scores[computerTile] - scores[playerTile]))
    else:
        print('The game was a tie!')

    print('Do you want to play again? (yes or no)')
    if not input().lower().startswith('y'):
        break
    
  

 

 

 

Reversegam游戏的AI几乎无法战胜,但这并不是因为计算机很聪明,而只是因为它要快很多。它遵循的策略很简单:如果可以就在角落落子,否则执行将会反转最多棋子的移动。我们也可以做到这些,只不过没有计算机块。

 

 

参考:

  1. 菜鸟教程
  2. http://inventwithpython.com/invent4thed/chapter3.html
  3. 《Python游戏编程快速上手》第四版,AI Sweigart著,李强 译

 

 

你可能感兴趣的:(Python游戏编程)