1import asyncio
2
3from gi.repository import GObject
4
5from .Move import Move
6from .lutils.egtb_k4it import EgtbK4kit
7from .lutils.egtb_gaviota import EgtbGaviota
8
9providers = []
10
11
12class EndgameTable(GObject.GObject):
13    """ Wrap the low-level providers of exact endgame knowledge. """
14
15    __gsignals__ = {
16        "scored": (GObject.SignalFlags.RUN_FIRST, None, (object, )),
17    }
18
19    def __init__(self):
20        GObject.GObject.__init__(self)
21
22        global providers
23        if not providers:
24            providers = [EgtbGaviota(), EgtbK4kit()]
25        self.providers = providers
26
27    def _pieceCounts(self, board):
28        return sorted([bin(board.friends[i]).count("1") for i in range(2)])
29
30    def scoreGame(self, lBoard, omitDepth=False, probeSoft=False):
31        """ Return result and depth to mate. (Intended for engine use.)
32
33            lBoard: A low-level board structure
34            omitDepth: Look up only the game's outcome (may save time)
35            probeSoft: Fail if the probe would require disk or network access.
36            Return value:
37            game_result: Either WHITEWON, DRAW, BLACKWON, or (on failure) None
38            depth: Depth to mate, or (if omitDepth or the game is drawn) None
39        """
40
41        piece_count = self._pieceCounts(lBoard)
42        for provider in self.providers:
43            if provider.supports(piece_count):
44                result, depth = provider.scoreGame(lBoard, omitDepth,
45                                                   probeSoft)
46                if result is not None:
47                    return result, depth
48        return None, None
49
50    @asyncio.coroutine
51    def scoreAllMoves(self, lBoard):
52        """ Return each move's result and depth to mate.
53
54            lBoard: A low-level board structure
55            Return value: a list, with best moves first, of:
56            move: A high-level move structure
57            game_result: Either WHITEWON, DRAW, BLACKWON
58            depth: Depth to mate
59        """
60
61        piece_count = self._pieceCounts(lBoard)
62        for provider in self.providers:
63            if provider.supports(piece_count):
64                results = yield from provider.scoreAllMoves(lBoard)
65                if results:
66                    ret = []
67                    for lmove, result, depth in results:
68                        ret.append((Move(lmove), result, depth))
69                    self.emit("scored", (lBoard, ret))
70                    return ret
71        return []
72