diff --git a/README.md b/README.md index a169966..ce4f1f3 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,12 @@ ychess is a chess implementation and engine written in nim. To play chess in the commandline simply download the code and run `nim c -r game.nim`. You can either play the 1v1 hotseat mode or a single player mode vs the engine. +### Lichess + +ychess uses the lichess api with the python plugin [berserk](https://github.com/rhgrant10/berserk). +An instance of the engine occasionally plays on [lichess](https://lichess.org/@/tiyn-ychess). +To get into the whitelist just write a ingame message to the account. + ## Testing Testing is done by `einheit` by [jyapayne](https://github.com/jyapayne/einheit). diff --git a/src/chess.nim b/src/chess.nim index 71681db..d7482f6 100644 --- a/src/chess.nim +++ b/src/chess.nim @@ -201,6 +201,19 @@ proc notationToMove*(notation: string, color: Color): Move = move = getMove(start, dest, prom, color) return move +proc moveToNotation*(move: Move): string = + ## Convert and return a `move` object to simplified algebraic chess notation. + var res = "" + var start = indToField(move.start) + res.add(start) + var dest = indToField(move.dest) + res.add(dest) + var color = move.color + var prom = PieceChar[move.prom] + if (color == Color.White and dest[1] == '8') or (color == Color.Black and dest[1] == '1'): + res.add(prom) + return res + proc initBoard(): Board = ## Create and return a board with pieces in starting position. let board = [ diff --git a/src/engine.nim b/src/engine.nim index 72ffec7..dc9ac43 100644 --- a/src/engine.nim +++ b/src/engine.nim @@ -1,4 +1,3 @@ -import sequtils import ./chess type diff --git a/src/lichess.nim b/src/lichess.nim new file mode 100644 index 0000000..1c7a7d3 --- /dev/null +++ b/src/lichess.nim @@ -0,0 +1,71 @@ +import nimpy +import asyncnet, asyncdispatch + +import ./secret.nim +import ./chess.nim +import ./engine.nim + +let berserk = pyImport("berserk") + +var session = berserk.TokenSession(secret.api_token) +var client = berserk.Client(session=session) + +let engineID = "tiyn-ychess" +let engineDifficulty = 5 +let toAccept = ["tiynger"] + + +proc playGame(id: string) {.async.} = + ## Plays a lichess game with `id` asynchronously. + var color: Color + var game = initGame() + for event in client.bots.stream_game_state(id): + echo(event) + if $event["type"] in ["gameState", "gameFull"]: + var movesString: PyObject + if $event["type"] == "gameFull": + echo("gameFull received") + movesString = event["state"]["moves"] + if $event["white"]["id"] == engineID: + echo("white assigned") + color = Color.White + if $event["black"]["id"] == engineID: + echo("black assigned") + color = Color.Black + else: + echo("gameState received") + movesString = event["moves"] + echo("movesString",movesString) + if $movesString != "": + echo("movestring not empty") + var moves = movesString.split(" ") + game.checkedMove(notationToMove($moves[-1], game.toMove)) + game.echoBoard(game.toMove) + echo("toMove", game.toMove) + echo("color", color) + if game.toMove == color: + echo("engine has to make a move") + var bestMove = moveToNotation(game.bestMove(engineDifficulty)) + echo(bestMove) + discard client.bots.make_move(id, bestMove) + +proc acceptChallenge(whiteList: openArray[string]): void = + ## Accepts a challenge of users in a `whiteList` and starts the + ## game process for each. + var events = client.bots.stream_incoming_events() + for event in events: + echo(event) + if $event["type"] == "challenge": + var challenger = $event["challenge"]["challenger"]["id"] + var id = $event["challenge"]["id"] + var speed = $event["challenge"]["speed"] + if challenger in whiteList and speed == "correspondence": + echo("challenge of ", challenger, " whiteList: ", id) + discard client.bots.accept_challenge(id) + discard playGame($event["challenge"]["id"]) + else: + discard client.bots.decline_challenge(id) + echo("challenge of ", challenger, " whiteList: ", id) + + +acceptChallenge(toAccept)