Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Changelog
=========

To be released
--------------

* Added::

client.analysis.get_cloud_evaluation

Thanks to @Anupya for their contributions to this release.

v0.13.1 (2023-11-02)
--------------------

Expand Down
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ Most of the API is available:
client.account.set_kid_mode
client.account.upgrade_to_bot

client.analysis.get_cloud_evaluation

client.board.stream_incoming_events
client.board.seek
client.board.stream_game_state
Expand Down
4 changes: 4 additions & 0 deletions berserk/clients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import requests

from .analysis import Analysis
from .base import BaseClient
from .account import Account
from .users import Users
Expand All @@ -26,6 +27,7 @@

__all__ = [
"Account",
"Analysis",
"Board",
"Bots",
"Broadcasts",
Expand Down Expand Up @@ -54,6 +56,7 @@ class Client(BaseClient):
All endpoints are namespaced into the clients below:

- :class:`account <berserk.clients.Account>` - managing account information
- :class:`account <berserk.clients.Analysis>` - getting information about position analysis
- :class:`bots <berserk.clients.Bots>` - performing bot operations
- :class:`broadcasts <berserk.clients.Broadcasts>` - getting and creating broadcasts
- :class:`challenges <berserk.clients.Challenges>` - using challenges
Expand Down Expand Up @@ -91,6 +94,7 @@ def __init__(
session = session or requests.Session()
super().__init__(session, base_url)
self.account = Account(session, base_url)
self.analysis = Analysis(session, base_url)
self.users = Users(session, base_url)
self.relations = Relations(session, base_url)
self.teams = Teams(session, base_url)
Expand Down
31 changes: 31 additions & 0 deletions berserk/clients/analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from typing import cast

from ..types import Variant
from .base import BaseClient
from ..types.analysis import PositionEvaluation


class Analysis(BaseClient):
"""Client for analysis-related endpoints."""

def get_cloud_evaluation(
self,
fen: str,
num_variations: int = 1,
variant: Variant = "standard",
) -> PositionEvaluation:
"""Get the cached evaluation of a position, if available.

Opening positions have more chances of being available. There are about 15 million positions in the database.
Up to 5 variations may be available. Variants are supported.

:param fen: FEN of a position
:param num_variations: number of variations
:param variant: game variant to use
:return: cloud evaluation of a position
"""
path = "/api/cloud-eval"
params = {"fen": fen, "multiPv": num_variations, "variant": variant}
return cast(PositionEvaluation, self._r.get(path=path, params=params))
20 changes: 20 additions & 0 deletions berserk/types/analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import List

from typing_extensions import TypedDict


class PrincipleVariation(TypedDict):
moves: str
"""Centipawn (cp) is the unit of measure used in chess as representation of the advantage. A centipawn is 1/100th
of a pawn. This value can be used as an indicator of the quality of play. The fewer centipawns one loses per move,
the stronger the play.
"""
cp: int


class PositionEvaluation(TypedDict):
fen: str
knodes: int
depth: int
""" Principle Variation (pv) is a variation composed of the "best" moves (in the opinion of the engine)."""
pvs: List[PrincipleVariation]
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
interactions:
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.31.0
method: GET
uri: https://lichess.org/api/cloud-eval?fen=rnbqkbnr%2Fppp1pppp%2F8%2F3pP3%2F8%2F8%2FPPPP1PPP%2FRNBQKBNR+b+KQkq+-+0+2&multiPv=1&variant=standard
response:
body:
string: '{"fen": "rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR b KQkq - 0 2","knodes":13683,"depth":22,"pvs":[{"moves":"c8f5 d2d4 e7e6 g1f3 g8e7 c1e3 c7c5 d4c5 e7c6 b1c3","cp":-13}]}'
headers:
Access-Control-Allow-Headers:
- Origin, Authorization, If-Modified-Since, Cache-Control, Content-Type
Access-Control-Allow-Methods:
- OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Thu, 02 Nov 2023 21:25:59 GMT
Permissions-Policy:
- interest-cohort=()
Server:
- nginx
Strict-Transport-Security:
- max-age=63072000; includeSubDomains; preload
Transfer-Encoding:
- chunked
Vary:
- Origin
X-Frame-Options:
- DENY
content-length:
- '6450'
status:
code: 200
message: OK
version: 1
16 changes: 16 additions & 0 deletions tests/clients/test_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import pytest

from berserk import Client

from berserk.types.analysis import PositionEvaluation
from utils import validate, skip_if_older_3_dot_10


class TestAnalysis:
@skip_if_older_3_dot_10
@pytest.mark.vcr
def test_get_cloud_evaluation(self):
res = Client().analysis.get_cloud_evaluation(
fen="rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR b KQkq - 0 2",
)
validate(PositionEvaluation, res)