2.2 编写第一个小游戏
本书以游戏为编程主题,下面就让我们尝试编写一个井字棋游戏来热身。编写该游戏一方面是为了复习我们以前学过的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
这个游戏是不是很简单。读者可以先试着玩一下。如果不能很好地理解这些代码,可以进入调试模式慢慢理解每行代码完成的任务。如果你对某些语法不熟悉,可以先复习、巩固对应的知识。