Пример #1
0
def nodeValueAStar(node, wrld):

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

    # TODO account for other players bombs
    # do not include the nodes that would be in bomb's path of explosion
    for k, bomb in wrld.bombs.items():
        if node.bombTimer <= 2:
            bombRange = wrld.expl_range
            for x in range(-bombRange, bombRange):
                if node.x == bomb.x + x and node.y == bomb.y:
                    return None
            for y in range(-bombRange, bombRange):
                if node.x == bomb.x and node.y == bomb.y + y:
                    return None
    node.hval = math.inf

    currSum = 0
    # for monster in monsterlist:
    for monster in node.monsters:
        pathBetweenSelfAndMonster = astar.calculateAStarPath(
            node, monster, wrld, node.monsters, False)
        myDistance = len(
            astar.calculateAStarPath(node, monster, wrld, node.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 < node.distanceSmart and monster.type == "smart":
                if distance < (node.distanceSmart - 1):
                    # try very hard not to get into detection range
                    currSum -= 5

                elif distance < (node.distanceSmart - 2):
                    currSum -= 10

                currSum += distance

            elif myDistance < node.distanceStupid + 1:
                currSum += distance
    node.hval = currSum
    return node
    def checkIfNearMonster(self, node, wrld):
        for monster in self.monsters:
            # if SelfPreservingMonster (smart) monster is within <maxDistance> steps, return true
            pathBetweenSelfAndMonster = astar.calculateAStarPath(
                node, monster, wrld, self.monsters, False)

            # if there is path between myself and the monster
            if pathBetweenSelfAndMonster[0]:
                distance = len(pathBetweenSelfAndMonster[1])
                if monster.type is not None and monster.type == "smart" and distance - 1 < self.distanceSmart:
                    return True

                elif distance - 1 < self.distanceStupid:
                    return True

        return False
    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