- 案例目的
本章案例研究,通过井字棋游戏案例帮助读者深入了解,使用数据结构和算法实现游戏,人工智能井字棋游戏包括较为复杂的计算机人工智能落子算法,判断输赢算法等,通过把不同功能定义为独立的函数,可以减少程序的复杂性。
- 案例内容
井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似,由于棋盘一般不画边框,格线排成井字故得名。游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线,则为获胜。
表 1棋谱类型("+"是指“眼”)
A型(O胜) | B型(X胜) | C型(O胜) |
|
|
|
三、
~ 实验环境
Pycharm、Anaconda
四、设计实现
4.1 设计思路
棋盘采用包含3*3个元素的列表来表示,board[o]到board[8]存储代表棋子的字符串,字符串中可以包含"X"、"O"、或者数字0到8(表示未落子)。
程序的流程如下:
(1)初始化棋盘;
(2)询问玩家选择棋子:棋子X先走,棋子0后走;
(3)显示棋盘及落子布局(调用函数display_board() ) ;
(4)循环轮流落子:
(4-1)如果玩家落子,则询问落子位置(调用函数getPlayerMove() ,然后判断玩家是否获胜(调用函数isWinner() ) ,如果获胜,显示棋盘(调用函数display_board()),输出信息,break跳出循环;
(4-2)如果计算机人工智能(AI)落子,则根据计算机人工智能(AI)落子算法计算落子位置,然后判断AI是否获胜(调用函数isWinner()),如果AI获胜,则显示棋盘(调用函数display_board()),输出信息, break跳出循环;
(4-3)判断是否平局(调用函数isTie()),如果平局,则显示棋盘(调用函数display_board()),输出信息,break跳出循环;否则继续轮流落子。
计算机人工智能(AI)落子算法如下:
(1)如果某位置落子可以获胜,则选择该位置;
(2)否则,如果某个位置玩家下一步落子可以获胜,则选择该位置;
(3)否则,按中心(4)、角(0、2、6、8)、边(1、3、5、7)顺序选择空的位置。
判断输赢规则如下:如果三条横线((0,1,2),(3,4,5),(6,7,8))、三条竖线((0,3,6),(1,4,7),(2,5,8))、两条对角线((0,4,8),(2,4,6))共八种情况的三个位置的棋子相同,则该棋子方赢棋。如果全部位置落子,则平局。
图 1 井字棋流程
4.2 代码实现
def display_board(b):
"""显示棋盘"""
print("\t{0}|{1}|{2}".format(b[0], b[1], b[2]))
print("\t_|_|_")
print("\t{0}|{1}|{2}".format(b[3], b[4], b[5]))
print("\t_|_|_")
print("\t{0}|{1}|{2}".format(b[6], b[7], b[8]))
def legal_moves(board):
"""返回可下棋的位置列表"""
moves = []
for i in range(9):
if board[i] in list("012345678"):
moves.append(i)
return moves
def getPlayerMove(board):
"""询问并确定玩家(player)选择落子位置,无效位置时重复询问"""
move = 9 # 初始值9为错误的位置
while move not in legal_moves(board):
move = int(input("请选择落子位置(0-8):"))
return move
def getComputerMove(board, computerLetter, playerLetter):
"""计算人工智能AI的落子位置, Tic Tac Toe AI核心算法"""
boardcopy = board.copy() # 拷贝棋盘,不影响原来
# 规则1:判断如果某位置落子可获胜,则选择该位置
for move in legal_moves(boardcopy):
boardcopy[move] = computerLetter
if isWinner(boardcopy, computerLetter): # 判断是否获胜
return move
boardcopy[move] = str(move)
# 规则2:某个位置玩家下一步落子可获胜,则选择该位置
for move in legal_moves(boardcopy):
boardcopy[move] = playerLetter
if isWinner(boardcopy, playerLetter): # 判断是否获胜
return move
boardcopy[move] = str(move)
# 规则2:中心(4)、角(0、2、6、8)、边(1、3、5、7)顺序选择空的位置
for move in (4, 0, 2, 6, 8, 1, 3, 5, 7):
if move in legal_moves(board):
return move
def isWinner(board, letter):
"""判断所给的棋子是否获胜"""
WAYS_TO_WIN = {(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8),
(0, 4, 8), (2, 4, 6)}
for r in WAYS_TO_WIN:
if board[r[0]] == board[r[1]] == board[r[2]]:
return True
return False
def isTie(board):
"""判断是否平局"""
for i in list("012345678"):
if i in board:
return False
return True
def tic_tac_toe():
"""井字棋"""
# 初始化棋盘为['0', '1', '2', '3', '4', '5', '6', '7', '8']
board = list("012345678")
# 询问玩家选择棋子:棋子X先走,棋子O后走
playerLetter = input("请选择棋子X或O(X先走,O后走):")
if playerLetter in ("X", "x"):
turn = "player" # 玩家先走
computerLetter = "O"
else:
turn = "computer"
computerLetter = "X"
playerLetter = "O"
print("{}先走!".format(turn))
while True: # 循环轮流落子
display_board(board)
if turn == 'player': # 玩家落子
move = getPlayerMove(board) # 询问落子位置
board[move] = playerLetter # 落子
if isWinner(board, playerLetter): # 判断是否获胜
display_board(board)
print('恭喜玩家获胜!')
break
else:
turn = "computer"
else: # 计算机落子
# 计算机落子位置
move = getComputerMove(board, computerLetter, playerLetter)
print("计算机人工智能AI落子位置:", move)
board[move] = computerLetter # 落子
if isWinner(board, computerLetter): # 判断是否获胜
display_board(board)
print('计算机人工智能AI获胜!')
break
else:
turn = "player"
# 判断是否平局
if isTie(board):
display_board(board)
print('平局!')
break
if __name__ == '__main__':
tic_tac_toe()
4.3 测试结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)