Skip to content

Instantly share code, notes, and snippets.

@yoniLavi
Created November 26, 2024 22:57
Show Gist options
  • Save yoniLavi/8b4a17829b13a648b573829336a189fc to your computer and use it in GitHub Desktop.
Save yoniLavi/8b4a17829b13a648b573829336a189fc to your computer and use it in GitHub Desktop.
A basic example of working with the lichess bot API
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"import requests\n",
"\n",
"LICHESS_TOKEN = \"PUT_TOKEN_HERE\" # A plain free token with the following permissions should suffice: challenge:read, challenge:write, board:play\n",
"LICHESS_API = \"https://lichess.org/api\"\n",
"HEADERS = {\n",
" \"Authorization\": f\"Bearer {LICHESS_TOKEN}\",\n",
" \"Content-Type\": \"application/x-www-form-urlencoded\"\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def create_ai_challenge(ai_level=1, our_color=\"white\"):\n",
" data = {\"level\": ai_level, \"color\": our_color}\n",
" response = requests.post(LICHESS_API + \"/challenge/ai\", data, headers=HEADERS)\n",
" if response.status_code != 201:\n",
" raise RuntimeError(f\"HTTP {response.status_code} when creating challenge: {response.text}\")\n",
"\n",
" return response.json()['id']\n",
"\n",
"\n",
"def make_move(game_id, move):\n",
" response = requests.post(LICHESS_API + f\"/board/game/{game_id}/move/{move}\", headers=HEADERS)\n",
" if response.status_code != 200:\n",
" raise RuntimeError(f\"HTTP {response.status_code} when making move: {response.text}\")\n",
"\n",
"\n",
"def get_ai_move(game_id, moves_so_far=1):\n",
" with requests.get(LICHESS_API + f\"/board/game/stream/{game_id}\", headers=HEADERS, stream=True) as response:\n",
" if response.status_code != 200:\n",
" raise RuntimeError(f\"HTTP {response.status_code} getting game state: {response.text}\")\n",
"\n",
" for line in response.iter_lines():\n",
" # there are different types of responses, with the moves being either at the top, or under \"state\"\n",
" state_response = json.loads(line.decode(\"utf-8\"))\n",
" moves = (state_response.get(\"state\", {}) or state_response).get(\"moves\", \"\").split()\n",
" if len(moves) <= moves_so_far:\n",
" continue\n",
" return moves[-1]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"New game created with ID: IcsAMCXv\n",
"We moved: e2e4; waiting for AI to move\n",
"AI's response move: e7e5\n",
"We moved: d2d4; waiting for AI to move\n",
"AI's response move: d7d5\n"
]
}
],
"source": [
"# Example usage\n",
"game_id = create_ai_challenge(ai_level=1, our_color=\"white\")\n",
"print(f\"New game created with ID: {game_id}\")\n",
"\n",
"our_first_move = \"e2e4\"\n",
"make_move(game_id, our_first_move)\n",
"print(f\"We moved: {our_first_move}; waiting for AI to move\")\n",
"ai_first_move = get_ai_move(game_id)\n",
"print(f\"AI's response move: {get_ai_move(game_id)}\")\n",
"\n",
"\n",
"our_second_move = \"d2d4\"\n",
"make_move(game_id, our_second_move)\n",
"print(f\"We moved: {our_second_move}; waiting for AI to move\")\n",
"ai_second_move = get_ai_move(game_id, moves_so_far=3)\n",
"print(f\"AI's response move: {get_ai_move(game_id)}\")\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment