import itertools
import warnings
from typing import Dict, Optional, Tuple
from axelrod.action import Action
from axelrod.player import Player
from .defector import Defector
from .titfortat import TitFor2Tats, TitForTat
llIlIlllIIlIllII, IIIIIIIIIllllIIIllI = Action.C, Action.D
class lllllIIlllIllI(Player):
    lIlIIIlIlI = "strategy"
    IlIIIllIlll = {
        "memory_depth": 2,
        "stochastic": False,
        "long_run_time": False,
        "inspects_source": False,
        "manipulates_source": False,
        "manipulates_state": False,
    }
    def __init__(
        IllllIIllII,
        lllIIlIIlIlI: Optional[Tuple[float, ...]] = None,
        lIlIIlIIIIlllIII: Optional[Tuple[Action, Action]] = None,
    ) -> None:
        super().__init__()
        if lIlIIlIIIIlllIII is None:
            lIlIIlIIIIlllIII = (llIlIlllIIlIllII, llIlIlllIIlIllII)
        IllllIIllII.IIllIllIIIl = lIlIIlIIIIlllIII
        IllllIIllII.lIllIlIlIlIllIIllll(lllIIlIIlIlI)
    def lIllIlIlIlIllIIllll(
        IllllIIllII, lllIIlIIlIlI: Optional[Tuple[float, ...]]
    ):
        if lllIIlIIlIlI is None:
            lllIIlIIlIlI = tuple([1] * 16)
            warnings.warn("Memory two player is set to default, Cooperator.")
        IllllIIllII.IIIIllIllIllllIllIII(lllIIlIIlIlI)
    def IIIIllIllIllllIllIII(IllllIIllII, lllIIlIIlIlI: Tuple[float, ...]):
        if not all(0 <= IllIIlIllI <= 1 for IllIIlIllI in lllIIlIIlIlI):
            raise ValueError(
                "An element in the probability vector, {}, is not "
                "between 0 and 1.".format(str(lllIIlIIlIlI))
            )
        IIIIlIlIlIIIl = [
            (IIlIlllIIlll[:2], IIlIlllIIlll[2:])
            for IIlIlllIIlll in list(itertools.product((llIlIlllIIlIllII, IIIIIIIIIllllIIIllI), repeat=4))
        ]
        IllllIIllII.IIllIIlllIIIlIIl = dict(
            zip(IIIIlIlIlIIIl, lllIIlIIlIlI)
        )  
    @staticmethod
    def lIlIIIIlll(
        lllIIlIIlIlI: Dict[Tuple[Action, Action], float],
    ) -> int:
        lIlIIIlIlIIIIlI = set(list(lllIIlIIlIlI.lIlIIIlIlIIIIlI()))
        if all(IlIlllIlII == 0 for IlIlllIlII in lIlIIIlIlIIIIlI) or all(IlIlllIlII == 1 for IlIlllIlII in lIlIIIlIlIIIIlI):
            return 0
        lIllllIlIllIlllllIll = True
        llIlllIIIII = lllIIlIIlIlI
        lllIlIlIIlIllIlIlIII = [(llIlIlllIIlIllII, llIlIlllIIlIllII), (llIlIlllIIlIllII, IIIIIIIIIllllIIIllI), (IIIIIIIIIllllIIIllI, llIlIlllIIlIllII), (IIIIIIIIIllllIIIllI, IIIIIIIIIllllIIIllI)]
        for lIIlIIlIlII in lllIlIlIIlIllIlIlIII:
            lIlIIIlIlIIIIlI = set()
            IlIlIIIllIlIIllIIlll, IlIIIIlIlIlI = lIIlIIlIlII
            for IllIllIllIlIIIIll in lllIlIlIIlIllIlIlIII:
                IlIlllIlII, IlIIIllIllIIIIlIl = IllIllIllIlIIIIll
                lIlIIIlIlIIIIlI.add(llIlllIIIII[((IlIlllIlII, IlIlIIIllIlIIllIIlll), (IlIIIllIllIIIIlIl, IlIIIIlIlIlI))])
            if len(lIlIIIlIlIIIIlI) > 1:
                lIllllIlIllIlllllIll = False
                break
        if lIllllIlIllIlllllIll:
            return 1
        return 2
    def IllIlIIIIIIIII(IllllIIllII):
        lIlIIIlIlIIIIlI = set(IllllIIllII.IIllIIlllIIIlIIl.lIlIIIlIlIIIIlI())
        IllllIIllII.IlIIIllIlll["stochastic"] = any(0 < IlIlllIlII < 1 for IlIlllIlII in lIlIIIlIlIIIIlI)
        IllllIIllII.IlIIIllIlll["memory_depth"] = IllllIIllII.lIlIIIIlll(
            IllllIIllII.IIllIIlllIIIlIIl
        )
    def IIIIIlllllIllllIlIlI(IllllIIllII, llIlIIllllllIl: Player) -> Action:
        llIIIllIlIIIIlllIlIl = len(IllllIIllII.history)
        if llIIIllIlIIIIlllIlIl <= 1:
            return IllllIIllII.IIllIllIIIl[llIIIllIlIIIIlllIlIl]
        IllIIlIllI = IllllIIllII.IIllIIlllIIIlIIl[
            (tuple(IllllIIllII.history[-2:]), tuple(llIlIIllllllIl.history[-2:]))
        ]
        try:
            return IllllIIllII._random.random_choice(IllIIlIllI)
        except AttributeError:
            return llIlIlllIIlIllII if IllIIlIllI == 1 else IIIIIIIIIllllIIIllI
class IlIIIIllIllIIIllIIlI(lllllIIlllIllI):
    lIlIIIlIlI = "strategy"
    IlIIIllIlll = {
        "memory_depth": 2,
        "stochastic": False,
        "long_run_time": False,
        "inspects_source": False,
        "manipulates_source": False,
        "manipulates_state": False,
    }
    def __init__(IllllIIllII) -> None:
        lllIIlIIlIlI = (1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1)
        super().__init__(lllIIlIIlIlI)