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来代替这两种颜色),开始的时候游戏版如图所示:

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

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

 

导入模块和设置常量

# 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语法:

  • 比较操作符
  • 布尔运算
  • 复合赋值操作符
  • 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坐标同时加减实现。下图表示了元素列表中的哪一项表示哪一个方向:

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

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值