1
1
import copy
2
2
import re
3
- from typing import Any , Dict , Optional
3
+ from typing import Dict , Optional
4
4
5
5
import chess
6
- import chess .uci
6
+ import chess .engine
7
7
8
8
from zulip_bots .lib import BotHandler
9
9
@@ -28,8 +28,9 @@ def initialize(self, bot_handler: BotHandler) -> None:
28
28
self .config_info = bot_handler .get_config_info ("chess" )
29
29
30
30
try :
31
- self .engine = chess .uci .popen_engine (self .config_info ["stockfish_location" ])
32
- self .engine .uci ()
31
+ self .engine = chess .engine .SimpleEngine .popen_uci (
32
+ self .config_info ["stockfish_location" ]
33
+ )
33
34
except FileNotFoundError :
34
35
# It is helpful to allow for fake Stockfish locations if the bot
35
36
# runner is testing or knows they won't be using an engine.
@@ -203,7 +204,7 @@ def check_game_over(
203
204
# be over if it's *5*-fold or *75* moves, but if either player
204
205
# wants the game to be a draw, after 3 or 75 it a draw. For now,
205
206
# just assume that the players would want the draw.
206
- if new_board .is_game_over (True ):
207
+ if new_board .is_game_over (claim_draw = True ):
207
208
game_over_output = ""
208
209
209
210
if new_board .is_checkmate ():
@@ -289,6 +290,10 @@ def move_computer(
289
290
290
291
computer_move = calculate_computer_move (new_board , self .engine )
291
292
293
+ if not computer_move :
294
+ bot_handler .send_reply (message , make_engine_failed_response ())
295
+ return
296
+
292
297
new_board_after_computer_move = copy .copy (new_board )
293
298
new_board_after_computer_move .push (computer_move )
294
299
@@ -317,9 +322,16 @@ def move_computer_first(
317
322
"""
318
323
last_board = self .validate_board (message , bot_handler , last_fen )
319
324
325
+ if not last_board :
326
+ return
327
+
320
328
computer_move = calculate_computer_move (last_board , self .engine )
321
329
322
- new_board_after_computer_move = copy .copy (last_board ) # type: chess.Board
330
+ if not computer_move :
331
+ bot_handler .send_reply (message , make_engine_failed_response ())
332
+ return
333
+
334
+ new_board_after_computer_move = copy .copy (last_board )
323
335
new_board_after_computer_move .push (computer_move )
324
336
325
337
if self .check_game_over (message , bot_handler , new_board_after_computer_move ):
@@ -353,7 +365,9 @@ def resign(self, message: Dict[str, str], bot_handler: BotHandler, last_fen: str
353
365
handler_class = ChessHandler
354
366
355
367
356
- def calculate_computer_move (board : chess .Board , engine : Any ) -> chess .Move :
368
+ def calculate_computer_move (
369
+ board : chess .Board , engine : chess .engine .SimpleEngine
370
+ ) -> Optional [chess .Move ]:
357
371
"""Calculates the computer's move.
358
372
359
373
Parameters:
@@ -362,9 +376,8 @@ def calculate_computer_move(board: chess.Board, engine: Any) -> chess.Move:
362
376
363
377
Returns: The computer's move object.
364
378
"""
365
- engine .position (board )
366
- best_move_and_ponder_move = engine .go (movetime = (3000 ))
367
- return best_move_and_ponder_move [0 ]
379
+ result = engine .play (board , chess .engine .Limit (time = 3.0 ))
380
+ return result .move
368
381
369
382
370
383
def make_draw_response (reason : str ) -> str :
@@ -493,6 +506,14 @@ def make_move_reponse(last_board: chess.Board, new_board: chess.Board, move: che
493
506
)
494
507
495
508
509
+ def make_engine_failed_response () -> str :
510
+ """Makes a response string for engine failure.
511
+
512
+ Returns: The engine failure response string.
513
+ """
514
+ return "The computer failed to make a move."
515
+
516
+
496
517
def make_footer () -> str :
497
518
"""Makes a footer to be appended to the bottom of other, actionable
498
519
responses.
0 commit comments