# Path: modules/game/Colour.py

# 
# Path: modules/game/Player.py
# class Player(NamedTuple('Player', [
#     ('id', 'PlayerID'),
#     ('titled', bool),
#     ('engine', bool),
#     ('gamesPlayed', int)])):
# class PlayerBSONHandler:
# class PlayerDB(NamedTuple('PlayerDB', [
#         ('playerColl', 'Collection')
#     ])):
#     def fromJson(userData: Dict):
#     def reads(bson: Dict) -> Player:
#     def writes(player: Player) -> Dict:
#     def byId(self, playerId: PlayerID) -> Opt[Player]:
#     def byPlayerId(self, playerId: PlayerID) -> Opt[Player]:
#     def unmarkedByUserIds(self, playerIds: List[PlayerID]) -> List[Player]:
#     def engineSample(self, engine: bool, size: int) -> List[Player]:
#     def oldestNonEngine(self) -> Opt[Player]:
#     def byEngine(self, engine: bool = True) -> List[Player]:
#     def all(self) -> List[Player]:
#     def write(self, player: Player):
# 
# Path: modules/game/EngineEval.py
# class EngineEval(NamedTuple('EngineEval', [
#         ('cp', Opt[Number]),
#         ('mate', Opt[int])
#     ])):
#     @staticmethod
#     def fromDict(d: Dict):
#         return EngineEval(d.get('cp', None), d.get('mate', None))
# 
#     def asdict(self) -> Dict:
#         return {'cp': self.cp} if self.cp is not None else {'mate': self.mate}
# 
#     def inverse(self):
#         return EngineEval(-self.cp if self.cp is not None else None,
#             -self.mate if self.mate is not None else None)
# 
#     def winningChances(self, colour: Colour) -> Number:
#         if self.mate is not None:
#             base = (1 if self.mate > 0 else 0)
#         else:
#             base = 1 / (1 + exp(-0.004 * self.cp))
#         return 100*(base if colour else (1-base))
# 
# class EngineEvalBSONHandler:
#     @staticmethod
#     def reads(bson: Dict) -> List[EngineEval]:
#         return EngineEval.fromDict(bson)
# 
#     def writes(engineEval: EngineEval) -> Dict:
#         return engineEval.asdict()


from default_imports import *
from modules.game.Colour import Colour
from modules.game.Player import PlayerID
from modules.game.EngineEval import EngineEval, EngineEvalBSONHandler
from pymongo.collection import Collection
from multiprocessing import Pool
from chess.pgn import read_game
            from StringIO import StringIO
            from io import StringIO
import math
import chess
import numpy as np
        try:
        except ImportError:

        return read_game(StringIO(" ".join(self.pgn)))

    def boardTensors(self, colour):
        # replay the game for move tensors
        playable = self.playable()
        node = playable.variation(0)

        advancement = lambda rank: rank if colour else (7 - rank)

        while not node.is_end():
            nextNode = node.variation(0)

            board = node.board()
            move = node.move

            if board.turn == colour:
                yield (
                    [
                        advancement(chess.square_rank(move.to_square)),
                        board.pseudo_legal_moves.count(),
                        int(board.is_capture(move))
                    ],
                    board.piece_at(move.to_square).piece_type
                )

            node = nextNode


# Path: modules/game/Colour.py

# 
# Path: modules/game/Player.py
# class Player(NamedTuple('Player', [
#     ('id', 'PlayerID'),
#     ('titled', bool),
#     ('engine', bool),
#     ('gamesPlayed', int)])):
# class PlayerBSONHandler:
# class PlayerDB(NamedTuple('PlayerDB', [
#         ('playerColl', 'Collection')
#     ])):
#     def fromJson(userData: Dict):
#     def reads(bson: Dict) -> Player:
#     def writes(player: Player) -> Dict:
#     def byId(self, playerId: PlayerID) -> Opt[Player]:
#     def byPlayerId(self, playerId: PlayerID) -> Opt[Player]:
#     def unmarkedByUserIds(self, playerIds: List[PlayerID]) -> List[Player]:
#     def engineSample(self, engine: bool, size: int) -> List[Player]:
#     def oldestNonEngine(self) -> Opt[Player]:
#     def byEngine(self, engine: bool = True) -> List[Player]:
#     def all(self) -> List[Player]:
#     def write(self, player: Player):
# 
# Path: modules/game/EngineEval.py
# class EngineEval(NamedTuple('EngineEval', [
#         ('cp', Opt[Number]),
#         ('mate', Opt[int])
#     ])):
#     @staticmethod
#     def fromDict(d: Dict):
#         return EngineEval(d.get('cp', None), d.get('mate', None))
# 
#     def asdict(self) -> Dict:
#         return {'cp': self.cp} if self.cp is not None else {'mate': self.mate}
# 
#     def inverse(self):
#         return EngineEval(-self.cp if self.cp is not None else None,
#             -self.mate if self.mate is not None else None)
# 
#     def winningChances(self, colour: Colour) -> Number:
#         if self.mate is not None:
#             base = (1 if self.mate > 0 else 0)
#         else:
#             base = 1 / (1 + exp(-0.004 * self.cp))
#         return 100*(base if colour else (1-base))
# 
# class EngineEvalBSONHandler:
#     @staticmethod
#     def reads(bson: Dict) -> List[EngineEval]:
#         return EngineEval.fromDict(bson)
# 
#     def writes(engineEval: EngineEval) -> Dict:
#         return engineEval.asdict()


# Path: modules/game/Game.py
from default_imports import *
from modules.game.Colour import Colour
from modules.game.Player import PlayerID
from modules.game.EngineEval import EngineEval, EngineEvalBSONHandler
from pymongo.collection import Collection
from multiprocessing import Pool
from chess.pgn import read_game
            from StringIO import StringIO
            from io import StringIO
import math
import chess
import numpy as np

        try:
        except ImportError:

        return read_game(StringIO(" ".join(self.pgn)))

    def boardTensors(self, colour):
        # replay the game for move tensors
        playable = self.playable()
        node = playable.variation(0)

        advancement = lambda rank: rank if colour else (7 - rank)

        while not node.is_end():
            nextNode = node.variation(0)

            board = node.board()
            move = node.move

            if board.turn == colour:
                yield (
                    [
                        advancement(chess.square_rank(move.to_square)),
                        board.pseudo_legal_moves.count(),
                        int(board.is_capture(move))
                    ],
                    board.piece_at(move.to_square).piece_type
                )

            node = nextNode


    def boardTensorsByPlayerId(self, playerId: PlayerID, length: int = 60, safe: bool = True):