Skip to content

Commit

Permalink
Merge pull request #18 from thearst3rd/better-uci
Browse files Browse the repository at this point in the history
Improve UCI position command support
  • Loading branch information
healeycodes authored Aug 4, 2021
2 parents f1eb78f + 0de5834 commit 8c1793c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 22 deletions.
42 changes: 30 additions & 12 deletions communication.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ def talk():

while True:
msg = input()
print(f">>> {msg}", file=sys.stderr)
command(depth, board, msg)


Expand All @@ -23,6 +22,11 @@ def command(depth: int, board: chess.Board, msg: str):
Accept UCI commands and respond.
The board state is also updated.
"""
msg = msg.strip()
tokens = msg.split(" ")
while "" in tokens:
tokens.remove("")

if msg == "quit":
sys.exit()

Expand All @@ -39,18 +43,32 @@ def command(depth: int, board: chess.Board, msg: str):
if msg == "ucinewgame":
return

if "position startpos moves" in msg:
moves = msg.split(" ")[3:]
board.clear()
board.set_fen(chess.STARTING_FEN)
for move in moves:
board.push(chess.Move.from_uci(move))
return
if msg.startswith("position"):
if len(tokens) < 2:
return

if "position fen" in msg:
fen = " ".join(msg.split(" ")[2:])
board.set_fen(fen)
return
# Set starting position
if tokens[1] == "startpos":
board.reset()
moves_start = 2
elif tokens[1] == "fen":
fen = " ".join(tokens[2:8])
board.set_fen(fen)
moves_start = 8
else:
return

# Apply moves
if len(tokens) <= moves_start or tokens[moves_start] != "moves":
return

for move in tokens[(moves_start+1):]:
board.push_uci(move)

if msg == "d":
# Non-standard command, but supported by Stockfish and helps debugging
print(board)
print(board.fen())

if msg[0:2] == "go":
_move = next_move(depth, board)
Expand Down
2 changes: 1 addition & 1 deletion movegeneration.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def next_move(depth: int, board: chess.Board, debug=True) -> chess.Move:

debug_info["time"] = time.time() - t0
if debug == True:
print(f">>> {debug_info}", file=sys.stderr)
print(f"info {debug_info}")
return move


Expand Down
56 changes: 47 additions & 9 deletions test/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,54 @@ def test_uci_command(self):
self.assertEqual(len(lines), 3)
self.assertEqual(lines[2], "uciok")

def test_startpos_command(self):
def test_position_startpos_command(self):
"""
Test position command setup a board one that has received one half-move
Test position command setup a board using identifier 'startpos'
"""
board = chess.Board()

# Startpos and moves
command(3, board, "position startpos moves e2e4")
self.assertEqual(
board.fen(), "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
)

# Just startpos
command(3, board, "position startpos")
self.assertEqual(
board.fen(), "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
)

# Arbitrary whitespace
command(3, board, " position startpos moves e2e4 d7d5 e4d5 ")
self.assertEqual(
board.fen(), "rnbqkbnr/ppp1pppp/8/3P4/8/8/PPPP1PPP/RNBQKBNR b KQkq - 0 2"
)

# Token 'moves' but no moves
command(3, board, "position startpos moves")
self.assertEqual(
board.fen(), "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
)

def test_position_fen_command(self):
"""
Test position command setup a board using fen string
"""
board = chess.Board()

# Just fen
command(3, board, "position fen rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2")
self.assertEqual(
board.fen(), "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2"
)

# Fen and moves
command(3, board, "position fen rnbqkbnr/pp2pppp/3p4/2p5/3PP3/5N2/PPP2PPP/RNBQKB1R b KQkq - 0 3 moves c5d4 f3d4 g7g6")
self.assertEqual(
board.fen(), "rnbqkbnr/pp2pp1p/3p2p1/8/3NP3/8/PPP2PPP/RNBQKB1R w KQkq - 0 5"
)

def test_go_command_black(self):
"""
Test go command with Andoma playing with black pieces
Expand All @@ -41,7 +79,7 @@ def test_go_command_black(self):
command(3, board, "go")

# black bishop should take a undefended rook
self.assertEqual(patched_output.getvalue().strip(), "bestmove d4b6")
self.assertEqual(patched_output.getvalue().splitlines()[1], "bestmove d4b6")

board = chess.Board()
with patch("sys.stdout", new=StringIO()) as patched_output:
Expand All @@ -53,7 +91,7 @@ def test_go_command_black(self):
command(3, board, "go")

# black will trade a bishop for a queen
self.assertEqual(patched_output.getvalue().strip(), "bestmove g7c3")
self.assertEqual(patched_output.getvalue().splitlines()[1], "bestmove g7c3")

board = chess.Board()
with patch("sys.stdout", new=StringIO()) as patched_output:
Expand All @@ -65,7 +103,7 @@ def test_go_command_black(self):
command(3, board, "go")

# black will threaten a bishop with a pawn (a very strong but not instantly obvious move)
self.assertEqual(patched_output.getvalue().strip(), "bestmove c5c4")
self.assertEqual(patched_output.getvalue().splitlines()[1], "bestmove c5c4")

def test_go_command_white(self):
"""
Expand All @@ -79,7 +117,7 @@ def test_go_command_white(self):
command(3, board, "go")

# white bishop should take a undefended rook
self.assertEqual(patched_output.getvalue().strip(), "bestmove b3g8")
self.assertEqual(patched_output.getvalue().splitlines()[1], "bestmove b3g8")

board = chess.Board()
with patch("sys.stdout", new=StringIO()) as patched_output:
Expand All @@ -91,7 +129,7 @@ def test_go_command_white(self):
command(3, board, "go")

# white will trade a bishop for a queen
self.assertEqual(patched_output.getvalue().strip(), "bestmove b2g7")
self.assertEqual(patched_output.getvalue().splitlines()[1], "bestmove b2g7")

board = chess.Board()
with patch("sys.stdout", new=StringIO()) as patched_output:
Expand All @@ -103,7 +141,7 @@ def test_go_command_white(self):
command(3, board, "go")

# white will threaten a bishop with a pawn (a very strong but not instantly obvious move)
self.assertEqual(patched_output.getvalue().strip(), "bestmove f4f5")
self.assertEqual(patched_output.getvalue().splitlines()[1], "bestmove f4f5")

def test_draw(self):
"""
Expand All @@ -119,4 +157,4 @@ def test_draw(self):
command(3, board, "go")

# bot is in a favorable position, should avoid threefold repetition
self.assertNotEqual(patched_output.getvalue().strip(), "bestmove c6a8")
self.assertNotEqual(patched_output.getvalue().splitlines()[1], "bestmove c6a8")

0 comments on commit 8c1793c

Please sign in to comment.