Python 国际象棋引擎。 Alphabeta 函数超出深度调用错误
Python chess engine. Alphabeta function exceeding depth call error
我最近一直在做一个项目,目标是制作一个国际象棋引擎,它可以评估某个位置并下出最佳棋步。我使用 this post 作为这个项目的基础,但后来意识到这不是我想要的。
源代码:github
我的代码:
def do_move(depth):
try:
move = chess.polyglot.MemoryMappedReader("C:/Users/Bruno/Desktop/pws/books/human.bin").weighted_choice(board).move
move = chess.polyglot.MemoryMappedReader("C:/Users/Bruno/Desktop/pws/books/computer.bin").weighted_choice(board).move
move = chess.polyglot.MemoryMappedReader("C:/Users/Bruno/Desktop/pws/books/pecg_book.bin").weighted_choice(board).move
return move
except:
bestMove = chess.Move.null()
bestValue = -99999
alpha = -100000
beta = 100000
for move in board.legal_moves:
board.push(move)
boardValue = -alphabeta(-beta, -alpha, (depth -1))
if boardValue > bestValue:
bestValue = boardValue
bestMove = move
if (boardValue > alpha):
alpha = boardValue
board.pop()
return bestMove
def alphabeta(depthleft, alpha, beta):
bestscore = -9999
if (depthleft == 0):
return quiesce(alpha, beta)
for move in board.legal_moves:
board.push(move)
score = -alphabeta(-beta, -alpha, depthleft - 1)
board.pop()
if (score >= beta):
return score
if (score > bestscore):
bestscore = score
if (score > alpha):
alpha = score
return bestscore
def quiesce(alpha, beta):
stand_pat = evaluation()
if (stand_pat >= beta):
return beta
if (alpha < stand_pat):
alpha = stand_pat
for move in board.legal_moves:
if board.is_capture(move):
board.push(move)
score = -quiesce(-beta, -alpha)
board.pop()
if (score >= beta):
return beta
if (score > alpha):
alpha = score
return alpha
目前,由于过度调用 do_move() 函数,代码在崩溃前可以执行大约 20 步左右的移动。
我该如何解决这个问题并让它玩完整个游戏?
示例代码基于您的 github link 并进行了修改。用户可以输入位置并让引擎搜索bestmove。注意时间以毫秒为单位。请参阅示例输出。它使用 python chess library.
代码
import time
import chess
import chess.pgn
INF = 100000
MATE_SCORE = INF-100
MAX_DEPTH = 16
MAX_TIME_MS = 120000 # 120s or 2m
# Evaluating the board
pawntable = [
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, -20, -20, 10, 10, 5,
5, -5, -10, 0, 0, -10, -5, 5,
0, 0, 0, 20, 20, 0, 0, 0,
5, 5, 10, 25, 25, 10, 5, 5,
10, 10, 20, 30, 30, 20, 10, 10,
50, 50, 50, 50, 50, 50, 50, 50,
0, 0, 0, 0, 0, 0, 0, 0]
knightstable = [
-50, -40, -30, -30, -30, -30, -40, -50,
-40, -20, 0, 5, 5, 0, -20, -40,
-30, 5, 10, 15, 15, 10, 5, -30,
-30, 0, 15, 20, 20, 15, 0, -30,
-30, 5, 15, 20, 20, 15, 5, -30,
-30, 0, 10, 15, 15, 10, 0, -30,
-40, -20, 0, 0, 0, 0, -20, -40,
-50, -40, -30, -30, -30, -30, -40, -50]
bishopstable = [
-20, -10, -10, -10, -10, -10, -10, -20,
-10, 5, 0, 0, 0, 0, 5, -10,
-10, 10, 10, 10, 10, 10, 10, -10,
-10, 0, 10, 10, 10, 10, 0, -10,
-10, 5, 5, 10, 10, 5, 5, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 0, 0, 0, 0, 0, 0, -10,
-20, -10, -10, -10, -10, -10, -10, -20]
rookstable = [
0, 0, 0, 5, 5, 0, 0, 0,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
5, 10, 10, 10, 10, 10, 10, 5,
0, 0, 0, 0, 0, 0, 0, 0]
queenstable = [
-20, -10, -10, -5, -5, -10, -10, -20,
-10, 0, 0, 0, 0, 0, 0, -10,
-10, 5, 5, 5, 5, 5, 0, -10,
0, 0, 5, 5, 5, 5, 0, -5,
-5, 0, 5, 5, 5, 5, 0, -5,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 0, 0, 0, 0, 0, -10,
-20, -10, -10, -5, -5, -10, -10, -20]
kingstable = [
20, 30, 10, 0, 0, 10, 30, 20,
20, 20, 0, 0, 0, 0, 20, 20,
-10, -20, -20, -20, -20, -20, -20, -10,
-20, -30, -30, -40, -40, -30, -30, -20,
-30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30]
def is_time_limit_reached():
global start_time
global timems
return 1000 * (time.perf_counter() - start_time) >= timems
def evaluate_board(board):
wp = len(board.pieces(chess.PAWN, chess.WHITE))
bp = len(board.pieces(chess.PAWN, chess.BLACK))
wn = len(board.pieces(chess.KNIGHT, chess.WHITE))
bn = len(board.pieces(chess.KNIGHT, chess.BLACK))
wb = len(board.pieces(chess.BISHOP, chess.WHITE))
bb = len(board.pieces(chess.BISHOP, chess.BLACK))
wr = len(board.pieces(chess.ROOK, chess.WHITE))
br = len(board.pieces(chess.ROOK, chess.BLACK))
wq = len(board.pieces(chess.QUEEN, chess.WHITE))
bq = len(board.pieces(chess.QUEEN, chess.BLACK))
material = 100 * (wp - bp) + 320 * (wn - bn) + 330 * (wb - bb) + 500 * (wr - br) + 900 * (wq - bq)
pawnsq = sum([pawntable[i] for i in board.pieces(chess.PAWN, chess.WHITE)])
pawnsq = pawnsq + sum([-pawntable[chess.square_mirror(i)]
for i in board.pieces(chess.PAWN, chess.BLACK)])
knightsq = sum([knightstable[i] for i in board.pieces(chess.KNIGHT, chess.WHITE)])
knightsq = knightsq + sum([-knightstable[chess.square_mirror(i)]
for i in board.pieces(chess.KNIGHT, chess.BLACK)])
bishopsq = sum([bishopstable[i] for i in board.pieces(chess.BISHOP, chess.WHITE)])
bishopsq = bishopsq + sum([-bishopstable[chess.square_mirror(i)]
for i in board.pieces(chess.BISHOP, chess.BLACK)])
rooksq = sum([rookstable[i] for i in board.pieces(chess.ROOK, chess.WHITE)])
rooksq = rooksq + sum([-rookstable[chess.square_mirror(i)]
for i in board.pieces(chess.ROOK, chess.BLACK)])
queensq = sum([queenstable[i] for i in board.pieces(chess.QUEEN, chess.WHITE)])
queensq = queensq + sum([-queenstable[chess.square_mirror(i)]
for i in board.pieces(chess.QUEEN, chess.BLACK)])
kingsq = sum([kingstable[i] for i in board.pieces(chess.KING, chess.WHITE)])
kingsq = kingsq + sum([-kingstable[chess.square_mirror(i)]
for i in board.pieces(chess.KING, chess.BLACK)])
eval = material + pawnsq + knightsq + bishopsq + rooksq + queensq + kingsq
if board.turn:
return eval
return -eval
def value_to_mate(value):
if (value < -MATE_SCORE):
return -(INF + value) // 2
elif (value > MATE_SCORE):
return (INF - value + 1) // 2
return 0
# Searching the best move using minimax and alphabeta algorithm with negamax implementation
def alphabeta(board, alpha, beta, depth):
global timems
global start_time
global ply
bestscore = -INF
if is_time_limit_reached():
return 0
if board.can_claim_draw() or board.is_insufficient_material():
return 0
incheck = board.is_check()
if incheck:
depth += 1
if (depth < 1):
return quiesce(board, alpha, beta)
legal = 0
for move in board.legal_moves:
board.push(move)
ply += 1
legal += 1
score = -alphabeta(board, -beta, -alpha, depth - 1)
board.pop()
ply -= 1
if (score >= beta):
return score
if (score > bestscore):
bestscore = score
if (score > alpha):
alpha = score
if legal == 0:
if incheck:
return -INF + ply
else:
return 0
return bestscore
def quiesce(board, alpha, beta):
if is_time_limit_reached():
return 0
if board.is_insufficient_material():
return 0
stand_pat = evaluate_board(board)
if (stand_pat >= beta):
return beta
if (alpha < stand_pat):
alpha = stand_pat
for move in board.legal_moves:
if board.is_capture(move):
board.push(move)
score = -quiesce(board, -beta, -alpha)
board.pop()
if (score >= beta):
return beta
if (score > alpha):
alpha = score
return alpha
def selectmove(board, depth):
global ply
bestMove = chess.Move.null()
bestValue = -INF
alpha = -INF
beta = INF
for move in board.legal_moves:
board.push(move)
ply += 1
boardValue = -alphabeta(board, -beta, -alpha, depth - 1)
if boardValue > bestValue:
bestValue = boardValue
bestMove = move
if (boardValue > alpha):
alpha = boardValue
board.pop()
ply -= 1
if is_time_limit_reached():
break
return bestMove, bestValue
if __name__ == '__main__':
global timems
global start_time
global ply
fen = chess.STARTING_FEN
# fen = "1k6/7Q/1K6/8/8/8/8/8 w - - 0 1" # mate in 1
# fen = "kbK5/pp6/1P6/8/8/8/8/R7 w - - 0 1" # mate in 2
# fen = "rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6" # sicilian
depth = MAX_DEPTH
timems = MAX_TIME_MS
board = chess.Board(fen)
while True:
userinput = input('> ')
line = userinput.rstrip()
if line == 'go':
bestmove, bestscore = None, None
start_time = time.perf_counter()
ply = 0
if not board.is_game_over():
for d in range(1, depth+1):
move, score = selectmove(board, d)
elapse = 1000 * (time.perf_counter() - start_time)
if elapse >= timems:
break # Don't overwrite our bestmove from the time-interrupted search.
bestmove = move
bestscore = score
if abs(bestscore) > MATE_SCORE:
mate = value_to_mate(bestscore)
print(f'info depth {d} score mate {mate} time {int(elapse)} pv {bestmove}') # time is in millisec
else:
print(f'info depth {d} score {bestscore} time {int(elapse)} pv {bestmove}') # time is in millisec
board.push(bestmove) # update board with the bestmove
print(f'info time {int(1000*(time.perf_counter() - start_time))}')
print(f'bestmove {bestmove}')
else:
print('Game is over!')
elif line == 'new':
board = chess.Board()
depth = MAX_DEPTH
timems = MAX_TIME_MS
print(board)
print(f'max depth: {depth}, max time ms: {timems}')
elif 'position fen ' in line:
fen = ' '.join(line.split()[2:7])
board = chess.Board(fen)
elif line == 'board':
print(board)
elif line == 'fen':
print(board.fen())
elif line == 'epd':
print(board.epd())
elif 'time' in line:
timems = int(line.split()[1])
elif 'depth' in line:
depth = int(line.split()[1])
elif line == 'game':
game = chess.pgn.Game()
print(game.from_board(board))
elif line == 'quit':
break
else:
# assume user has entered a move
try:
board.push(chess.Move.from_uci(line))
except ValueError:
print(f'illegal move {line}')
输出
正在玩游戏
> new
r n b q k b n r
p p p p p p p p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
P P P P P P P P
R N B Q K B N R
max depth: 16, max time ms: 120000
> time 5000
> e2e4
> go
info depth 1 score 10 time 18 pv g8f6
info depth 2 score -40 time 140 pv g8f6
info depth 3 score 10 time 973 pv g8f6
info time 5001
bestmove g8f6
> board
r n b q k b . r
p p p p p p p p
. . . . . n . .
. . . . . . . .
. . . . P . . .
. . . . . . . .
P P P P . P P P
R N B Q K B N R
> b1c3
> go
info depth 1 score 10 time 19 pv b8c6
info depth 2 score -20 time 421 pv d7d5
info depth 3 score 10 time 2865 pv d7d5
info time 5000
bestmove d7d5
> board
r n b q k b . r
p p p . p p p p
. . . . . n . .
. . . p . . . .
. . . . P . . .
. . N . . . . .
P P P P . P P P
R . B Q K B N R
> game
[Event "?"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "?"]
[Black "?"]
[Result "*"]
1. e4 Nf6 2. Nc3 d5 *
> quit
设置位置
> position fen kbK5/pp6/1P6/8/8/8/8/R7 w - - 0 1
> board
k b K . . . . .
p p . . . . . .
. P . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
R . . . . . . .
> time 5000
> go
info depth 1 score 10 time 10 pv a1a5
info depth 2 score 10 time 92 pv a1a5
info depth 3 score mate 2 time 362 pv a1a6
info depth 4 score mate 2 time 2151 pv a1a6
info time 5001
bestmove a1a6
> board
k b K . . . . .
p p . . . . . .
R P . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
> go
info depth 1 score 480 time 5 pv b7a6
info depth 2 score mate -1 time 32 pv b8c7
info depth 3 score mate -1 time 184 pv b8c7
info depth 4 score mate -1 time 1314 pv b8c7
info time 5000
bestmove b8c7
> go
info depth 1 score mate 1 time 4 pv a6a7
info depth 2 score mate 1 time 37 pv a6a7
info depth 3 score mate 1 time 143 pv a6a7
info depth 4 score mate 1 time 878 pv a6a7
info depth 5 score mate 1 time 4305 pv a6a7
info time 5001
bestmove a6a7
> go
Game is over!
>
我最近一直在做一个项目,目标是制作一个国际象棋引擎,它可以评估某个位置并下出最佳棋步。我使用 this post 作为这个项目的基础,但后来意识到这不是我想要的。 源代码:github
我的代码:
def do_move(depth):
try:
move = chess.polyglot.MemoryMappedReader("C:/Users/Bruno/Desktop/pws/books/human.bin").weighted_choice(board).move
move = chess.polyglot.MemoryMappedReader("C:/Users/Bruno/Desktop/pws/books/computer.bin").weighted_choice(board).move
move = chess.polyglot.MemoryMappedReader("C:/Users/Bruno/Desktop/pws/books/pecg_book.bin").weighted_choice(board).move
return move
except:
bestMove = chess.Move.null()
bestValue = -99999
alpha = -100000
beta = 100000
for move in board.legal_moves:
board.push(move)
boardValue = -alphabeta(-beta, -alpha, (depth -1))
if boardValue > bestValue:
bestValue = boardValue
bestMove = move
if (boardValue > alpha):
alpha = boardValue
board.pop()
return bestMove
def alphabeta(depthleft, alpha, beta):
bestscore = -9999
if (depthleft == 0):
return quiesce(alpha, beta)
for move in board.legal_moves:
board.push(move)
score = -alphabeta(-beta, -alpha, depthleft - 1)
board.pop()
if (score >= beta):
return score
if (score > bestscore):
bestscore = score
if (score > alpha):
alpha = score
return bestscore
def quiesce(alpha, beta):
stand_pat = evaluation()
if (stand_pat >= beta):
return beta
if (alpha < stand_pat):
alpha = stand_pat
for move in board.legal_moves:
if board.is_capture(move):
board.push(move)
score = -quiesce(-beta, -alpha)
board.pop()
if (score >= beta):
return beta
if (score > alpha):
alpha = score
return alpha
目前,由于过度调用 do_move() 函数,代码在崩溃前可以执行大约 20 步左右的移动。
我该如何解决这个问题并让它玩完整个游戏?
示例代码基于您的 github link 并进行了修改。用户可以输入位置并让引擎搜索bestmove。注意时间以毫秒为单位。请参阅示例输出。它使用 python chess library.
代码
import time
import chess
import chess.pgn
INF = 100000
MATE_SCORE = INF-100
MAX_DEPTH = 16
MAX_TIME_MS = 120000 # 120s or 2m
# Evaluating the board
pawntable = [
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, -20, -20, 10, 10, 5,
5, -5, -10, 0, 0, -10, -5, 5,
0, 0, 0, 20, 20, 0, 0, 0,
5, 5, 10, 25, 25, 10, 5, 5,
10, 10, 20, 30, 30, 20, 10, 10,
50, 50, 50, 50, 50, 50, 50, 50,
0, 0, 0, 0, 0, 0, 0, 0]
knightstable = [
-50, -40, -30, -30, -30, -30, -40, -50,
-40, -20, 0, 5, 5, 0, -20, -40,
-30, 5, 10, 15, 15, 10, 5, -30,
-30, 0, 15, 20, 20, 15, 0, -30,
-30, 5, 15, 20, 20, 15, 5, -30,
-30, 0, 10, 15, 15, 10, 0, -30,
-40, -20, 0, 0, 0, 0, -20, -40,
-50, -40, -30, -30, -30, -30, -40, -50]
bishopstable = [
-20, -10, -10, -10, -10, -10, -10, -20,
-10, 5, 0, 0, 0, 0, 5, -10,
-10, 10, 10, 10, 10, 10, 10, -10,
-10, 0, 10, 10, 10, 10, 0, -10,
-10, 5, 5, 10, 10, 5, 5, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 0, 0, 0, 0, 0, 0, -10,
-20, -10, -10, -10, -10, -10, -10, -20]
rookstable = [
0, 0, 0, 5, 5, 0, 0, 0,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
5, 10, 10, 10, 10, 10, 10, 5,
0, 0, 0, 0, 0, 0, 0, 0]
queenstable = [
-20, -10, -10, -5, -5, -10, -10, -20,
-10, 0, 0, 0, 0, 0, 0, -10,
-10, 5, 5, 5, 5, 5, 0, -10,
0, 0, 5, 5, 5, 5, 0, -5,
-5, 0, 5, 5, 5, 5, 0, -5,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 0, 0, 0, 0, 0, -10,
-20, -10, -10, -5, -5, -10, -10, -20]
kingstable = [
20, 30, 10, 0, 0, 10, 30, 20,
20, 20, 0, 0, 0, 0, 20, 20,
-10, -20, -20, -20, -20, -20, -20, -10,
-20, -30, -30, -40, -40, -30, -30, -20,
-30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30]
def is_time_limit_reached():
global start_time
global timems
return 1000 * (time.perf_counter() - start_time) >= timems
def evaluate_board(board):
wp = len(board.pieces(chess.PAWN, chess.WHITE))
bp = len(board.pieces(chess.PAWN, chess.BLACK))
wn = len(board.pieces(chess.KNIGHT, chess.WHITE))
bn = len(board.pieces(chess.KNIGHT, chess.BLACK))
wb = len(board.pieces(chess.BISHOP, chess.WHITE))
bb = len(board.pieces(chess.BISHOP, chess.BLACK))
wr = len(board.pieces(chess.ROOK, chess.WHITE))
br = len(board.pieces(chess.ROOK, chess.BLACK))
wq = len(board.pieces(chess.QUEEN, chess.WHITE))
bq = len(board.pieces(chess.QUEEN, chess.BLACK))
material = 100 * (wp - bp) + 320 * (wn - bn) + 330 * (wb - bb) + 500 * (wr - br) + 900 * (wq - bq)
pawnsq = sum([pawntable[i] for i in board.pieces(chess.PAWN, chess.WHITE)])
pawnsq = pawnsq + sum([-pawntable[chess.square_mirror(i)]
for i in board.pieces(chess.PAWN, chess.BLACK)])
knightsq = sum([knightstable[i] for i in board.pieces(chess.KNIGHT, chess.WHITE)])
knightsq = knightsq + sum([-knightstable[chess.square_mirror(i)]
for i in board.pieces(chess.KNIGHT, chess.BLACK)])
bishopsq = sum([bishopstable[i] for i in board.pieces(chess.BISHOP, chess.WHITE)])
bishopsq = bishopsq + sum([-bishopstable[chess.square_mirror(i)]
for i in board.pieces(chess.BISHOP, chess.BLACK)])
rooksq = sum([rookstable[i] for i in board.pieces(chess.ROOK, chess.WHITE)])
rooksq = rooksq + sum([-rookstable[chess.square_mirror(i)]
for i in board.pieces(chess.ROOK, chess.BLACK)])
queensq = sum([queenstable[i] for i in board.pieces(chess.QUEEN, chess.WHITE)])
queensq = queensq + sum([-queenstable[chess.square_mirror(i)]
for i in board.pieces(chess.QUEEN, chess.BLACK)])
kingsq = sum([kingstable[i] for i in board.pieces(chess.KING, chess.WHITE)])
kingsq = kingsq + sum([-kingstable[chess.square_mirror(i)]
for i in board.pieces(chess.KING, chess.BLACK)])
eval = material + pawnsq + knightsq + bishopsq + rooksq + queensq + kingsq
if board.turn:
return eval
return -eval
def value_to_mate(value):
if (value < -MATE_SCORE):
return -(INF + value) // 2
elif (value > MATE_SCORE):
return (INF - value + 1) // 2
return 0
# Searching the best move using minimax and alphabeta algorithm with negamax implementation
def alphabeta(board, alpha, beta, depth):
global timems
global start_time
global ply
bestscore = -INF
if is_time_limit_reached():
return 0
if board.can_claim_draw() or board.is_insufficient_material():
return 0
incheck = board.is_check()
if incheck:
depth += 1
if (depth < 1):
return quiesce(board, alpha, beta)
legal = 0
for move in board.legal_moves:
board.push(move)
ply += 1
legal += 1
score = -alphabeta(board, -beta, -alpha, depth - 1)
board.pop()
ply -= 1
if (score >= beta):
return score
if (score > bestscore):
bestscore = score
if (score > alpha):
alpha = score
if legal == 0:
if incheck:
return -INF + ply
else:
return 0
return bestscore
def quiesce(board, alpha, beta):
if is_time_limit_reached():
return 0
if board.is_insufficient_material():
return 0
stand_pat = evaluate_board(board)
if (stand_pat >= beta):
return beta
if (alpha < stand_pat):
alpha = stand_pat
for move in board.legal_moves:
if board.is_capture(move):
board.push(move)
score = -quiesce(board, -beta, -alpha)
board.pop()
if (score >= beta):
return beta
if (score > alpha):
alpha = score
return alpha
def selectmove(board, depth):
global ply
bestMove = chess.Move.null()
bestValue = -INF
alpha = -INF
beta = INF
for move in board.legal_moves:
board.push(move)
ply += 1
boardValue = -alphabeta(board, -beta, -alpha, depth - 1)
if boardValue > bestValue:
bestValue = boardValue
bestMove = move
if (boardValue > alpha):
alpha = boardValue
board.pop()
ply -= 1
if is_time_limit_reached():
break
return bestMove, bestValue
if __name__ == '__main__':
global timems
global start_time
global ply
fen = chess.STARTING_FEN
# fen = "1k6/7Q/1K6/8/8/8/8/8 w - - 0 1" # mate in 1
# fen = "kbK5/pp6/1P6/8/8/8/8/R7 w - - 0 1" # mate in 2
# fen = "rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6" # sicilian
depth = MAX_DEPTH
timems = MAX_TIME_MS
board = chess.Board(fen)
while True:
userinput = input('> ')
line = userinput.rstrip()
if line == 'go':
bestmove, bestscore = None, None
start_time = time.perf_counter()
ply = 0
if not board.is_game_over():
for d in range(1, depth+1):
move, score = selectmove(board, d)
elapse = 1000 * (time.perf_counter() - start_time)
if elapse >= timems:
break # Don't overwrite our bestmove from the time-interrupted search.
bestmove = move
bestscore = score
if abs(bestscore) > MATE_SCORE:
mate = value_to_mate(bestscore)
print(f'info depth {d} score mate {mate} time {int(elapse)} pv {bestmove}') # time is in millisec
else:
print(f'info depth {d} score {bestscore} time {int(elapse)} pv {bestmove}') # time is in millisec
board.push(bestmove) # update board with the bestmove
print(f'info time {int(1000*(time.perf_counter() - start_time))}')
print(f'bestmove {bestmove}')
else:
print('Game is over!')
elif line == 'new':
board = chess.Board()
depth = MAX_DEPTH
timems = MAX_TIME_MS
print(board)
print(f'max depth: {depth}, max time ms: {timems}')
elif 'position fen ' in line:
fen = ' '.join(line.split()[2:7])
board = chess.Board(fen)
elif line == 'board':
print(board)
elif line == 'fen':
print(board.fen())
elif line == 'epd':
print(board.epd())
elif 'time' in line:
timems = int(line.split()[1])
elif 'depth' in line:
depth = int(line.split()[1])
elif line == 'game':
game = chess.pgn.Game()
print(game.from_board(board))
elif line == 'quit':
break
else:
# assume user has entered a move
try:
board.push(chess.Move.from_uci(line))
except ValueError:
print(f'illegal move {line}')
输出
正在玩游戏
> new
r n b q k b n r
p p p p p p p p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
P P P P P P P P
R N B Q K B N R
max depth: 16, max time ms: 120000
> time 5000
> e2e4
> go
info depth 1 score 10 time 18 pv g8f6
info depth 2 score -40 time 140 pv g8f6
info depth 3 score 10 time 973 pv g8f6
info time 5001
bestmove g8f6
> board
r n b q k b . r
p p p p p p p p
. . . . . n . .
. . . . . . . .
. . . . P . . .
. . . . . . . .
P P P P . P P P
R N B Q K B N R
> b1c3
> go
info depth 1 score 10 time 19 pv b8c6
info depth 2 score -20 time 421 pv d7d5
info depth 3 score 10 time 2865 pv d7d5
info time 5000
bestmove d7d5
> board
r n b q k b . r
p p p . p p p p
. . . . . n . .
. . . p . . . .
. . . . P . . .
. . N . . . . .
P P P P . P P P
R . B Q K B N R
> game
[Event "?"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "?"]
[Black "?"]
[Result "*"]
1. e4 Nf6 2. Nc3 d5 *
> quit
设置位置
> position fen kbK5/pp6/1P6/8/8/8/8/R7 w - - 0 1
> board
k b K . . . . .
p p . . . . . .
. P . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
R . . . . . . .
> time 5000
> go
info depth 1 score 10 time 10 pv a1a5
info depth 2 score 10 time 92 pv a1a5
info depth 3 score mate 2 time 362 pv a1a6
info depth 4 score mate 2 time 2151 pv a1a6
info time 5001
bestmove a1a6
> board
k b K . . . . .
p p . . . . . .
R P . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
> go
info depth 1 score 480 time 5 pv b7a6
info depth 2 score mate -1 time 32 pv b8c7
info depth 3 score mate -1 time 184 pv b8c7
info depth 4 score mate -1 time 1314 pv b8c7
info time 5000
bestmove b8c7
> go
info depth 1 score mate 1 time 4 pv a6a7
info depth 2 score mate 1 time 37 pv a6a7
info depth 3 score mate 1 time 143 pv a6a7
info depth 4 score mate 1 time 878 pv a6a7
info depth 5 score mate 1 time 4305 pv a6a7
info time 5001
bestmove a6a7
> go
Game is over!
>