Exemple #1
0
def getNeighbors(node, endNode, wrld):
    listOfNeighbors = []
    # Go through neighboring cells
    for dx in [-1, 0, 1]:
        # Avoid out-of-bounds access
        if (node.x + dx >= 0) and (node.x + dx < wrld.width()):
            for dy in [-1, 0, 1]:
                # Avoid out-of-bounds access
                if (node.y + dy >= 0) and (node.y + dy < wrld.height()):
                    # add node if it's the end node, useful if calculating distance to monster
                    if endNode.x == node.x + dx and endNode.y == node.y + dy:
                        listOfNeighbors.append(
                            customEntities.Node(node.x + dx,
                                                node.y + dy,
                                                parent=node))
                    # Is this cell not a wall or an explosion?
                    elif not (wrld.wall_at(node.x + dx, node.y + dy)
                              or wrld.explosion_at(node.x + dx, node.y + dy)):
                        if not (dx == 0 and dy == 0):
                            listOfNeighbors.append(
                                customEntities.Node(node.x + dx,
                                                    node.y + dy,
                                                    parent=node))
    # All done
    return listOfNeighbors
Exemple #2
0
def calculateAStarPath(startNode, endNode, wrld, listOfMonsters,
                       shouldPathAroundMonsters):
    openNodes = []
    closedNodes = []
    # End node is position 7, 18
    startNode = customEntities.Node(startNode.x, startNode.y)
    openNodes.append(startNode)
    while len(openNodes) > 0:
        minNode = openNodes[0]
        currIndex = 0

        # find the smallest node fval and append it
        for index, currNode in enumerate(openNodes):
            if currNode.fval < minNode.fval:
                minNode = currNode
                currIndex = index

        openNodes.pop(currIndex)
        closedNodes.append(minNode)

        if minNode.x == endNode.x and minNode.y == endNode.y:
            path = []
            currNode = minNode
            while currNode is not None:
                path.append(currNode)
                currNode = currNode.parent
            return True, path[::-1]
        for neighbor in getNeighbors(minNode, endNode, wrld):
            isClosed = False
            isOpen = False

            sameNode = None
            nodeIndex = None
            for closedNode in closedNodes:
                if neighbor.x == closedNode.x and neighbor.y == closedNode.y:
                    isClosed = True
                    break
            for index, openNode in enumerate(openNodes):
                if neighbor.x == openNode.x and neighbor.y == openNode.y:
                    isOpen = True
                    sameNode = openNode
                    nodeIndex = index
                    break

            if not isClosed:
                neighbor.gval = minNode.gval + 1
                neighbor.hval = chebyshevDistance(neighbor, endNode,
                                                  listOfMonsters,
                                                  shouldPathAroundMonsters)
                neighbor.fval = neighbor.gval + neighbor.hval

                if isOpen and neighbor.fval < sameNode.fval:
                    openNodes[nodeIndex] = neighbor

                elif not isOpen:
                    openNodes.append(neighbor)
    return False, closedNodes
    def calculateCharacterPath(self, endNode, wrld, shouldPathAroundMonsters):
        startNode = customEntities.Node(self.x, self.y)
        path = astar.calculateAStarPath(startNode, endNode, wrld,
                                        self.monsters,
                                        shouldPathAroundMonsters)

        if path[0]:
            self.path = path[1]
        else:
            # if I can't find the exit after searching all possible nodes, I should find the node closest to the exit.
            #   > Also, flag that spot for bombing
            minNode = startNode
            minNode.hval = math.inf
            for node in path[1]:
                node.hval = astar.manhattanDistance(node, endNode)
                if node.hval < minNode.hval:
                    minNode = node

            if astar.manhattanDistance(minNode, endNode) == astar.manhattanDistance(self, endNode) \
                and self.bombTimer == 0 and len(wrld.explosions.items()) == 0:
                self.placeBombAtEnd = True

            else:
                self.calculateCharacterPath(minNode, wrld, True)
    def do(self, wrld):
        # recalculate the AStar path and distance from exit every time
        self.distanceFromExit = astar.chebyshevDistance(
            customEntities.Node(self.x, self.y), customEntities.Node(7, 18),
            self.monsters, False)
        self.calculateCharacterPath(customEntities.Node(7, 18), wrld, True)
        self.pathIterator = 0

        if self.shouldPanic and self.bombTimer == 0 and self.explosionTimer == 0:
            self.placeBombAtEnd = True

        if self.bombTimer == 0 and self.explosionTimer > 0:
            self.explosionTimer -= 1
            if self.explosionTimer == 0:
                self.bombPosition = None

        if self.bombTimer > 0:
            self.bombTimer -= 1
            if self.bombTimer == 0:
                self.numberOfBombsPlaced += 1
                self.explosionTimer = wrld.expl_duration + 1

        if len(self.path) == 1:
            self.runAway(wrld)

        if not self.monsters or len(self.monsters) != len(
                wrld.monsters.items()):
            self.monsters = []
            for key, monsterlist in wrld.monsters.items():
                for monster in monsterlist:
                    self.monsters.append(
                        customEntities.Monster(monster.x, monster.y))
        else:
            i = 0
            for key, monsterlist in wrld.monsters.items():
                for monster in monsterlist:
                    self.monsters[i].x = monster.x
                    self.monsters[i].y = monster.y
                i += 1
            for monster in self.monsters:
                monster.checkVelocity(wrld)
        if self.bombTimer <= 2 and self.bombPosition is not None:
            self.runAway(wrld)

        if self.checkIfNearMonster(self, wrld):
            # if my path ends at the exit
            selfIsCloserToExitThanMonster = True
            myPathToExit = astar.calculateAStarPath(self,
                                                    customEntities.Node(7, 18),
                                                    wrld, self.monsters, False)

            # if there isn't currently a path to the exit
            if not myPathToExit[0]:
                selfIsCloserToExitThanMonster = False

            else:
                for key, monsterlist in wrld.monsters.items():
                    for monster in monsterlist:
                        if len(myPathToExit[1]) >= len(
                                astar.calculateAStarPath(
                                    monster, customEntities.Node(7, 18), wrld,
                                    self.monsters, False)[1]):
                            selfIsCloserToExitThanMonster = False
                            break

            if self.shouldPanic and self.bombTimer == 0 and self.explosionTimer <= wrld.expl_duration - 1:
                self.placeBombAtEnd = True

            elif not selfIsCloserToExitThanMonster or (
                    self.bombTimer <= 2 and self.bombPosition is not None):
                # pick the spot out of the 8 cardinal directions that is least near to a monster.
                self.runAway(wrld)

            else:
                self.calculateCharacterPath(customEntities.Node(7, 18), wrld,
                                            False)

        if self.placeBombAtEnd:
            self.bombPosition = customEntities.Node(self.x, self.y)
            self.place_bomb()
            self.runAway(wrld)
            self.bombTimer = wrld.bomb_time
            self.placeBombAtEnd = False

        self.pathIterator += 1
        self.move(self.path[self.pathIterator].x - self.x,
                  self.path[self.pathIterator].y - self.y)
        return
    def runAway(self, wrld):
        # put current position into the path
        path = [customEntities.Node(self.x, self.y)]
        possibleNodes = []
        shouldRun = False

        # start by setting the lowest sum to infinity
        highestSum = -math.inf

        # get the set of neighbors, including ourself
        neighbors = astar.getNeighbors(self, customEntities.Node(7, 18), wrld)
        neighbors.append(customEntities.Node(self.x, self.y))

        # iterate over the available spots of the eight cardinal directions
        for node in neighbors:
            currSum = 0

            # if there's an explosion, don't add
            if wrld.explosion_at(node.x, node.y):
                continue

            shouldContinue = False

            # TODO account for other players bombs
            # do not include the nodes that would be in bomb's path of explosion
            if self.bombTimer <= 2 and self.bombPosition is not None:
                bombRange = wrld.expl_range
                for x in range(-bombRange, bombRange + 1):
                    if node.x == self.bombPosition.x + x and node.y == self.bombPosition.y:
                        shouldContinue = True
                        break

                for y in range(-bombRange, bombRange + 1):
                    if node.x == self.bombPosition.x and node.y == self.bombPosition.y + y:
                        shouldContinue = True
                        break
            if shouldContinue:
                continue

            node.hval = math.inf
            # for monster in monsterlist:
            for monster in self.monsters:
                pathBetweenSelfAndMonster = astar.calculateAStarPath(
                    node, monster, wrld, self.monsters, False)
                myDistance = len(
                    astar.calculateAStarPath(self, monster, wrld,
                                             self.monsters, False)[1])

                # if there is a path between myself and the monster
                if pathBetweenSelfAndMonster[0]:
                    distance = len(pathBetweenSelfAndMonster[1])
                    # distance = self.chebyshevDistance(node, monster, False)
                    if myDistance < self.distanceSmart and monster.type == "smart":
                        if distance < (self.distanceSmart - 1):
                            # try very hard not to get into detection range
                            currSum -= 5

                        elif distance < (self.distanceSmart - 2):
                            currSum -= 10
                            shouldRun = True

                        currSum += distance
                        node.hval = astar.manhattanDistance(node, monster)

                    elif myDistance < self.distanceStupid + 1:
                        currSum += distance
                        if distance < self.distanceStupid - 1:
                            shouldRun = True

            if currSum == highestSum:
                possibleNodes.append(node)

            elif currSum > highestSum:
                highestSum = currSum
                possibleNodes = [node]

        pathToStart = (astar.calculateAStarPath(self,
                                                customEntities.Node(5, 13),
                                                wrld, self.monsters, True))[1]
        self.calculateCharacterPath(customEntities.Node(7, 18), wrld, True)
        if not possibleNodes:
            # accept death.
            self.path = [
                customEntities.Node(self.x, self.y),
                customEntities.Node(self.x, self.y)
            ]
            return

        bestNode = None
        highestSum = -math.inf

        if shouldRun:
            for node in possibleNodes:
                if node.hval > highestSum:
                    bestNode = node
                    highestSum = node.hval

        if bestNode is None:
            # append possible nodes
            for node in possibleNodes:
                # if node is in the path to the end
                if len(self.path) > 1 and self.path[
                        1].x == node.x and self.path[1].y == node.y:
                    bestNode = node
                    break

        if bestNode is None:
            for node in possibleNodes:
                # if node is in the path to the start
                if len(pathToStart) > 1 and pathToStart[
                        1].x == node.x and pathToStart[1].y == node.y:
                    bestNode = node
                    break

        # if no node was added before, just add the first node
        if bestNode is not None:
            path.append(bestNode)
        else:
            path.append(possibleNodes[0])
        self.path = path