好的,下面是用alphabeta剪枝实现五子棋的Python代码:
```python
import numpy as np
# 定义棋盘大小
BOARD_SIZE = 15
# 定义棋子类型
EMPTY = 0
BLACK = 1
WHITE = 2
# 定义评估函数中的棋型
FIVE = 100000 # 连五
FOUR = 10000 # 活四
THREE = 1000 # 活三
TWO = 100 # 活二
# 定义走法评分表
score_table = {
FIVE: 100000,
FOUR + THREE: 10000,
THREE + THREE: 5000,
FOUR + TWO: 5000,
THREE + TWO: 1000,
TWO + TWO: 500,
FOUR: 500,
THREE: 100,
TWO: 50,
}
# 初始化棋盘
board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
# 判断是否在棋盘内
def is_in_board(x, y):
return 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE
# 判断某一位置是否可以下棋
def is_valid_move(x, y):
return is_in_board(x, y) and board[x][y] == EMPTY
# 判断是否五子连珠
def is_five_in_a_row(x, y, player):
# 水平方向
count = 1
for i in range(1, 5):
if is_in_board(x+i, y) and board[x+i][y] == player:
count += 1
else:
break
for i in range(1, 5):
if is_in_board(x-i, y) and board[x-i][y] == player:
count += 1
else:
break
if count >= 5:
return True
# 垂直方向
count = 1
for i in range(1, 5):
if is_in_board(x, y+i) and board[x][y+i] == player:
count += 1
else:
break
for i in range(1, 5):
if is_in_board(x, y-i) and board[x][y-i] == player:
count += 1
else:
break
if count >= 5:
return True
# 左上-右下方向
count = 1
for i in range(1, 5):
if is_in_board(x+i, y+i) and board[x+i][y+i] == player:
count += 1
else:
break
for i in range(1, 5):
if is_in_board(x-i, y-i) and board[x-i][y-i] == player:
count += 1
else:
break
if count >= 5:
return True
# 右上-左下方向
count = 1
for i in range(1, 5):
if is_in_board(x+i, y-i) and board[x+i][y-i] == player:
count += 1
else:
break
for i in range(1, 5):
if is_in_board(x-i, y+i) and board[x-i][y+i] == player:
count += 1
else:
break
if count >= 5:
return True
return False
# 获得当前棋盘中的所有空位
def get_empty_positions():
positions = []
for i in range(BOARD_SIZE):
for j in range(BOARD_SIZE):
if board[i][j] == EMPTY:
positions.append((i, j))
return positions
# 评估当前棋盘状态
def evaluate_board(player):
opp = BLACK if player == WHITE else WHITE
score = 0
for i in range(BOARD_SIZE):
for j in range(BOARD_SIZE):
if board[i][j] == player:
# 水平方向
count = 1
for k in range(1, 5):
if is_in_board(i+k, j) and board[i+k][j] == player:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i-k, j) and board[i-k][j] == player:
count += 1
else:
break
score += score_table.get(count*1000, 0)
# 垂直方向
count = 1
for k in range(1, 5):
if is_in_board(i, j+k) and board[i][j+k] == player:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i, j-k) and board[i][j-k] == player:
count += 1
else:
break
score += score_table.get(count*1000, 0)
# 左上-右下方向
count = 1
for k in range(1, 5):
if is_in_board(i+k, j+k) and board[i+k][j+k] == player:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i-k, j-k) and board[i-k][j-k] == player:
count += 1
else:
break
score += score_table.get(count*1000, 0)
# 右上-左下方向
count = 1
for k in range(1, 5):
if is_in_board(i+k, j-k) and board[i+k][j-k] == player:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i-k, j+k) and board[i-k][j+k] == player:
count += 1
else:
break
score += score_table.get(count*1000, 0)
elif board[i][j] == opp:
# 水平方向
count = 1
for k in range(1, 5):
if is_in_board(i+k, j) and board[i+k][j] == opp:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i-k, j) and board[i-k][j] == opp:
count += 1
else:
break
score -= score_table.get(count*1000, 0)
# 垂直方向
count = 1
for k in range(1, 5):
if is_in_board(i, j+k) and board[i][j+k] == opp:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i, j-k) and board[i][j-k] == opp:
count += 1
else:
break
score -= score_table.get(count*1000, 0)
# 左上-右下方向
count = 1
for k in range(1, 5):
if is_in_board(i+k, j+k) and board[i+k][j+k] == opp:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i-k, j-k) and board[i-k][j-k] == opp:
count += 1
else:
break
score -= score_table.get(count*1000, 0)
# 右上-左下方向
count = 1
for k in range(1, 5):
if is_in_board(i+k, j-k) and board[i+k][j-k] == opp:
count += 1
else:
break
for k in range(1, 5):
if is_in_board(i-k, j+k) and board[i-k][j+k] == opp:
count += 1
else:
break
score -= score_table.get(count*1000, 0)
return score
# 极大极小搜索 + alphabeta剪枝
def alphabeta_search(player, depth, alpha, beta):
if depth == 0:
return None, evaluate_board(player)
positions = get_empty_positions()
if len(positions) == 0:
return None, 0
best_pos = None
if player == BLACK:
best_score = -np.inf
for pos in positions:
x, y = pos
board[x][y] = BLACK
if is_five_in_a_row(x, y, BLACK):
board[x][y] = EMPTY
return pos, FIVE
_, score = alphabeta_search(WHITE, depth-1, alpha, beta)
board[x][y] = EMPTY
if score > best_score:
best_score = score
best_pos = pos
alpha = max(alpha, best_score)
if alpha >= beta:
break
else:
best_score = np.inf
for pos in positions:
x, y = pos
board[x][y] = WHITE
if is_five_in_a_row(x, y, WHITE):
board[x][y] = EMPTY
return pos, -FIVE
_, score = alphabeta_search(BLACK, depth-1, alpha, beta)
board[x][y] = EMPTY
if score < best_score:
best_score = score
best_pos = pos
beta = min(beta, best_score)
if alpha >= beta:
break
return best_pos, best_score
# 人机对战
def play_with_computer():
print("-----五子棋人机对战-----")
print("玩家执黑棋,电脑执白棋")
print("请输入您的下棋坐标,格式为x,y,如2,3")
# 随机先后手
if np.random.randint(2) == 0:
player = BLACK
print("您先手")
else:
player = WHITE
print("电脑先手")
while True:
if player == BLACK:
# 人下棋
while True:
move = input("请您输入下棋坐标:")
x, y = [int(i) for i in move.split(",")]
if is_valid_move(x, y):
board[x][y] = BLACK
break
else:
print("该位置已有棋子,请重新输入")
else:
# 电脑下棋
print("电脑正在思考...")
pos, _ = alphabeta_search(WHITE, 3, -np.inf, np.inf)
x, y = pos
board[x][y] = WHITE
print("电脑下棋坐标:{},{}".format(x, y))
# 打印棋盘
for i in range(BOARD_SIZE):
print(" ".join(str(x) for x in board[i]))
print("-" * 20)
# 判断游戏是否结束
if is_five_in_a_row(x, y, player):
if player == BLACK:
print("恭喜您获胜!")
else:
print("很遗憾,您输了!")
break
if len(get_empty_positions()) == 0:
print("平局!")
break
# 交换先后手
player = BLACK if player == WHITE else WHITE
play_with_computer()
```
在以上代码中,我们定义了五子棋的棋盘大小、棋子类型、评估函数中的棋型、走法评分表等变量。首先,我们定义了一些基本的函数,如判断某一位置是否可以下棋、判断是否五子连珠、获得当前棋盘中的所有空位等。接着,我们定义了评估函数,该函数通过检查棋盘中各种棋型的数量来评估当前棋盘状态,并返回一个分数。我们还实现了极大极小搜索算法和alphabeta剪枝算法,用于搜索最优解。最后,我们实现了一个人机对战的函数,通过不断交替让玩家和电脑下棋来进行游戏。