本书以游戏为编程主题,下面就让我们尝试编写一个井字棋游戏来热身。编写该游戏一方面是为了复习我们以前学过的Python知识,另一方面也可以让我们更熟悉VS Code。
井字棋游戏很简单,它的棋盘是一个3×3的网格,玩家率先实现3颗棋子在一条直线上即可胜利。本游戏程序包含的核心数据就是棋盘信息,另外还需要若干函数来承载游戏功能,例如显示棋盘信息的函数、处理玩家输入的函数,以及判断棋局胜负的函数等。所有代码都在一个代码文件中。
首先定义几个变量,包括棋盘大小变量boardSize和棋盘信息变量board。我们会使用两种符号分别表示两个玩家的落子,其中一个玩家的落子使用字母符号“X”来表示,而另一个玩家的落子使用字母符号“O”来表示,当棋盘上还没有玩家落子时,所有位置都以符号“.”来表示。先手玩家使用字母符号“X”来落子,将落子信息保存在变量currentPlayer中。随后输出一些游戏提示信息。
boardSize=3 board=['.'] * boardSize * boardSize currentPlayer='X' print("井字棋游戏开始") print("规则:三子连成直线即胜利") print("X先手,O后手")
随后我们定义print_board函数,它负责在终端上显示棋盘信息。
def print_board(board): print("\n") print("%s|%s|%s"%(board[0],board[1],board[2])) print("-+-+-") print("%s|%s|%s"%(board[3],board[4],board[5])) print("-+-+-") print("%s|%s|%s"%(board[6],board[7],board[8]))
我们还需要一个函数来负责判断胜负。函数hasWon看起来很复杂,但其内在逻辑很简单,就是列举各种可能获胜的棋局状态,只要满足这种状态就返回True。如果觉得某个地方不容易理解,可以通过VS Code设置断点,并按键盘上的F5键进入调试模式,在调试模式下可以一步步地运行代码,以观察每个变量的值并理解代码的运行逻辑。
def hasWon(currentBoard,player): winningSet=[player in range(boardSize)] row1=currentBoard[:3] row2=currentBoard[3:6] row3=currentBoard[6:] if winningSet in [row1,row2,row3]: return True col1=[currentBoard[0],currentBoard[3],currentBoard[6]] col2=[currentBoard[1],currentBoard[4],currentBoard[7]] col3=[currentBoard[2],currentBoard[5],currentBoard[8]] if winningSet in[col1,col2,col3]: return True diag1=[currentBoard[0],currentBoard[4],currentBoard[8]] diag2=[currentBoard[6],currentBoard[4],currentBoard[2]] if winningSet in [diag1,diag2]: return True return False
因为两个玩家交替落子,所以需要定义getNextPlayer函数以交换当前玩家。
def getNextPlayer(currentPlayer): if currentPlayer=='X': return 'O' return 'X'
getPlayerMove函数用来处理玩家的输入。玩家输入的是坐标的形式,每次需要输入两个数字,数字之间以英文逗号间隔,数字取值为0~2。“X,Y”表示落子位置在棋盘上的第X行、第Y列。需要注意的是,该函数获取玩家输入后,会将这些输入信息通过字符串操作拆分成两部分,再转换成整数类型保存为坐标,最后将二维的坐标信息转换成一维的索引。判断当前棋盘的落子位置为空白位置时,就用当前玩家的表示落子的字母符号进行赋值。
def getPlayerMove(board,currentPlayer): isMoveValid=False while isMoveValid==False: print('') userMove=input(f'玩家{currentPlayer}输入棋盘坐标(坐标取值0,1,2): X,Y? ') userX, userY=[int(char) for char in userMove.split(',')] userIndex=userX * boardSize+userY if board[userIndex]=='.': isMoveValid=True board[userIndex]=currentPlayer return board
当棋盘上摆满棋子时,需要结束游戏,因此要定义一个hasMovesLeft函数来判断还有没有空白位置供玩家落子。
def hasMovesLeft(board): return '.' in board
最后将这些函数组装在一起。
if__name__=='__main__': print_board(board) while hasMovesLeft(board): board=getPlayerMove(board,currentPlayer) print_board(board) if hasWon(board, currentPlayer): print('Player'+currentPlayer+'haswon!') break currentPlayer=getNextPlayer(currentPlayer)
首先显示棋盘,只要棋盘上还有空白位置可以下棋,就保持运行游戏主循环中的代码。代码先处理玩家输入,显示新的棋盘;如果出现胜负结果,就显示相关信息。否则轮换玩家。游戏画面如图2-3所示。
图2-3
这个游戏是不是很简单。读者可以先试着玩一下。如果不能很好地理解这些代码,可以进入调试模式慢慢理解每行代码完成的任务。如果你对某些语法不熟悉,可以先复习、巩固对应的知识。