# File: D (Python 2.4)

from direct.distributed.DistributedNodeAI import DistributedNodeAI
from direct.distributed.ClockDelta import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
from direct.fsm import StateData
from direct.distributed.ClockDelta import *
from toontown.safezone import CheckersBoard

class DistributedCheckersAI(DistributedNodeAI):
    
    def __init__(self, air, parent, name, x, y, z, h, p, r):
        DistributedNodeAI.__init__(self, air)
        self.name = name
        self.air = air
        self.setPos(x, y, z)
        self.setHpr(h, p, r)
        self.myPos = (x, y, z)
        self.myHpr = (h, p, r)
        self.board = CheckersBoard.CheckersBoard()
        self.parent = self.air.doId2do[parent]
        self.parentDo = parent
        self.wantStart = []
        self.playersPlaying = []
        self.playersSitting = 0
        self.playersTurn = 1
        self.movesMade = 0
        self.playerNum = 1
        self.hasWon = False
        self.playersGamePos = [
            None,
            None]
        self.wantTimer = True
        self.timerEnd = 0
        self.turnEnd = 0
        self.playersObserving = []
        self.winLaffPoints = 20
        self.movesRequiredToWin = 10
        self.zoneId = self.air.allocateZone()
        self.generateOtpObject(air.districtId, self.zoneId, optionalFields = [
            'setX',
            'setY',
            'setZ',
            'setH',
            'setP',
            'setR'])
        self.parent.setCheckersZoneId(self.zoneId)
        self.startingPositions = [
            [
                0,
                1,
                2,
                3,
                4,
                5,
                6,
                7,
                8,
                9,
                10,
                11],
            [
                20,
                21,
                22,
                23,
                24,
                25,
                26,
                27,
                28,
                29,
                30,
                31]]
        self.kingPositions = [
            [
                31,
                30,
                29,
                28],
            [
                0,
                1,
                2,
                3]]
        self.timerStart = None
        self.fsm = ClassicFSM.ClassicFSM('Checkers', [
            State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, [
                'playing']),
            State.State('playing', self.enterPlaying, self.exitPlaying, [
                'gameOver']),
            State.State('gameOver', self.enterGameOver, self.exitGameOver, [
                'waitingToBegin'])], 'waitingToBegin', 'waitingToBegin')
        self.fsm.enterInitialState()

    
    def announceGenerate(self):
        self.parent.setGameDoId(self.doId)

    
    def getTableDoId(self):
        return self.parentDo

    
    def delete(self):
        self.fsm.requestFinalState()
        self.board.delete()
        del self.fsm
        DistributedNodeAI.delete(self)

    
    def informGameOfPlayer(self):
        self.playersSitting += 1
        if self.playersSitting < 2:
            self.timerEnd = 0
        elif self.playersSitting == 2:
            self.timerEnd = globalClock.getRealTime() + 20
            self.parent.isAccepting = False
            self.parent.sendUpdate('setIsPlaying', [
                1])
        elif self.playersSitting > 2:
            pass
        
        self.sendUpdate('setTimer', [
            globalClockDelta.localToNetworkTime(self.timerEnd)])

    
    def informGameOfPlayerLeave(self):
        self.playersSitting -= 1
        if self.playersSitting < 2 and self.fsm.getCurrentState().getName() == 'waitingToBegin':
            self.timerEnd = 0
            self.parent.isAccepting = True
            self.parent.sendUpdate('setIsPlaying', [
                0])
        
        if self.playersSitting > 2 and self.fsm.getCurrentState().getName() == 'waitingToBegin':
            pass
        1
        self.timerEnd = 0
        if self.timerEnd != 0:
            self.sendUpdate('setTimer', [
                globalClockDelta.localToNetworkTime(self.timerEnd)])
        else:
            self.sendUpdate('setTimer', [
                0])

    
    def setGameCountdownTime(self):
        self.timerEnd = globalClock.getRealTime() + 10

    
    def setTurnCountdownTime(self):
        self.turnEnd = globalClock.getRealTime() + 40

    
    def getTimer(self):
        if self.timerEnd != 0:
            return 0
        else:
            return 0

    
    def getTurnTimer(self):
        return globalClockDelta.localToNetworkTime(self.turnEnd)

    
    def requestTimer(self):
        avId = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avId, 'setTimer', [
            globalClockDelta.localToNetworkTime(self.timerEnd)])

    
    def handlePlayerExit(self, avId):
        if avId in self.wantStart:
            self.wantStart.remove(avId)
        
        if self.fsm.getCurrentState().getName() == 'playing':
            gamePos = self.playersGamePos.index(avId)
            self.playersGamePos[gamePos] = None
            self.fsm.request('gameOver')
        

    
    def handleEmptyGame(self):
        self.movesMade = 0
        self.playersTurn = 1
        self.playerNum = 1
        self.fsm.request('waitingToBegin')
        self.parent.isAccepting = True

    
    def requestWin(self):
        avId = self.air.getAvatarIdFromSender()

    
    def distributeLaffPoints(self):
        for x in self.parent.seats:
            if x != None:
                av = self.air.doId2do.get(x)
                av.toonUp(self.winLaffPoints)
                continue
        

    
    def enterWaitingToBegin(self):
        self.setGameCountdownTime()
        self.parent.isAccepting = True

    
    def exitWaitingToBegin(self):
        self.turnEnd = 0

    
    def enterPlaying(self):
        self.parent.isAccepting = False
        for x in self.playersGamePos:
            if x != None:
                self.playersTurn = self.playersGamePos.index(x)
                self.d_sendTurn(self.playersTurn + 1)
                break
                continue
        
        self.setTurnCountdownTime()
        self.sendUpdate('setTurnTimer', [
            globalClockDelta.localToNetworkTime(self.turnEnd)])

    
    def exitPlaying(self):
        pass

    
    def enterGameOver(self):
        self.timerEnd = 0
        isAccepting = True
        self.parent.handleGameOver()
        self.playersObserving = []
        self.playersTurn = 1
        self.playerNum = 1
        self.clearBoard()
        self.sendGameState([])
        self.movesMade = 0
        self.playersGamePos = [
            None,
            None,
            None,
            None,
            None,
            None]
        self.parent.isAccepting = True
        self.fsm.request('waitingToBegin')

    
    def exitGameOver(self):
        pass

    
    def requestBegin(self):
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.wantStart:
            self.wantStart.append(avId)
        
        numPlayers = 0
        for x in self.parent.seats:
            if x != None:
                numPlayers = numPlayers + 1
                continue
        
        if len(self.wantStart) == numPlayers and numPlayers >= 2:
            self.d_gameStart(avId)
            self.parent.sendIsPlaying()
        

    
    def d_gameStart(self, avId):
        for x in self.playersObserving:
            self.sendUpdateToAvatarId(x, 'gameStart', [
                255])
        
        zz = 0
        numPlayers = 0
        for x in self.parent.seats:
            if x != None:
                numPlayers += 1
                self.playersPlaying.append(x)
                continue
        
        if numPlayers == 2:
            player1 = self.playersPlaying[0]
            self.sendUpdateToAvatarId(player1, 'gameStart', [
                1])
            self.playersGamePos[0] = player1
            for x in self.startingPositions[0]:
                self.board.setState(x, 1)
            
            player2 = self.playersPlaying[1]
            self.sendUpdateToAvatarId(player2, 'gameStart', [
                2])
            self.playersGamePos[1] = player2
            for x in self.startingPositions[1]:
                self.board.setState(x, 2)
            
        
        self.sendGameState([])
        self.wantStart = []
        self.fsm.request('playing')
        self.parent.getTableState()

    
    def d_sendTurn(self, playersTurn):
        self.sendUpdate('sendTurn', [
            playersTurn])

    
    def advancePlayerTurn(self):
        if self.playersTurn == 0:
            self.playersTurn = 1
            self.playerNum = 2
        else:
            self.playerNum = 1
            self.playersTurn = 0

    
    def requestMove(self, moveList):
        if self.checkLegalMoves(moveList) == True:
            self.makeMove(moveList)
            self.advancePlayerTurn()
            self.d_sendTurn(self.playersTurn + 1)
            self.setTurnCountdownTime()
            self.sendUpdate('setTurnTimer', [
                globalClockDelta.localToNetworkTime(self.turnEnd)])
        else:
            avId = self.air.getAvatarIdFromSender()
            self.sendUpdateToAvatarId(avId, 'illegalMove', [])
            self.air.writeServerEvent('suspicious', avId, 'has requested an illegal move in Regular checkers - not possible')

    
    def checkLegalMoves(self, moveList):
        if self.board.squareList[moveList[0]].getState() >= 3:
            moveType = 'king'
        else:
            moveType = 'normal'
        if len(moveList) == 2:
            firstSquare = self.board.squareList[moveList[0]]
            secondSquare = self.board.squareList[moveList[1]]
            if self.checkLegalMove(firstSquare, secondSquare, moveType) == True:
                return True
            else:
                for x in range(len(moveList) - 1):
                    y = self.checkLegalJump(self.board.getSquare(moveList[x]), self.board.getSquare(moveList[x + 1]), moveType)
                    if y == False:
                        return False
                    else:
                        return True
                    return False
                
        elif len(moveList) > 2:
            for x in range(len(moveList) - 1):
                y = self.checkLegalJump(self.board.getSquare(moveList[x]), self.board.getSquare(moveList[x + 1]), moveType)
                if y == False:
                    return False
                    continue
            
            return True
        

    
    def makeMove(self, moveList):
        for x in range(len(moveList) - 1):
            firstSquare = self.board.squareList[moveList[x]]
            secondSquare = self.board.squareList[moveList[x + 1]]
            if firstSquare.getNum() in secondSquare.getAdjacent():
                break
            
            index = firstSquare.jumps.index(secondSquare.getNum())
            self.board.squareList[firstSquare.getAdjacent()[index]].setState(0)
        
        haveMoved = False
        squareState = self.board.squareList[moveList[0]].getState()
        if squareState <= 2:
            piecetype = 'normal'
            if squareState == 1:
                playerNum = 1
            else:
                playerNum = 2
        else:
            piecetype = 'king'
            if squareState == 3:
                playerNum = 1
            else:
                playerNum = 2
        if piecetype == 'normal':
            lastElement = moveList[len(moveList) - 1]
            if playerNum == 1:
                if lastElement in self.kingPositions[0]:
                    self.board.squareList[moveList[0]].setState(0)
                    self.board.squareList[lastElement].setState(3)
                    haveMoved = True
                    self.sendGameState(moveList)
                
            elif lastElement in self.kingPositions[1]:
                self.board.squareList[moveList[0]].setState(0)
                self.board.squareList[lastElement].setState(4)
                haveMoved = True
                self.sendGameState(moveList)
            
        
        if haveMoved == False:
            spot1 = self.board.squareList[moveList[0]].getState()
            self.board.squareList[moveList[0]].setState(0)
            self.board.squareList[moveList[len(moveList) - 1]].setState(spot1)
            self.sendGameState(moveList)
        
        temp = self.playerNum
        self.playerNum = 1
        if self.hasWon == True:
            return None
        
        if self.hasPeicesAndMoves(1, 3) == False:
            self.parent.announceWinner('Checkers', self.playersPlaying[1])
            self.fsm.request('gameOver')
            self.hasWon = True
            return None
        
        self.playerNum = temp
        temp = self.playerNum
        self.playerNum = 2
        if self.hasPeicesAndMoves(2, 4) == False:
            self.parent.announceWinner('Checkers', self.playersPlaying[0])
            self.fsm.request('gameOver')
            self.hasWon = True
            return None
        
        self.playerNum = temp

    
    def hasPeicesAndMoves(self, normalNum, kingNum):
        for x in self.board.squareList:
            if x.getState() == normalNum:
                if self.existsLegalMovesFrom(x.getNum(), 'normal') == True:
                    return True
                
                if self.existsLegalJumpsFrom(x.getNum(), 'normal') == True:
                    return True
                
            self.existsLegalJumpsFrom(x.getNum(), 'normal') == True
            if x.getState() == kingNum:
                if self.existsLegalMovesFrom(x.getNum(), 'king') == True:
                    return True
                
                if self.existsLegalJumpsFrom(x.getNum(), 'king') == True:
                    return True
                
            self.existsLegalJumpsFrom(x.getNum(), 'king') == True
        
        return False

    
    def getState(self):
        return self.fsm.getCurrentState().getName()

    
    def getName(self):
        return self.name

    
    def getGameState(self):
        return [
            self.board.getStates(),
            []]

    
    def sendGameState(self, moveList):
        gameState = self.board.getStates()
        self.sendUpdate('setGameState', [
            gameState,
            moveList])

    
    def clearBoard(self):
        for x in self.board.squareList:
            x.setState(0)
        

    
    def getPosHpr(self):
        return self.posHpr

    
    def existsLegalJumpsFrom(self, index, peice):
        if peice == 'king':
            for x in range(4):
                if self.board.squareList[index].getAdjacent()[x] != None and self.board.squareList[index].getJumps()[x] != None:
                    adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]]
                    jump = self.board.squareList[self.board.squareList[index].getJumps()[x]]
                    if adj.getState() == 0:
                        pass
                    elif adj.getState() == self.playerNum or adj.getState() == self.playerNum + 2:
                        pass
                    elif jump.getState() == 0:
                        return True
                    
                adj.getState() == self.playerNum + 2
            
            return False
        elif peice == 'normal':
            if self.playerNum == 1:
                moveForward = [
                    1,
                    2]
            elif self.playerNum == 2:
                moveForward = [
                    0,
                    3]
            
            for x in moveForward:
                if self.board.squareList[index].getAdjacent()[x] != None and self.board.squareList[index].getJumps()[x] != None:
                    adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]]
                    jump = self.board.squareList[self.board.squareList[index].getJumps()[x]]
                    if adj.getState() == 0:
                        pass
                    elif adj.getState() == self.playerNum or adj.getState() == self.playerNum + 2:
                        pass
                    elif jump.getState() == 0:
                        return True
                    
                adj.getState() == self.playerNum + 2
            
            return False
        

    
    def existsLegalMovesFrom(self, index, peice):
        if peice == 'king':
            for x in self.board.squareList[index].getAdjacent():
                if x != None:
                    if self.board.squareList[x].getState() == 0:
                        return True
                    
                self.board.squareList[x].getState() == 0
            
            return False
        elif peice == 'normal':
            if self.playerNum == 1:
                moveForward = [
                    1,
                    2]
            elif self.playerNum == 2:
                moveForward = [
                    0,
                    3]
            
            for x in moveForward:
                if self.board.squareList[index].getAdjacent()[x] != None:
                    adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]]
                    if adj.getState() == 0:
                        return True
                    
                adj.getState() == 0
            
            return False
        

    
    def existsLegalJumpsFrom(self, index, peice):
        if peice == 'king':
            for x in range(4):
                if self.board.squareList[index].getAdjacent()[x] != None and self.board.squareList[index].getJumps()[x] != None:
                    adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]]
                    jump = self.board.squareList[self.board.squareList[index].getJumps()[x]]
                    if adj.getState() == 0:
                        pass
                    elif adj.getState() == self.playerNum or adj.getState() == self.playerNum + 2:
                        pass
                    elif jump.getState() == 0:
                        return True
                    
                adj.getState() == self.playerNum + 2
            
            return False
        elif peice == 'normal':
            if self.playerNum == 1:
                moveForward = [
                    1,
                    2]
            elif self.playerNum == 2:
                moveForward = [
                    0,
                    3]
            
            for x in moveForward:
                if self.board.squareList[index].getAdjacent()[x] != None and self.board.squareList[index].getJumps()[x] != None:
                    adj = self.board.squareList[self.board.squareList[index].getAdjacent()[x]]
                    jump = self.board.squareList[self.board.squareList[index].getJumps()[x]]
                    if adj.getState() == 0:
                        pass
                    elif adj.getState() == self.playerNum or adj.getState() == self.playerNum + 2:
                        pass
                    elif jump.getState() == 0:
                        return True
                    
                adj.getState() == self.playerNum + 2
            
            return False
        

    
    def checkLegalMove(self, firstSquare, secondSquare, peice):
        if self.playerNum == 1:
            moveForward = [
                1,
                2]
        else:
            moveForward = [
                0,
                3]
        if peice == 'king':
            for x in range(4):
                if firstSquare.getAdjacent()[x] != None:
                    if self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0:
                        return True
                    
                self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0
            
            return False
        elif peice == 'normal':
            for x in moveForward:
                if firstSquare.getAdjacent()[x] != None:
                    if self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0:
                        return True
                    
                self.board.squareList[firstSquare.getAdjacent()[x]].getState() == 0
            
            return False
        

    
    def checkLegalJump(self, firstSquare, secondSquare, peice):
        if self.playerNum == 1:
            moveForward = [
                1,
                2]
            opposingPeices = [
                2,
                4]
        else:
            moveForward = [
                0,
                3]
            opposingPeices = [
                1,
                3]
        if peice == 'king':
            if secondSquare.getNum() in firstSquare.getJumps():
                index = firstSquare.getJumps().index(secondSquare.getNum())
                if self.board.squareList[firstSquare.getAdjacent()[index]].getState() in opposingPeices:
                    return True
                else:
                    return False
            
        elif peice == 'normal':
            if secondSquare.getNum() in firstSquare.getJumps():
                index = firstSquare.getJumps().index(secondSquare.getNum())
                if index in moveForward:
                    if self.board.squareList[firstSquare.getAdjacent()[index]].getState() in opposingPeices:
                        return True
                    else:
                        return False
                else:
                    return False
            else:
                return False