text: from CrateGlobals import *
  from otp.level import DistributedEntityAI
  from direct.directnotify import DirectNotifyGlobal
  
  class DistributedGridAI(DistributedEntityAI.DistributedEntityAI):
      notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGridAI')
  
      def __init__(self, level, entId):
          self.initialized = 0
          DistributedEntityAI.DistributedEntityAI.__init__(self, level, entId)
          self.activeCellList = []
  
      def delete(self):
          DistributedEntityAI.DistributedEntityAI.delete(self)
          del self.activeCellList
  
      def generate(self):
          DistributedEntityAI.DistributedEntityAI.generate(self)
  
      def initializeGrid(self):
          if not self.initialized:
              self.objPos = {}
              self.gridCells = [None] * self.numRow
              for i in range(len(self.gridCells)):
                  self.gridCells[i] = [None] * self.numCol
                  for j in range(len(self.gridCells[i])):
                      self.gridCells[i][j] = []
  
              self.initialized = 1
          return
  
      def addActiveCell(self, cell):
          self.activeCellList.append(cell)
  
      def getObjPos(self, objId):
          objPos = self.objPos.get(objId, None)
          if objPos:
              row, col = objPos
              if row >= 0 and row < self.numRow and col >= 0 and col < self.numCol:
                  return [(col + 1) * self.cellSize, (row + 1) * self.cellSize, 0]
              else:
                  self.notify.debug('row/col out of range %s/%s' % (row, col))
          else:
              self.notify.debug("didn't have record of obj")
          return
  
      def addObjectByPos(self, objId, pos, width = 1):
          if not self.initialized:
              self.initializeGrid()
          if self.objPos.get(objId, None):
              return 1
          x, y = pos[0], pos[1]
          col = min(int(x / self.cellSize), self.numCol - width)
          row = min(int(y / self.cellSize), self.numRow - width)
          self.notify.debug('attempt add %d at %s, row,col = %d,%d' % (objId,
           pos,
           row,
           col))
          while col >= 0 and col < self.numCol:
              while row >= 0 and row < self.numRow:
                  if self.addObjectByRowCol(objId, row, col):
                      return 1
                  else:
                      row += 2
              else:
                  row = 0
                  col += 2
  
          else:
              self.notify.debug('requestObjPos: row/col out of range %s/%s' % (row, col))
              row = min(row, self.numRow)
              row = max(0, row)
              col = min(col, self.numRow)
              col = max(0, col)
              return self.addObjectByRowCol(objId, row, col)
  
          return
  
      def addObjectByRowCol(self, objId, row, col):
          if row >= 0 and row < self.numRow - 1 and col >= 0 and col < self.numCol - 1:
              self.notify.debug('adding obj %s to grid cell %s,%s' % (objId, row, col))
              self.gridCells[row][col].append(objId)
              self.gridCells[row + 1][col].append(objId)
              self.gridCells[row][col + 1].append(objId)
              self.gridCells[row + 1][col + 1].append(objId)
              self.objPos[objId] = [row, col]
              self.__setChangedActiveCells(onList=[[row, col],
               [row + 1, col],
               [row, col + 1],
               [row + 1, col + 1]], objId=objId)
              return 1
          self.notify.debug("couldn't obj to grid cell %s,%s" % (row, col))
          return 0
  
      def removeObject(self, objId):
          objPos = self.objPos.get(objId)
          if not objPos:
              return
          row, col = objPos
          self.notify.debug('removing obj %s from %s, %s' % (objId, row, col))
          self.gridCells[row][col].remove(objId)
          self.gridCells[row + 1][col].remove(objId)
          self.gridCells[row][col + 1].remove(objId)
          self.gridCells[row + 1][col + 1].remove(objId)
          del self.objPos[objId]
          self.__setChangedActiveCells(offList=[[row, col],
           [row + 1, col],
           [row, col + 1],
           [row + 1, col + 1]], objId=objId)
  
      def checkMoveDir(self, objId, h):
          if h > 225 and h < 315:
              return self.checkMove(objId, 0, 1)
          elif h > 45 and h < 135:
              return self.checkMove(objId, 0, -1)
          elif h < 45 or h > 315:
              return self.checkMove(objId, 1, 0)
          elif h > 135 and h < 225:
              return self.checkMove(objId, -1, 0)
  
      def doMoveDir(self, objId, h):
          if h > 225 and h < 315:
              return self.doMove(objId, 0, 1)
          elif h > 45 and h < 135:
              return self.doMove(objId, 0, -1)
          elif h < 45 or h > 315:
              return self.doMove(objId, 1, 0)
          elif h > 135 and h < 225:
              return self.doMove(objId, -1, 0)
  
      def checkPush(self, objId, side):
          if side == 0:
              return self.checkMove(objId, 0, -1)
          elif side == 1:
              return self.checkMove(objId, 0, 1)
          elif side == 2:
              return self.checkMove(objId, -1, 0)
          elif side == 3:
              return self.checkMove(objId, 1, 0)
  
      def doPush(self, objId, side):
          if side == 0:
              return self.doMove(objId, 0, -1)
          elif side == 1:
              return self.doMove(objId, 0, 1)
          elif side == 2:
              return self.doMove(objId, -1, 0)
          elif side == 3:
              return self.doMove(objId, 1, 0)
  
      def checkMove(self, objId, dRow, dCol):
          objPos = self.objPos.get(objId)
          if not objPos:
              return
          row, col = objPos
          validMove = 1
          if dRow < 0:
              validMove = validMove & self.__isEmpty(row - 1, col) & self.__isEmpty(row - 1, col + 1)
          elif dRow > 0:
              validMove = validMove & self.__isEmpty(row + 2, col) & self.__isEmpty(row + 2, col + 1)
          if dCol < 0:
              validMove = validMove & self.__isEmpty(row, col - 1) & self.__isEmpty(row + 1, col - 1)
          elif dCol > 0:
              validMove = validMove & self.__isEmpty(row, col + 2) & self.__isEmpty(row + 1, col + 2)
          return validMove
  
      def doMove(self, objId, dRow, dCol):
          objPos = self.objPos.get(objId)
          if not objPos:
              return 0
          row, col = objPos
          validMove = self.checkMove(objId, dRow, dCol)
          if validMove:
              self.gridCells[row][col].remove(objId)
              self.gridCells[row + 1][col].remove(objId)
              self.gridCells[row][col + 1].remove(objId)
              self.gridCells[row + 1][col + 1].remove(objId)
              newRow = row + dRow
              newCol = col + dCol
              self.gridCells[newRow][newCol].append(objId)
              self.gridCells[newRow + 1][newCol].append(objId)
              self.gridCells[newRow][newCol + 1].append(objId)
              self.gridCells[newRow + 1][newCol + 1].append(objId)
              self.objPos[objId] = [newRow, newCol]
              self.updateActiveCells(objId, row, col, dRow, dCol)
          return validMove
  
      def updateActiveCells(self, objId, row, col, dRow, dCol):
          newRow = row + dRow
          newCol = col + dCol
          newCells = [[newRow, newCol],
           [newRow + 1, newCol],
           [newRow, newCol + 1],
           [newRow + 1, newCol + 1]]
          oldCells = [[row, col],
           [row + 1, col],
           [row, col + 1],
           [row + 1, col + 1]]
          onList = []
          offList = []
          for cell in newCells:
              if cell not in oldCells:
                  onList.append(cell)
  
          for cell in oldCells:
              if cell not in newCells:
                  offList.append(cell)
  
          self.__setChangedActiveCells(onList, offList, objId)
  
      def __setChangedActiveCells(self, onList = [], offList = [], objId = None):
          for cell in self.activeCellList:
              self.notify.debug('onList = %s, offList = %s, cell = %s' % (onList, offList, cell.getRowCol()))
              if cell.getRowCol() in onList:
                  cell.b_setState(1, objId)
              elif cell.getRowCol() in offList:
                  cell.b_setState(0, objId)
  
      def __isEmpty(self, row, col):
          if row < 0 or row >= self.numRow or col < 0 or col >= self.numCol:
              return 0
          if len(self.gridCells[row][col]) > 0:
              return 0
          return 1
  
      def printGrid(self):
          if not __debug__:
              return
          for i in range(len(self.gridCells)):
              str = ''
              for j in range(len(self.gridCells[i])):
                  col = self.gridCells[i][j]
                  active = 0
                  for cell in self.activeCellList:
                      if cell.getRowCol() == [i, j]:
                          active = 1
  
                  if len(col) > 0:
                      if active:
                          str += '[X]'
                      else:
                          str += ' X '
                  elif active:
                      str += '[.]'
                  else:
                      str += ' . '
  
              print str + '  : %d' % i
  
          print ''
  