# 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
    def moveTensor(analysis: Analysis, emt: Emt, boardTensor: List[int], avgEmt: Number, colour: Colour) -> MoveTensor:
        return [
            analysis[1].winningChances(colour),
            (analysis[0].winningChances(colour) - analysis[1].winningChances(colour)),
            emt,
            emt - avgEmt,
            100*((emt - avgEmt)/(avgEmt + 1e-8)),
        ] + boardTensor

    @staticmethod
    def nullBoardTensor():
        return [0, 0, 0]

    @staticmethod
    def nullMoveTensor() -> MoveTensor:
        return [0, 0, 0, 0, 0, 0, 0, 0]

    @staticmethod
    def ply(moveNumber: int, colour: Colour) -> int:
        return (2*(moveNumber-1)) + (0 if colour else 1)

class GameBSONHandler:
    @staticmethod
    def reads(bson: Dict) -> Game:
        return Game(
            id = bson['_id'],
            white = bson.get('white'),
            black = bson.get('black'),
            pgn = bson['pgn'],
            emts = bson['emts'],

# 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

    def moveTensor(analysis: Analysis, emt: Emt, boardTensor: List[int], avgEmt: Number, colour: Colour) -> MoveTensor:
        return [
            analysis[1].winningChances(colour),
            (analysis[0].winningChances(colour) - analysis[1].winningChances(colour)),
            emt,
            emt - avgEmt,
            100*((emt - avgEmt)/(avgEmt + 1e-8)),
        ] + boardTensor

    @staticmethod
    def nullBoardTensor():
        return [0, 0, 0]

    @staticmethod
    def nullMoveTensor() -> MoveTensor:
        return [0, 0, 0, 0, 0, 0, 0, 0]

    @staticmethod
    def ply(moveNumber: int, colour: Colour) -> int:
        return (2*(moveNumber-1)) + (0 if colour else 1)

class GameBSONHandler:
    @staticmethod
    def reads(bson: Dict) -> Game:
        return Game(
            id = bson['_id'],
            white = bson.get('white'),
            black = bson.get('black'),
            pgn = bson['pgn'],
            emts = bson['emts'],

            analysis = [EngineEvalBSONHandler.reads(a) for a in bson.get('analysis', [])])