added lichess bot
This commit is contained in:
1
lichess_bot/test_bot/__init__.py
Normal file
1
lichess_bot/test_bot/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""pytest won't search `test_bot/` if there is no `__init__.py` file."""
|
||||
14
lichess_bot/test_bot/conftest.py
Normal file
14
lichess_bot/test_bot/conftest.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""Remove files created when testing lichess_bot."""
|
||||
import shutil
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
|
||||
def pytest_sessionfinish(session: Any, exitstatus: Any) -> None:
|
||||
"""Remove files created when testing lichess_bot."""
|
||||
shutil.copyfile("lib/correct_lichess.py", "lib/lichess.py")
|
||||
os.remove("lib/correct_lichess.py")
|
||||
if os.path.exists("TEMP") and not os.getenv("GITHUB_ACTIONS"):
|
||||
shutil.rmtree("TEMP")
|
||||
if os.path.exists("logs"):
|
||||
shutil.rmtree("logs")
|
||||
228
lichess_bot/test_bot/lichess.py
Normal file
228
lichess_bot/test_bot/lichess.py
Normal file
@@ -0,0 +1,228 @@
|
||||
"""Imitate `lichess.py`. Used in tests."""
|
||||
import time
|
||||
import chess
|
||||
import chess.engine
|
||||
import json
|
||||
import logging
|
||||
import traceback
|
||||
from lib.timer import seconds, to_msec
|
||||
from typing import Union, Any, Optional, Generator
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def backoff_handler(details: Any) -> None:
|
||||
"""Log exceptions inside functions with the backoff decorator."""
|
||||
logger.debug("Backing off {wait:0.1f} seconds after {tries} tries "
|
||||
"calling function {target} with args {args} and kwargs {kwargs}".format(**details))
|
||||
logger.debug(f"Exception: {traceback.format_exc()}")
|
||||
|
||||
|
||||
def is_final(error: Any) -> bool:
|
||||
"""Mock error handler for tests when a function has a backup decorator."""
|
||||
logger.debug(error)
|
||||
return False
|
||||
|
||||
|
||||
class GameStream:
|
||||
"""Imitate lichess.org's GameStream. Used in tests."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize `self.moves_sent` to an empty string. It stores the moves that we have already sent."""
|
||||
self.moves_sent = ""
|
||||
|
||||
def iter_lines(self) -> Generator[bytes, None, None]:
|
||||
"""Send the game events to lichess_bot."""
|
||||
yield json.dumps(
|
||||
{"id": "zzzzzzzz",
|
||||
"variant": {"key": "standard",
|
||||
"name": "Standard",
|
||||
"short": "Std"},
|
||||
"clock": {"initial": 60000,
|
||||
"increment": 2000},
|
||||
"speed": "bullet",
|
||||
"perf": {"name": "Bullet"},
|
||||
"rated": True,
|
||||
"createdAt": 1600000000000,
|
||||
"white": {"id": "bo",
|
||||
"name": "bo",
|
||||
"title": "BOT",
|
||||
"rating": 3000},
|
||||
"black": {"id": "b",
|
||||
"name": "b",
|
||||
"title": "BOT",
|
||||
"rating": 3000,
|
||||
"provisional": True},
|
||||
"initialFen": "startpos",
|
||||
"type": "gameFull",
|
||||
"state": {"type": "gameState",
|
||||
"moves": "",
|
||||
"wtime": 10000,
|
||||
"btime": 10000,
|
||||
"winc": 100,
|
||||
"binc": 100,
|
||||
"status": "started"}}).encode("utf-8")
|
||||
time.sleep(1)
|
||||
while True:
|
||||
time.sleep(0.001)
|
||||
with open("./logs/events.txt") as events:
|
||||
event = events.read()
|
||||
while True:
|
||||
try:
|
||||
with open("./logs/states.txt") as states:
|
||||
state = states.read().split("\n")
|
||||
moves = state[0]
|
||||
board = chess.Board()
|
||||
for move in moves.split():
|
||||
board.push_uci(move)
|
||||
wtime, btime = [seconds(float(n)) for n in state[1].split(",")]
|
||||
if len(moves) <= len(self.moves_sent) and not event:
|
||||
time.sleep(0.001)
|
||||
continue
|
||||
self.moves_sent = moves
|
||||
break
|
||||
except (IndexError, ValueError):
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
new_game_state = {"type": "gameState",
|
||||
"moves": moves,
|
||||
"wtime": int(to_msec(wtime)),
|
||||
"btime": int(to_msec(btime)),
|
||||
"winc": 100,
|
||||
"binc": 100}
|
||||
if event == "end":
|
||||
new_game_state["status"] = "outoftime"
|
||||
new_game_state["winner"] = "black"
|
||||
yield json.dumps(new_game_state).encode("utf-8")
|
||||
break
|
||||
if moves:
|
||||
new_game_state["status"] = "started"
|
||||
yield json.dumps(new_game_state).encode("utf-8")
|
||||
|
||||
|
||||
class EventStream:
|
||||
"""Imitate lichess.org's EventStream. Used in tests."""
|
||||
|
||||
def __init__(self, sent_game: bool = False) -> None:
|
||||
""":param sent_game: If we have already sent the `gameStart` event, so we don't send it again."""
|
||||
self.sent_game = sent_game
|
||||
|
||||
def iter_lines(self) -> Generator[bytes, None, None]:
|
||||
"""Send the events to lichess_bot."""
|
||||
if self.sent_game:
|
||||
yield b''
|
||||
time.sleep(1)
|
||||
else:
|
||||
yield json.dumps(
|
||||
{"type": "gameStart",
|
||||
"game": {"id": "zzzzzzzz",
|
||||
"source": "friend",
|
||||
"compat": {"bot": True,
|
||||
"board": True}}}).encode("utf-8")
|
||||
|
||||
|
||||
# Docs: https://lichess.org/api.
|
||||
class Lichess:
|
||||
"""Imitate communication with lichess.org."""
|
||||
|
||||
def __init__(self, token: str, url: str, version: str) -> None:
|
||||
"""Has the same parameters as `lichess.Lichess` to be able to be used in its placed without any modification."""
|
||||
self.baseUrl = url
|
||||
self.game_accepted = False
|
||||
self.moves: list[chess.engine.PlayResult] = []
|
||||
self.sent_game = False
|
||||
|
||||
def upgrade_to_bot_account(self) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def make_move(self, game_id: str, move: chess.engine.PlayResult) -> None:
|
||||
"""Write a move to `./logs/states.txt`, to be read by the opponent."""
|
||||
self.moves.append(move)
|
||||
uci_move = move.move.uci() if move.move else "error"
|
||||
with open("./logs/states.txt") as file:
|
||||
contents = file.read().split("\n")
|
||||
contents[0] += f" {uci_move}"
|
||||
with open("./logs/states.txt", "w") as file:
|
||||
file.write("\n".join(contents))
|
||||
|
||||
def chat(self, game_id: str, room: str, text: str) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def abort(self, game_id: str) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def get_event_stream(self) -> EventStream:
|
||||
"""Send the `EventStream`."""
|
||||
events = EventStream(self.sent_game)
|
||||
self.sent_game = True
|
||||
return events
|
||||
|
||||
def get_game_stream(self, game_id: str) -> GameStream:
|
||||
"""Send the `GameStream`."""
|
||||
return GameStream()
|
||||
|
||||
def accept_challenge(self, challenge_id: str) -> None:
|
||||
"""Set `self.game_accepted` to true."""
|
||||
self.game_accepted = True
|
||||
|
||||
def decline_challenge(self, challenge_id: str, reason: str = "generic") -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def get_profile(self) -> dict[str, Union[str, bool, dict[str, str]]]:
|
||||
"""Return a simple profile for the bot that lichess_bot uses when testing."""
|
||||
return {"id": "b",
|
||||
"username": "b",
|
||||
"online": True,
|
||||
"title": "BOT",
|
||||
"url": "https://lichess.org/@/b",
|
||||
"followable": True,
|
||||
"following": False,
|
||||
"blocking": False,
|
||||
"followsYou": False,
|
||||
"perfs": {}}
|
||||
|
||||
def get_ongoing_games(self) -> list[str]:
|
||||
"""Return that the bot isn't playing a game."""
|
||||
return []
|
||||
|
||||
def resign(self, game_id: str) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def get_game_pgn(self, game_id: str) -> str:
|
||||
"""Return a simple PGN."""
|
||||
return """
|
||||
[Event "Test game"]
|
||||
[Site "pytest"]
|
||||
[Date "2022.03.11"]
|
||||
[Round "1"]
|
||||
[White "bo"]
|
||||
[Black "b"]
|
||||
[Result "0-1"]
|
||||
|
||||
*
|
||||
"""
|
||||
|
||||
def get_online_bots(self) -> list[dict[str, Union[str, bool]]]:
|
||||
"""Return that the only bot online is us."""
|
||||
return [{"username": "b", "online": True}]
|
||||
|
||||
def challenge(self, username: str, params: dict[str, str]) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def cancel(self, challenge_id: str) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def online_book_get(self, path: str, params: Optional[dict[str, str]] = None) -> None:
|
||||
"""Isn't used in tests."""
|
||||
return
|
||||
|
||||
def is_online(self, user_id: str) -> bool:
|
||||
"""Return that a bot is online."""
|
||||
return True
|
||||
8
lichess_bot/test_bot/test-requirements.txt
Normal file
8
lichess_bot/test_bot/test-requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
pytest==7.4.4
|
||||
pytest-timeout==2.2.0
|
||||
flake8==7.0.0
|
||||
flake8-markdown==0.5.0
|
||||
flake8-docstrings==1.7.0
|
||||
mypy==1.8.0
|
||||
types-requests==2.31.0.20240106
|
||||
types-PyYAML==6.0.12.12
|
||||
319
lichess_bot/test_bot/test_bot.py
Normal file
319
lichess_bot/test_bot/test_bot.py
Normal file
@@ -0,0 +1,319 @@
|
||||
"""Test lichess_bot."""
|
||||
import pytest
|
||||
import zipfile
|
||||
import requests
|
||||
import time
|
||||
import yaml
|
||||
import chess
|
||||
import chess.engine
|
||||
import threading
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
import shutil
|
||||
import importlib
|
||||
from lib import config
|
||||
import tarfile
|
||||
from lib.timer import Timer, to_seconds, seconds
|
||||
from typing import Any
|
||||
if __name__ == "__main__":
|
||||
sys.exit(f"The script {os.path.basename(__file__)} should only be run by pytest.")
|
||||
shutil.copyfile("lib/lichess.py", "lib/correct_lichess.py")
|
||||
shutil.copyfile("test_bot/lichess.py", "lib/lichess.py")
|
||||
lichess_bot = importlib.import_module("lichess_bot")
|
||||
|
||||
platform = sys.platform
|
||||
file_extension = ".exe" if platform == "win32" else ""
|
||||
stockfish_path = f"./TEMP/sf{file_extension}"
|
||||
|
||||
|
||||
def download_sf() -> None:
|
||||
"""Download Stockfish 15."""
|
||||
if os.path.exists(stockfish_path):
|
||||
return
|
||||
|
||||
windows_or_linux = "windows" if platform == "win32" else "ubuntu"
|
||||
sf_base = f"stockfish-{windows_or_linux}-x86-64-modern"
|
||||
archive_ext = "zip" if platform == "win32" else "tar"
|
||||
archive_link = f"https://github.com/official-stockfish/Stockfish/releases/download/sf_16/{sf_base}.{archive_ext}"
|
||||
|
||||
response = requests.get(archive_link, allow_redirects=True)
|
||||
archive_name = f"./TEMP/sf_zip.{archive_ext}"
|
||||
with open(archive_name, "wb") as file:
|
||||
file.write(response.content)
|
||||
|
||||
archive_open = zipfile.ZipFile if archive_ext == "zip" else tarfile.TarFile
|
||||
with archive_open(archive_name, "r") as archive_ref:
|
||||
archive_ref.extractall("./TEMP/")
|
||||
|
||||
exe_ext = ".exe" if platform == "win32" else ""
|
||||
shutil.copyfile(f"./TEMP/stockfish/{sf_base}{exe_ext}", stockfish_path)
|
||||
|
||||
if windows_or_linux == "ubuntu":
|
||||
st = os.stat(stockfish_path)
|
||||
os.chmod(stockfish_path, st.st_mode | stat.S_IEXEC)
|
||||
|
||||
|
||||
def download_lc0() -> None:
|
||||
"""Download Leela Chess Zero 0.29.0."""
|
||||
if os.path.exists("./TEMP/lc0.exe"):
|
||||
return
|
||||
response = requests.get("https://github.com/LeelaChessZero/lc0/releases/download/v0.29.0/lc0-v0.29.0-windows-cpu-dnnl.zip",
|
||||
allow_redirects=True)
|
||||
with open("./TEMP/lc0_zip.zip", "wb") as file:
|
||||
file.write(response.content)
|
||||
with zipfile.ZipFile("./TEMP/lc0_zip.zip", "r") as zip_ref:
|
||||
zip_ref.extractall("./TEMP/")
|
||||
|
||||
|
||||
def download_sjeng() -> None:
|
||||
"""Download Sjeng."""
|
||||
if os.path.exists("./TEMP/sjeng.exe"):
|
||||
return
|
||||
response = requests.get("https://sjeng.org/ftp/Sjeng112.zip", allow_redirects=True)
|
||||
with open("./TEMP/sjeng_zip.zip", "wb") as file:
|
||||
file.write(response.content)
|
||||
with zipfile.ZipFile("./TEMP/sjeng_zip.zip", "r") as zip_ref:
|
||||
zip_ref.extractall("./TEMP/")
|
||||
shutil.copyfile("./TEMP/Release/Sjeng112.exe", "./TEMP/sjeng.exe")
|
||||
|
||||
|
||||
if not os.path.exists("TEMP"):
|
||||
os.mkdir("TEMP")
|
||||
download_sf()
|
||||
if platform == "win32":
|
||||
download_lc0()
|
||||
download_sjeng()
|
||||
logging_level = lichess_bot.logging.DEBUG
|
||||
lichess_bot.logging_configurer(logging_level, None, None, False)
|
||||
lichess_bot.logger.info("Downloaded engines")
|
||||
|
||||
|
||||
def thread_for_test() -> None:
|
||||
"""Play the moves for the opponent of lichess_bot."""
|
||||
open("./logs/events.txt", "w").close()
|
||||
open("./logs/states.txt", "w").close()
|
||||
open("./logs/result.txt", "w").close()
|
||||
|
||||
start_time = seconds(10)
|
||||
increment = seconds(0.1)
|
||||
|
||||
board = chess.Board()
|
||||
wtime = start_time
|
||||
btime = start_time
|
||||
|
||||
with open("./logs/states.txt", "w") as file:
|
||||
file.write(f"\n{to_seconds(wtime)},{to_seconds(btime)}")
|
||||
|
||||
engine = chess.engine.SimpleEngine.popen_uci(stockfish_path)
|
||||
engine.configure({"Skill Level": 0, "Move Overhead": 1000, "Use NNUE": False})
|
||||
|
||||
while not board.is_game_over():
|
||||
if len(board.move_stack) % 2 == 0:
|
||||
if not board.move_stack:
|
||||
move = engine.play(board,
|
||||
chess.engine.Limit(time=1),
|
||||
ponder=False)
|
||||
else:
|
||||
move_timer = Timer()
|
||||
move = engine.play(board,
|
||||
chess.engine.Limit(white_clock=to_seconds(wtime) - 2,
|
||||
white_inc=to_seconds(increment)),
|
||||
ponder=False)
|
||||
wtime -= move_timer.time_since_reset()
|
||||
wtime += increment
|
||||
engine_move = move.move
|
||||
if engine_move is None:
|
||||
raise RuntimeError("Engine attempted to make null move.")
|
||||
board.push(engine_move)
|
||||
|
||||
uci_move = engine_move.uci()
|
||||
with open("./logs/states.txt") as states:
|
||||
state_str = states.read()
|
||||
state = state_str.split("\n")
|
||||
state[0] += f" {uci_move}"
|
||||
state_str = "\n".join(state)
|
||||
with open("./logs/states.txt", "w") as file:
|
||||
file.write(state_str)
|
||||
|
||||
else: # lichess_bot move.
|
||||
move_timer = Timer()
|
||||
state2 = state_str
|
||||
moves_are_correct = False
|
||||
while state2 == state_str or not moves_are_correct:
|
||||
with open("./logs/states.txt") as states:
|
||||
state2 = states.read()
|
||||
time.sleep(0.001)
|
||||
moves = state2.split("\n")[0]
|
||||
temp_board = chess.Board()
|
||||
moves_are_correct = True
|
||||
for move_str in moves.split():
|
||||
try:
|
||||
temp_board.push_uci(move_str)
|
||||
except ValueError:
|
||||
moves_are_correct = False
|
||||
with open("./logs/states.txt") as states:
|
||||
state2 = states.read()
|
||||
if len(board.move_stack) > 1:
|
||||
btime -= move_timer.time_since_reset()
|
||||
btime += increment
|
||||
move_str = state2.split("\n")[0].split(" ")[-1]
|
||||
board.push_uci(move_str)
|
||||
|
||||
time.sleep(0.001)
|
||||
with open("./logs/states.txt") as states:
|
||||
state_str = states.read()
|
||||
state = state_str.split("\n")
|
||||
state[1] = f"{to_seconds(wtime)},{to_seconds(btime)}"
|
||||
state_str = "\n".join(state)
|
||||
with open("./logs/states.txt", "w") as file:
|
||||
file.write(state_str)
|
||||
|
||||
with open("./logs/events.txt", "w") as file:
|
||||
file.write("end")
|
||||
engine.quit()
|
||||
outcome = board.outcome()
|
||||
win = outcome.winner == chess.BLACK if outcome else False
|
||||
with open("./logs/result.txt", "w") as file:
|
||||
file.write("1" if win else "0")
|
||||
|
||||
|
||||
def run_bot(raw_config: dict[str, Any], logging_level: int) -> str:
|
||||
"""Start lichess_bot."""
|
||||
config.insert_default_values(raw_config)
|
||||
CONFIG = config.Configuration(raw_config)
|
||||
lichess_bot.logger.info(lichess_bot.intro())
|
||||
li = lichess_bot.lichess.Lichess(CONFIG.token, CONFIG.url, lichess_bot.__version__)
|
||||
|
||||
user_profile = li.get_profile()
|
||||
username = user_profile["username"]
|
||||
if user_profile.get("title") != "BOT":
|
||||
return "0"
|
||||
lichess_bot.logger.info(f"Welcome {username}!")
|
||||
lichess_bot.disable_restart()
|
||||
|
||||
thr = threading.Thread(target=thread_for_test)
|
||||
thr.start()
|
||||
lichess_bot.start(li, user_profile, CONFIG, logging_level, None, None, one_game=True)
|
||||
thr.join()
|
||||
|
||||
with open("./logs/result.txt") as file:
|
||||
data = file.read()
|
||||
return data
|
||||
|
||||
|
||||
@pytest.mark.timeout(150, method="thread")
|
||||
def test_sf() -> None:
|
||||
"""Test lichess_bot with Stockfish (UCI)."""
|
||||
if platform != "linux" and platform != "win32":
|
||||
assert True
|
||||
return
|
||||
if os.path.exists("logs"):
|
||||
shutil.rmtree("logs")
|
||||
os.mkdir("logs")
|
||||
with open("./config.yml.default") as file:
|
||||
CONFIG = yaml.safe_load(file)
|
||||
CONFIG["token"] = ""
|
||||
CONFIG["engine"]["dir"] = "./TEMP/"
|
||||
CONFIG["engine"]["name"] = f"sf{file_extension}"
|
||||
CONFIG["engine"]["uci_options"]["Threads"] = 1
|
||||
CONFIG["pgn_directory"] = "TEMP/sf_game_record"
|
||||
win = run_bot(CONFIG, logging_level)
|
||||
shutil.rmtree("logs")
|
||||
lichess_bot.logger.info("Finished Testing SF")
|
||||
assert win == "1"
|
||||
assert os.path.isfile(os.path.join(CONFIG["pgn_directory"],
|
||||
"bo vs b - zzzzzzzz.pgn"))
|
||||
|
||||
|
||||
@pytest.mark.timeout(150, method="thread")
|
||||
def test_lc0() -> None:
|
||||
"""Test lichess_bot with Leela Chess Zero (UCI)."""
|
||||
if platform != "win32":
|
||||
assert True
|
||||
return
|
||||
if os.path.exists("logs"):
|
||||
shutil.rmtree("logs")
|
||||
os.mkdir("logs")
|
||||
with open("./config.yml.default") as file:
|
||||
CONFIG = yaml.safe_load(file)
|
||||
CONFIG["token"] = ""
|
||||
CONFIG["engine"]["dir"] = "./TEMP/"
|
||||
CONFIG["engine"]["working_dir"] = "./TEMP/"
|
||||
CONFIG["engine"]["name"] = "lc0.exe"
|
||||
CONFIG["engine"]["uci_options"]["Threads"] = 1
|
||||
CONFIG["engine"]["uci_options"].pop("Hash", None)
|
||||
CONFIG["engine"]["uci_options"].pop("Move Overhead", None)
|
||||
CONFIG["pgn_directory"] = "TEMP/lc0_game_record"
|
||||
win = run_bot(CONFIG, logging_level)
|
||||
shutil.rmtree("logs")
|
||||
lichess_bot.logger.info("Finished Testing LC0")
|
||||
assert win == "1"
|
||||
assert os.path.isfile(os.path.join(CONFIG["pgn_directory"],
|
||||
"bo vs b - zzzzzzzz.pgn"))
|
||||
|
||||
|
||||
@pytest.mark.timeout(150, method="thread")
|
||||
def test_sjeng() -> None:
|
||||
"""Test lichess_bot with Sjeng (XBoard)."""
|
||||
if platform != "win32":
|
||||
assert True
|
||||
return
|
||||
if os.path.exists("logs"):
|
||||
shutil.rmtree("logs")
|
||||
os.mkdir("logs")
|
||||
with open("./config.yml.default") as file:
|
||||
CONFIG = yaml.safe_load(file)
|
||||
CONFIG["token"] = ""
|
||||
CONFIG["engine"]["dir"] = "./TEMP/"
|
||||
CONFIG["engine"]["working_dir"] = "./TEMP/"
|
||||
CONFIG["engine"]["protocol"] = "xboard"
|
||||
CONFIG["engine"]["name"] = "sjeng.exe"
|
||||
CONFIG["engine"]["ponder"] = False
|
||||
CONFIG["pgn_directory"] = "TEMP/sjeng_game_record"
|
||||
win = run_bot(CONFIG, logging_level)
|
||||
shutil.rmtree("logs")
|
||||
lichess_bot.logger.info("Finished Testing Sjeng")
|
||||
assert win == "1"
|
||||
assert os.path.isfile(os.path.join(CONFIG["pgn_directory"],
|
||||
"bo vs b - zzzzzzzz.pgn"))
|
||||
|
||||
|
||||
@pytest.mark.timeout(150, method="thread")
|
||||
def test_homemade() -> None:
|
||||
"""Test lichess_bot with a homemade engine running Stockfish (Homemade)."""
|
||||
if platform != "linux" and platform != "win32":
|
||||
assert True
|
||||
return
|
||||
strategies_py = "lib/strategies.py"
|
||||
with open(strategies_py) as file:
|
||||
original_strategies = file.read()
|
||||
|
||||
with open(strategies_py, "a") as file:
|
||||
file.write(f"""
|
||||
class Stockfish(ExampleEngine):
|
||||
def __init__(self, commands, options, stderr, draw_or_resign, **popen_args):
|
||||
super().__init__(commands, options, stderr, draw_or_resign, **popen_args)
|
||||
import chess
|
||||
self.engine = chess.engine.SimpleEngine.popen_uci('{stockfish_path}')
|
||||
|
||||
def search(self, board, time_limit, *args):
|
||||
return self.engine.play(board, time_limit)
|
||||
""")
|
||||
if os.path.exists("logs"):
|
||||
shutil.rmtree("logs")
|
||||
os.mkdir("logs")
|
||||
with open("./config.yml.default") as file:
|
||||
CONFIG = yaml.safe_load(file)
|
||||
CONFIG["token"] = ""
|
||||
CONFIG["engine"]["name"] = "Stockfish"
|
||||
CONFIG["engine"]["protocol"] = "homemade"
|
||||
CONFIG["pgn_directory"] = "TEMP/homemade_game_record"
|
||||
win = run_bot(CONFIG, logging_level)
|
||||
shutil.rmtree("logs")
|
||||
with open(strategies_py, "w") as file:
|
||||
file.write(original_strategies)
|
||||
lichess_bot.logger.info("Finished Testing Homemade")
|
||||
assert win == "1"
|
||||
assert os.path.isfile(os.path.join(CONFIG["pgn_directory"],
|
||||
"bo vs b - zzzzzzzz.pgn"))
|
||||
Reference in New Issue
Block a user