python井字棋ai_实现AI下井字棋的alpha-beta剪枝算法(python实现)

代码参考自中国大学mooc上人工智能与信息社会陈斌老师的算法,我在原来的基础上增加了玩家输入的异常捕获 AlphaBeta剪枝算法是对Minimax方法的优化,能够极大提高搜索树的效率,如果对这个算法感兴趣的可以去参考相关资料。 当正确理解AlphaBeta剪枝算法后,还可以将它应用在象棋、围棋等一些高级游戏的算法搜索上,使得电脑寻找最优胜率的速度加快

python代码实现

#coding:utf-8

'''井字棋(Tic tac toe)Python3语言实现, 带有Alpha-Beta剪枝的Minimax算法.

代码参考自中国大学mooc 人工智能与信息社会(陈斌)'''

import random

# 用如下的9个数字来表示棋盘的位置:

# 0  1  2

# 3  4  5

# 6  7  8

# 设定获胜的组合方式(横、竖、斜)

WINNING_TRIADS = ((0, 1, 2), (3, 4, 5), (6, 7, 8),

(0, 3, 6), (1, 4, 7),(2, 5, 8),

(0, 4, 8), (2, 4, 6))

# 设定棋盘按一行三个打印

PRINTING_TRIADS = ((0, 1, 2), (3, 4, 5), (6, 7, 8))

# 用一维列表表示棋盘:

SLOTS = (0, 1, 2, 3, 4, 5, 6, 7, 8)

# -1表示X玩家 0表示空位 1表示O玩家.

X_token = -1

Open_token = 0

O_token = 1

MARKERS = ['_', 'O', 'X']

END_PHRASE = ('平局', '胜利', '失败')

def alpha_beta_valuation(board, player, next_player, alpha, beta):

"""运用AlphaBeta剪枝来计算当前局面的分值

因为搜索层数少,总能搜索到最终局面,估值结果为[-1,0,1]

"""

wnnr = winner(board)

if wnnr != Open_token:

# 有玩家获胜

return wnnr

elif not legal_move_left(board):

# 没有空位,平局

return 0

# 检查当前玩家"player"的所有可落子点

for move in SLOTS:

if board[move] == Open_token:

board[move] = player

# 落子之后交换玩家,继续检验

val = alpha_beta_valuation(board, next_player, player, alpha, beta)

board[move] = Open_token

if player == O_token:  # 当前玩家是O,是Max玩家(记号是1)

if val > alpha:

alpha = val

if alpha >= beta:

return beta  # 直接返回当前的最大可能取值beta, 进行剪枝

else:  # 当前玩家是X,是Min玩家(记号是-1)

if val < beta:

beta = val

if beta <= alpha:

return alpha  # 直接返回当前的最小可能取值alpha, 进行剪枝

if player == O_token:

retval = alpha

else:

retval = beta

return retval

def print_board(board):

"""打印当前棋盘"""

for row in PRINTING_TRIADS:

r = ' '

for hole in row:

r += MARKERS[board[hole]] + ' '

print(r)

def legal_move_left(board):

""" 判断棋盘上是否还有空位 """

for slot in SLOTS:

if board[slot] == Open_token:

return True

return False

def winner(board):

""" 判断局面的胜者,返回值-1表示X获胜,1表示O获胜,0表示平局或者未结束"""

for triad in WINNING_TRIADS:

triad_sum = board[triad[0]] + board[triad[1]] + board[triad[2]]

if triad_sum == 3 or triad_sum == -3:

return board[triad[0]]  # 表示棋子的数值恰好也是-1:X,1:O

return 0

def determine_move(board):

"""决定电脑(玩家O)的下一步棋,若估值相同则随机选取步数"""

best_val = -2  # 本程序估值结果只在[-1,0,1]中

my_moves = []

print("开始思考")

for move in SLOTS:

if board[move] == Open_token:

board[move] = O_token

val = alpha_beta_valuation(board, X_token, O_token, -2, 2)

board[move] = Open_token

print("Computer如果下在", move, ",将导致", END_PHRASE[val])

if val > best_val:

best_val = val

my_moves = [move]

if val == best_val:

my_moves.append(move)

return random.choice(my_moves)

HUMAN = 1

COMPUTER = 0

def main():

"""主函数,先决定谁是X(先手方),再开始下棋"""

next_move = HUMAN

opt = input("请选择先手方,输入X表示玩家先手,输入O表示电脑先手:")

if opt == "X":

next_move = HUMAN

elif opt == "O":

next_move = COMPUTER

else:

print("输入有误,默认玩家先手")

# 初始化空棋盘

board = [Open_token for i in range(9)]

# 开始下棋

while legal_move_left(board) and winner(board) == Open_token:

print()

print_board(board)

if next_move == HUMAN and legal_move_left(board):

try:

humanmv = int(input("请输入你要落子的位置(0-8):"))

if board[humanmv] != Open_token:

continue

board[humanmv] = X_token

next_move = COMPUTER

except:

print("输入有误,请重试")

continue

if next_move == COMPUTER and legal_move_left(board):

mymv = determine_move(board)

print("Computer最终决定下在", mymv)

board[mymv] = O_token

next_move = HUMAN

# 输出结果

print_board(board)

print(["平局", "Computer赢了", "你赢了"][winner(board)])

if __name__ == '__main__':

main()

运行结果


版权声明:本文为weixin_32868705原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。