Пример #1
0
class SneakingCommander(Commander):
    def initialize(self):
        self.makeGraph()

        self.graph.add_node("enemy_base")
        self.positions["enemy_base"] = None
        start, finish = self.level.botSpawnAreas[self.game.enemyTeam.name]
        for i, j in itertools.product(range(int(start.x), int(finish.x)),
                                      range(int(start.y), int(finish.y))):
            self.graph.add_edge("enemy_base", self.terrain[j][i], weight=1.0)

        self.graph.add_node("base")
        self.positions["base"] = None
        start, finish = self.level.botSpawnAreas[self.game.team.name]
        for i, j in itertools.product(range(int(start.x), int(finish.x)),
                                      range(int(start.y), int(finish.y))):
            self.graph.add_edge("base", self.terrain[j][i], weight=1.0)

        self.node_EnemyFlagIndex = self.getNodeIndex(
            self.game.team.flag.position)
        self.node_EnemyScoreIndex = self.getNodeIndex(
            self.game.enemyTeam.flagScoreLocation)

        # self.node_Bases = self.graph.add_vertex()
        # e = self.graph.add_edge(self.node_Bases, self.node_MyBase)
        # e = self.graph.add_edge(self.node_Bases, self.node_EnemyBase)

        vb2f = nx.shortest_path(self.graph,
                                source="enemy_base",
                                target=self.node_EnemyFlagIndex)
        vf2s = nx.shortest_path(self.graph,
                                source=self.node_EnemyFlagIndex,
                                target=self.node_EnemyScoreIndex)
        #vb2s = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyScoreIndex)

        self.node_EnemyBaseToFlagIndex = "enemy_base_to_flag"
        self.graph.add_node(self.node_EnemyBaseToFlagIndex)
        self.positions["enemy_base_to_flag"] = None
        for vertex in vb2f:
            self.graph.add_edge(self.node_EnemyBaseToFlagIndex,
                                vertex,
                                weight=1.0)

        self.node_EnemyFlagToScoreIndex = "enemy_flag_to_score"
        self.graph.add_node(self.node_EnemyFlagToScoreIndex)
        self.positions["enemy_flag_to_score"] = None
        for vertex in vf2s:
            self.graph.add_edge(self.node_EnemyFlagToScoreIndex,
                                vertex,
                                weight=1.0)

        self.node_EnemyBaseToScoreIndex = "enemy_base_to_score"
        self.graph.add_node(self.node_EnemyBaseToScoreIndex)
        self.positions["enemy_base_to_score"] = None
        # for vertex in vb2s:
        #     self.graph.add_edge(self.node_EnemyBaseToScoreIndex, vertex, weight = 1.0)

        ## node = self.makeNode(self.game.enemyTeam.flag.position)
        self.distances = nx.single_source_shortest_path_length(
            self.graph, self.node_EnemyFlagToScoreIndex)

        self.graph.remove_node("base")
        self.graph.remove_node("enemy_base")
        self.graph.remove_node(self.node_EnemyBaseToFlagIndex)
        self.graph.remove_node(self.node_EnemyFlagToScoreIndex)
        self.graph.remove_node(self.node_EnemyBaseToScoreIndex)

        self.updateEdgeWeights()

        self.paths = {b: None for b in self.game.team.members}

        self.visualizer = VisualizerApplication(self)
        self.visualizer.setDrawHookPreWorld(self.drawPreWorld)
        self.visualizer.setDrawHookPreBots(self.drawPreBots)
        self.visualizer.setDrawHookEnd(self.drawEnd)
        # self.visualizer.setKeyboardHook(self.keyboard)

    def getDistance(self, x, y):
        n = self.terrain[y][x]
        if n:
            return self.distances[n]
        else:
            return 0.0

    def shutdown(self):
        self.visualizer.quit()
        del self.visualizer

    def makeGraph(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        g = nx.Graph(directed=False, map_height=height, map_width=width)
        #self.positions = g.new_vertex_property('vector<float>')
        #self.weights = g.new_edge_property('float')

        #g.vertex_properties['pos'] = self.positions
        #g.edge_properties['weight'] = self.weights

        self.terrain = []
        self.positions = {}
        for j in range(0, height):
            row = []
            for i in range(0, width):
                if blocks[i][j] == 0:
                    g.add_node(i + j * width,
                               position=(float(i) + 0.5, float(j) + 0.5))
                    self.positions[i + j * width] = Vector2(
                        float(i) + 0.5,
                        float(j) + 0.5)
                    row.append(i + j * width)
                else:
                    row.append(None)
            self.terrain.append(row)

        for i, j in itertools.product(range(0, width), range(0, height)):
            p = self.terrain[j][i]
            if not p: continue

            if i < width - 1:
                q = self.terrain[j][i + 1]
                if q:
                    e = g.add_edge(p, q, weight=1.0)

            if j < height - 1:
                r = self.terrain[j + 1][i]
                if r:
                    e = g.add_edge(p, r, weight=1.0)

        self.graph = g

    def getNodeIndex(self, position):
        i = int(position.x)
        j = int(position.y)
        width = self.graph.graph["map_width"]
        return i + j * width

    def updateEdgeWeights(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        # update the weights in the graph based on the distance to the shortest path between the enemy flag and enemy score location

        for j in range(0, height):
            for i in range(0, width - 1):
                a = self.terrain[j][i]
                b = self.terrain[j][i + 1]
                if a and b:
                    w = max(255 - 4 * (self.distances[a] + self.distances[b]),
                            0)
                    self.graph[a][b]['weight'] = w

        for j in range(0, height - 1):
            for i in range(0, width):
                a = self.terrain[j][i]
                b = self.terrain[j + 1][i]
                if a and b:
                    w = max(255 - 4 * (self.distances[a] + self.distances[b]),
                            0)
                    self.graph[a][b]['weight'] = w

    def tick(self):
        for bot in self.game.bots_alive:
            if bot.state == BotInfo.STATE_IDLE:
                if not bot.flag:
                    # go to flag
                    dst = self.game.enemyTeam.flag.position
                    message = 'go to flag'
                else:
                    # go home
                    dst = self.game.team.flagScoreLocation
                    message = 'go home'

                # calculate the shortest path between the bot and the target using our weights
                srcIndex = self.getNodeIndex(bot.position)
                dstIndex = self.getNodeIndex(dst)
                pathNodes = nx.shortest_path(self.graph, srcIndex, dstIndex,
                                             'weight')

                pathLength = len(pathNodes)
                if pathLength > 0:
                    path = [
                        self.positions[p] for p in pathNodes
                        if self.positions[p]
                    ]
                    if len(path) > 0:
                        orderPath = path[::10]
                        orderPath.append(
                            path[-1]
                        )  # take every 10th point including last point
                        self.issue(commands.Move,
                                   bot,
                                   orderPath,
                                   description=message)
                        self.paths[
                            bot] = path  # store the path for visualization

        self.visualizer.tick()

    def drawPreWorld(self, visualizer):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        furthest = max(
            [self.distances[n] for n in itertools.chain(*self.terrain) if n])

        for i, j in itertools.product(range(width), range(height)):
            # average weights of edges connected to this node
            sum, count = 0, 0
            node = self.terrain[j][i]
            if node:
                for offset in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                    ni, nj = i + offset[0], j + offset[1]
                    if ni < 0 or ni >= width or nj < 0 or nj >= height:
                        continue
                    neighbour = self.terrain[nj][ni]
                    if neighbour:
                        sum, count = sum + self.graph[node][neighbour][
                            'weight'], count + 1
            if count:
                d = sum / count
            else:
                d = 32

            if self.level.blockHeights[i][j] == 1:
                visualizer.drawPixel((i, j), QtGui.qRgb(196, 196, 196))
            elif self.level.blockHeights[i][j] >= 2:
                visualizer.drawPixel((i, j), QtGui.qRgb(64, 64, 64))
            else:
                visualizer.drawPixel((i, j), QtGui.qRgb(d, d, d))

    def drawPreBots(self, visualizer):
        for name, bot in self.game.bots.items():
            if bot.position is None:
                continue

            if 'Red' in name:
                color = QtGui.qRgb(255, 0, 0)
                pathColor = QtGui.qRgb(127, 0, 0)
            else:
                color = QtGui.qRgb(0, 0, 255)
                pathColor = QtGui.qRgb(0, 0, 127)

            if bot.health <= 0.0:
                color = QtGui.qRgb(0, 0, 0)

            if (bot.health > 0) and (bot in self.paths) and self.paths[bot]:
                path = self.paths[bot]
                pLast = bot.position
                for p in path:
                    visualizer.drawPixel((int(p.x), int(p.y)),
                                         QtGui.qRgb(255, 255, 0))
                    # visualizer.drawRay(pLast, p, color)
                    pLast = p

    def drawEnd(self, visualizer):
        pass
Пример #2
0
class AmbushCommander(Commander):
    """
        Display current state and predictions on the screen in a PyQT application.
    """
    MODE_VISIBILITY = 0 
    MODE_TRAVELLING = 1

    def drawPreWorld(self, visualizer):
       furthest = max([self.distances[n] for n in itertools.chain(*self.terrain) if n])
       brightest = max([self.visibilities.pixel(i,j) for i, j in itertools.product(range(88), range(50))])
        
        # visible = QtGui.QImage(88, 50, QtGui.QImage.Format_ARGB32)
        # visible.fill(0)

       for i, j in itertools.product(range(88), range(50)):            
            n = self.terrain[j][i]
            if n:
                if self.mode == self.MODE_TRAVELLING:
                    d = self.distances[n] * 255.0 / furthest
                if self.mode == self.MODE_VISIBILITY:
                    d = self.visibilities.pixel(i,j) * 255 / brightest
            else:                
                d = 32
            visualizer.drawPixel((i, j), QtGui.qRgb(d,d,d))
                
    def drawPreBots(self, visualizer):
        for p, _ in self.ambushes:
            visualizer.drawCircle(p, QtGui.qRgb(255,255,0), 0.5)
            
    def keyPressed(self, e):
        if e.key() == QtCore.Qt.Key_Space:
            self.mode = 1 - self.mode

    def initialize(self):
        self.mode = self.MODE_VISIBILITY
        self.visualizer = VisualizerApplication(self)

        self.visualizer.setDrawHookPreWorld(self.drawPreWorld)
        self.visualizer.setDrawHookPreBots(self.drawPreBots)
        self.visualizer.setKeyboardHook(self.keyPressed)

        self.makeGraph()
        
        self.graph.add_node("enemy_base")
        start, finish = self.level.botSpawnAreas[self.game.enemyTeam.name]        
        for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))):
            self.graph.add_edge("enemy_base", self.terrain[j][i], weight = 1.0)            


        self.graph.add_node("base")
        start, finish = self.level.botSpawnAreas[self.game.team.name]        
        for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))):
            self.graph.add_edge("base", self.terrain[j][i],weight = 1.0)            


        self.node_EnemyFlagIndex = self.getNodeIndex(self.game.team.flag.position)
        self.node_EnemyScoreIndex = self.getNodeIndex(self.game.enemyTeam.flagScoreLocation)

        # self.node_Bases = self.graph.add_vertex()
        # e = self.graph.add_edge(self.node_Bases, self.node_MyBase)
        # e = self.graph.add_edge(self.node_Bases, self.node_EnemyBase)

        vb2f = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyFlagIndex)
        vf2s = nx.shortest_path(self.graph, source=self.node_EnemyFlagIndex, target=self.node_EnemyScoreIndex)
        #vb2s = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyScoreIndex)

        self.visibilities = QtGui.QImage(88, 50, QtGui.QImage.Format_ARGB32)
        self.visibilities.fill(0)
        path = vb2f+vf2s
        edgesinpath=zip(path[0:],path[1:])        
        for vt, vf in edgesinpath[:-1]:
            if "position" not in self.graph.node[vf]:
                continue
            position = Vector2(*self.graph.node[vf]["position"])
            if "position" not in self.graph.node[vt]:
                continue
            next_position = Vector2(*self.graph.node[vt]["position"])
            if position == next_position:
                continue
            orientation = (next_position - position).normalized()

            def visible(p):
                delta = (p-position)
                l = delta.length()
                if l > 20.0:
                    return False
                if l < 2.5:
                    return True
                delta /= l
                return orientation.dotProduct(delta) >= 0.5

            cells = []
            w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y)))
            w.compute(position)

            for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]:
                self.visibilities.setPixel(x, y, self.visibilities.pixel(x, y)+1)

        starte, finishe = self.level.botSpawnAreas[self.game.enemyTeam.name]
        startf, finishf = self.level.botSpawnAreas[self.game.team.name]
        points = [self.game.team.flag.position, self.game.enemyTeam.flag.position,
                  self.game.team.flagScoreLocation, self.game.enemyTeam.flagScoreLocation] * 4
        for i, j in list(itertools.product(range(int(starte.x), int(finishe.x)), range(int(starte.y), int(finishe.y)))) \
                    + list(itertools.product(range(int(startf.x), int(finishf.x)), range(int(startf.y), int(finishf.y)))) \
                    + [(int(p.x), int(p.y)) for p in points]:
            n = self.terrain[j][i]
            if not n: continue
            
            position = Vector2(*self.graph.node[n]["position"])
            def visible(p):
                delta = (p-position)
                l = delta.length()
                return l <= 15.0

            cells = []
            w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y)))
            w.compute(position)

            for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]:
                self.visibilities.setPixel(x, y, self.visibilities.pixel(x, y)+1)


        self.node_EnemyBaseToFlagIndex = "enemy_base_to_flag"
        self.graph.add_node(self.node_EnemyBaseToFlagIndex)
        for vertex in vb2f:
            self.graph.add_edge(self.node_EnemyBaseToFlagIndex, vertex, weight = 1.0)
        
        self.node_EnemyFlagToScoreIndex = "enemy_flag_to_score" 
        self.graph.add_node(self.node_EnemyFlagToScoreIndex)
        for vertex in vf2s:
            self.graph.add_edge(self.node_EnemyFlagToScoreIndex, vertex, weight = 1.0)
        
        self.node_EnemyBaseToScoreIndex = "enemy_base_to_score"
        self.graph.add_node(self.node_EnemyBaseToScoreIndex)
       # for vertex in vb2s:
       #     self.graph.add_edge(self.node_EnemyBaseToScoreIndex, vertex, weight = 1.0)

        ## node = self.makeNode(self.game.enemyTeam.flag.position)
        self.distances = nx.single_source_shortest_path_length(self.graph, self.node_EnemyFlagToScoreIndex)
        self.queue = {}
        self.index = 0
        print "Done with init. Calculating ambush spots"
        self.calculateAmbushes()

    def evaluate(self, position, orientation, callback):
        cells = []
        w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y)))
        w.compute(position)

        def visible(p):
            delta = (p-position)
            l = delta.length()
            if l > 15.0:
                return False
            if l < 2.5:
                return True
            delta /= l
            return orientation.dotProduct(delta) > 0.9238

        total = 0.0
        for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]:
            total += callback(x,y)
        return total

    def findNearby(self, results, candidate, distance = 2.0):
        d = distance * distance
        s, (position, _) = candidate
        for _, (p, _) in results:
            if (p-position).squaredLength() < d:
                return True            
        return False

    def replaceInList(self, candidate, results, maximum = 40):
        results.append(candidate)

        if len(results) < 50:
            return

        copy = results[:]
        copy.sort(key=lambda s: -s[0])

        results[:] = []

        for i, c in enumerate(copy):
            if not self.findNearby(results, c):
                results.append(c)
            if len(results) >= maximum:
                break

    def calculateAmbushes(self):        
        results = []
        for i in range(2000):  # NOTE: you must feed in better pre-selected positions (eg near boxes) to get good results with this number of iterations.
            if (i%1000)==0: print >>sys.stderr, '.',
            p = self.level.findRandomFreePositionInBox(self.level.area)
            o = Vector2(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5)).normalized()

            s = self.evaluate(p, o, lambda x, y: 25.0-square(self.getDistance(x, y))) - square(self.visibilities.pixel(int(p.x), int(p.y)) * 5.0)
            self.replaceInList((s, (p,o)), results)

        self.ambushes = [r for _, r in results]

    def getSituation(self):
        result = None
        score = 0.0
        for i in range(10):
            p = self.level.findRandomFreePositionInBox(self.level.area)
            o = Vector2(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5)).normalized()
            s = self.evaluate(p, o, lambda x, y: 15.0-self.getDistance(x, y))
                # - self.getDistance(int(p.x), int(p.y)) * 100 
            if s > score or result == None:
                result = (p, o)
                score = s
        print score
        return result

    def getDistance(self, x, y):
        n = self.terrain[y][x]
        if n:
            return self.distances[n]
        else:
            return 0.0

    def tick(self):
        for e in self.game.match.combatEvents[self.index:]:
            if e.type != gameinfo.MatchCombatEvent.TYPE_RESPAWN:
                continue
            if e.subject in self.queue:
                del self.queue[e.subject] 
        self.index = len(self.game.match.combatEvents)

        for bot in self.game.bots_available:
            if bot in self.queue:
                p, o = self.queue[bot]
                if (bot.position-p).length() < 1.0:
                    self.issue(commands.Defend, bot, o)
                    continue
            else:
                p, o = random.choice(self.ambushes)
                self.queue[bot] = (p, o)
            
            self.issue(commands.Charge, bot, p)
        
        self.visualizer.tick()

    def shutdown(self):
        self.visualizer.quit()
        del self.visualizer

    def makeGraph(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        g = nx.Graph(directed=False, map_height = height, map_width = width)
        #self.positions = g.new_vertex_property('vector<float>')
        #self.weights = g.new_edge_property('float')
    
        #g.vertex_properties['pos'] = self.positions
        #g.edge_properties['weight'] = self.weights
    
        self.terrain = []
        for j in range(0, height):
            row = []
            for i in range(0,width):
                if blocks[i][j] == 0:
                    g.add_node(i+j*width, position = (float(i)+0.5, float(j)+0.5) )
                    row.append(i+j*width)
                else:
                    row.append(None)
            self.terrain.append(row)
        
        for i, j in itertools.product(range(0, width), range(0, height)):
            p = self.terrain[j][i]
            if not p: continue
    
            if i < width-1:
                q = self.terrain[j][i+1]
                if q:
                    e = g.add_edge(p, q, weight = 1.0)
    
            if j < height-1:
                r = self.terrain[j+1][i]
                if r:
                    e = g.add_edge(p, r, weight = 1.0)
    
        self.graph = g



    def getNodeIndex(self, position):
        i = int(position.x)
        j = int(position.y)
        width = self.graph.graph["map_width"]
        return i+j*width
Пример #3
0
class AmbushCommander(Commander):
    """
        Display current state and predictions on the screen in a PyQT application.
    """
    MODE_VISIBILITY = 0
    MODE_TRAVELLING = 1

    def drawPreWorld(self, visualizer):
        furthest = max(
            [self.distances[n] for n in itertools.chain(*self.terrain) if n])
        brightest = max([
            self.visibilities.pixel(i, j)
            for i, j in itertools.product(range(88), range(50))
        ])

        # visible = QtGui.QImage(88, 50, QtGui.QImage.Format_ARGB32)
        # visible.fill(0)

        for i, j in itertools.product(range(88), range(50)):
            n = self.terrain[j][i]
            if n:
                if self.mode == self.MODE_TRAVELLING:
                    d = self.distances[n] * 255.0 / furthest
                if self.mode == self.MODE_VISIBILITY:
                    d = self.visibilities.pixel(i, j) * 255 / brightest
            else:
                d = 32
            visualizer.drawPixel((i, j), QtGui.qRgb(d, d, d))

    def drawPreBots(self, visualizer):
        for p, _ in self.ambushes:
            visualizer.drawCircle(p, QtGui.qRgb(255, 255, 0), 0.5)

    def keyPressed(self, e):
        if e.key() == QtCore.Qt.Key_Space:
            self.mode = 1 - self.mode

    def initialize(self):
        self.mode = self.MODE_VISIBILITY
        self.visualizer = VisualizerApplication(self)

        self.visualizer.setDrawHookPreWorld(self.drawPreWorld)
        self.visualizer.setDrawHookPreBots(self.drawPreBots)
        self.visualizer.setKeyboardHook(self.keyPressed)

        self.makeGraph()

        self.graph.add_node("enemy_base")
        start, finish = self.level.botSpawnAreas[self.game.enemyTeam.name]
        for i, j in itertools.product(range(int(start.x), int(finish.x)),
                                      range(int(start.y), int(finish.y))):
            self.graph.add_edge("enemy_base", self.terrain[j][i], weight=1.0)

        self.graph.add_node("base")
        start, finish = self.level.botSpawnAreas[self.game.team.name]
        for i, j in itertools.product(range(int(start.x), int(finish.x)),
                                      range(int(start.y), int(finish.y))):
            self.graph.add_edge("base", self.terrain[j][i], weight=1.0)

        self.node_EnemyFlagIndex = self.getNodeIndex(
            self.game.team.flag.position)
        self.node_EnemyScoreIndex = self.getNodeIndex(
            self.game.enemyTeam.flagScoreLocation)

        # self.node_Bases = self.graph.add_vertex()
        # e = self.graph.add_edge(self.node_Bases, self.node_MyBase)
        # e = self.graph.add_edge(self.node_Bases, self.node_EnemyBase)

        vb2f = nx.shortest_path(self.graph,
                                source="enemy_base",
                                target=self.node_EnemyFlagIndex)
        vf2s = nx.shortest_path(self.graph,
                                source=self.node_EnemyFlagIndex,
                                target=self.node_EnemyScoreIndex)
        #vb2s = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyScoreIndex)

        self.visibilities = QtGui.QImage(88, 50, QtGui.QImage.Format_ARGB32)
        self.visibilities.fill(0)
        path = vb2f + vf2s
        edgesinpath = zip(path[0:], path[1:])
        for vt, vf in edgesinpath[:-1]:
            if "position" not in self.graph.node[vf]:
                continue
            position = Vector2(*self.graph.node[vf]["position"])
            if "position" not in self.graph.node[vt]:
                continue
            next_position = Vector2(*self.graph.node[vt]["position"])
            if position == next_position:
                continue
            orientation = (next_position - position).normalized()

            def visible(p):
                delta = (p - position)
                l = delta.length()
                if l > 20.0:
                    return False
                if l < 2.5:
                    return True
                delta /= l
                return orientation.dotProduct(delta) >= 0.5

            cells = []
            w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1,
                     lambda x, y: cells.append((x, y)))
            w.compute(position)

            for x, y in [
                    c for c in cells
                    if visible(Vector2(c[0] + 0.5, c[1] + 0.5))
            ]:
                self.visibilities.setPixel(x, y,
                                           self.visibilities.pixel(x, y) + 1)

        starte, finishe = self.level.botSpawnAreas[self.game.enemyTeam.name]
        startf, finishf = self.level.botSpawnAreas[self.game.team.name]
        points = [
            self.game.team.flag.position, self.game.enemyTeam.flag.position,
            self.game.team.flagScoreLocation,
            self.game.enemyTeam.flagScoreLocation
        ] * 4
        for i, j in list(itertools.product(range(int(starte.x), int(finishe.x)), range(int(starte.y), int(finishe.y)))) \
                    + list(itertools.product(range(int(startf.x), int(finishf.x)), range(int(startf.y), int(finishf.y)))) \
                    + [(int(p.x), int(p.y)) for p in points]:
            n = self.terrain[j][i]
            if not n: continue

            position = Vector2(*self.graph.node[n]["position"])

            def visible(p):
                delta = (p - position)
                l = delta.length()
                return l <= 15.0

            cells = []
            w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1,
                     lambda x, y: cells.append((x, y)))
            w.compute(position)

            for x, y in [
                    c for c in cells
                    if visible(Vector2(c[0] + 0.5, c[1] + 0.5))
            ]:
                self.visibilities.setPixel(x, y,
                                           self.visibilities.pixel(x, y) + 1)

        self.node_EnemyBaseToFlagIndex = "enemy_base_to_flag"
        self.graph.add_node(self.node_EnemyBaseToFlagIndex)
        for vertex in vb2f:
            self.graph.add_edge(self.node_EnemyBaseToFlagIndex,
                                vertex,
                                weight=1.0)

        self.node_EnemyFlagToScoreIndex = "enemy_flag_to_score"
        self.graph.add_node(self.node_EnemyFlagToScoreIndex)
        for vertex in vf2s:
            self.graph.add_edge(self.node_EnemyFlagToScoreIndex,
                                vertex,
                                weight=1.0)

        self.node_EnemyBaseToScoreIndex = "enemy_base_to_score"
        self.graph.add_node(self.node_EnemyBaseToScoreIndex)
        # for vertex in vb2s:
        #     self.graph.add_edge(self.node_EnemyBaseToScoreIndex, vertex, weight = 1.0)

        ## node = self.makeNode(self.game.enemyTeam.flag.position)
        self.distances = nx.single_source_shortest_path_length(
            self.graph, self.node_EnemyFlagToScoreIndex)
        self.queue = {}
        self.index = 0
        print "Done with init. Calculating ambush spots"
        self.calculateAmbushes()

    def evaluate(self, position, orientation, callback):
        cells = []
        w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1,
                 lambda x, y: cells.append((x, y)))
        w.compute(position)

        def visible(p):
            delta = (p - position)
            l = delta.length()
            if l > 15.0:
                return False
            if l < 2.5:
                return True
            delta /= l
            return orientation.dotProduct(delta) > 0.9238

        total = 0.0
        for x, y in [
                c for c in cells if visible(Vector2(c[0] + 0.5, c[1] + 0.5))
        ]:
            total += callback(x, y)
        return total

    def findNearby(self, results, candidate, distance=2.0):
        d = distance * distance
        s, (position, _) = candidate
        for _, (p, _) in results:
            if (p - position).squaredLength() < d:
                return True
        return False

    def replaceInList(self, candidate, results, maximum=40):
        results.append(candidate)

        if len(results) < 50:
            return

        copy = results[:]
        copy.sort(key=lambda s: -s[0])

        results[:] = []

        for i, c in enumerate(copy):
            if not self.findNearby(results, c):
                results.append(c)
            if len(results) >= maximum:
                break

    def calculateAmbushes(self):
        results = []
        for i in range(
                500
        ):  # NOTE: you must feed in better pre-selected positions (eg near boxes) to get good results with this number of iterations.
            if (i % 1000) == 0: print >> sys.stderr, '.',
            p = self.level.findRandomFreePositionInBox(self.level.area)
            o = Vector2(random.uniform(-0.5, 0.5),
                        random.uniform(-0.5, 0.5)).normalized()

            s = self.evaluate(
                p, o,
                lambda x, y: 25.0 - square(self.getDistance(x, y))) - square(
                    self.visibilities.pixel(int(p.x), int(p.y)) * 5.0)
            self.replaceInList((s, (p, o)), results)

        self.ambushes = [r for _, r in results]

    def getSituation(self):
        result = None
        score = 0.0
        for i in range(10):
            p = self.level.findRandomFreePositionInBox(self.level.area)
            o = Vector2(random.uniform(-0.5, 0.5),
                        random.uniform(-0.5, 0.5)).normalized()
            s = self.evaluate(p, o, lambda x, y: 15.0 - self.getDistance(x, y))
            # - self.getDistance(int(p.x), int(p.y)) * 100
            if s > score or result == None:
                result = (p, o)
                score = s
        print score
        return result

    def getDistance(self, x, y):
        n = self.terrain[y][x]
        if n:
            return self.distances[n]
        else:
            return 0.0

    def tick(self):
        for e in self.game.match.combatEvents[self.index:]:
            if e.type != gameinfo.MatchCombatEvent.TYPE_RESPAWN:
                continue
            if e.subject in self.queue:
                del self.queue[e.subject]
        self.index = len(self.game.match.combatEvents)

        for bot in self.game.bots_available:
            if bot in self.queue:
                p, o = self.queue[bot]
                if (bot.position - p).length() < 1.0:
                    self.issue(commands.Defend, bot, o)
                    continue
            else:
                p, o = random.choice(self.ambushes)
                self.queue[bot] = (p, o)

            self.issue(commands.Charge, bot, p)

        self.visualizer.tick()

    def shutdown(self):
        self.visualizer.quit()
        del self.visualizer

    def makeGraph(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        g = nx.Graph(directed=False, map_height=height, map_width=width)
        #self.positions = g.new_vertex_property('vector<float>')
        #self.weights = g.new_edge_property('float')

        #g.vertex_properties['pos'] = self.positions
        #g.edge_properties['weight'] = self.weights

        self.terrain = []
        for j in range(0, height):
            row = []
            for i in range(0, width):
                if blocks[i][j] == 0:
                    g.add_node(i + j * width,
                               position=(float(i) + 0.5, float(j) + 0.5))
                    row.append(i + j * width)
                else:
                    row.append(None)
            self.terrain.append(row)

        for i, j in itertools.product(range(0, width), range(0, height)):
            p = self.terrain[j][i]
            if not p: continue

            if i < width - 1:
                q = self.terrain[j][i + 1]
                if q:
                    e = g.add_edge(p, q, weight=1.0)

            if j < height - 1:
                r = self.terrain[j + 1][i]
                if r:
                    e = g.add_edge(p, r, weight=1.0)

        self.graph = g

    def getNodeIndex(self, position):
        i = int(position.x)
        j = int(position.y)
        width = self.graph.graph["map_width"]
        return i + j * width
Пример #4
0
class SneakingCommander(Commander):

    def initialize(self):
        self.makeGraph()
        
        self.graph.add_node("enemy_base")
        self.positions["enemy_base"] = None
        start, finish = self.level.botSpawnAreas[self.game.enemyTeam.name]
        for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))):
            self.graph.add_edge("enemy_base", self.terrain[j][i], weight = 1.0)

        self.graph.add_node("base")
        self.positions["base"] = None
        start, finish = self.level.botSpawnAreas[self.game.team.name]
        for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))):
            self.graph.add_edge("base", self.terrain[j][i], weight = 1.0)

        self.node_EnemyFlagIndex = self.getNodeIndex(self.game.team.flag.position)
        self.node_EnemyScoreIndex = self.getNodeIndex(self.game.enemyTeam.flagScoreLocation)

        # self.node_Bases = self.graph.add_vertex()
        # e = self.graph.add_edge(self.node_Bases, self.node_MyBase)
        # e = self.graph.add_edge(self.node_Bases, self.node_EnemyBase)

        vb2f = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyFlagIndex)
        vf2s = nx.shortest_path(self.graph, source=self.node_EnemyFlagIndex, target=self.node_EnemyScoreIndex)
        #vb2s = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyScoreIndex)

        self.node_EnemyBaseToFlagIndex = "enemy_base_to_flag"
        self.graph.add_node(self.node_EnemyBaseToFlagIndex)
        self.positions["enemy_base_to_flag"] = None
        for vertex in vb2f:
            self.graph.add_edge(self.node_EnemyBaseToFlagIndex, vertex, weight = 1.0)
        
        self.node_EnemyFlagToScoreIndex = "enemy_flag_to_score" 
        self.graph.add_node(self.node_EnemyFlagToScoreIndex)
        self.positions["enemy_flag_to_score"] = None
        for vertex in vf2s:
            self.graph.add_edge(self.node_EnemyFlagToScoreIndex, vertex, weight = 1.0)
        
        self.node_EnemyBaseToScoreIndex = "enemy_base_to_score"
        self.graph.add_node(self.node_EnemyBaseToScoreIndex)
        self.positions["enemy_base_to_score"] = None
       # for vertex in vb2s:
       #     self.graph.add_edge(self.node_EnemyBaseToScoreIndex, vertex, weight = 1.0)

        ## node = self.makeNode(self.game.enemyTeam.flag.position)
        self.distances = nx.single_source_shortest_path_length(self.graph, self.node_EnemyFlagToScoreIndex)

        self.graph.remove_node("base")
        self.graph.remove_node("enemy_base")
        self.graph.remove_node(self.node_EnemyBaseToFlagIndex)
        self.graph.remove_node(self.node_EnemyFlagToScoreIndex)
        self.graph.remove_node(self.node_EnemyBaseToScoreIndex)

        self.updateEdgeWeights()

        self.paths = {b: None for b in self.game.team.members}

        self.visualizer = VisualizerApplication(self)
        self.visualizer.setDrawHookPreWorld(self.drawPreWorld)
        self.visualizer.setDrawHookPreBots(self.drawPreBots)
        self.visualizer.setDrawHookEnd(self.drawEnd)
        # self.visualizer.setKeyboardHook(self.keyboard)

    def getDistance(self, x, y):
        n = self.terrain[y][x]
        if n:
            return self.distances[n]
        else:
            return 0.0



    def shutdown(self):
        self.visualizer.quit()
        del self.visualizer


    def makeGraph(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        g = nx.Graph(directed=False, map_height = height, map_width = width)
        #self.positions = g.new_vertex_property('vector<float>')
        #self.weights = g.new_edge_property('float')
    
        #g.vertex_properties['pos'] = self.positions
        #g.edge_properties['weight'] = self.weights
    
        self.terrain = []
        self.positions = {}
        for j in range(0, height):
            row = []
            for i in range(0,width):
                if blocks[i][j] == 0:
                    g.add_node(i+j*width, position = (float(i)+0.5, float(j)+0.5) )
                    self.positions[i+j*width] = Vector2(float(i) + 0.5, float(j) + 0.5)
                    row.append(i+j*width)
                else:
                    row.append(None)
            self.terrain.append(row)
        
        for i, j in itertools.product(range(0, width), range(0, height)):
            p = self.terrain[j][i]
            if not p: continue
    
            if i < width-1:
                q = self.terrain[j][i+1]
                if q:
                    e = g.add_edge(p, q, weight = 1.0)
    
            if j < height-1:
                r = self.terrain[j+1][i]
                if r:
                    e = g.add_edge(p, r, weight = 1.0)
    
        self.graph = g

    def getNodeIndex(self, position):
        i = int(position.x)
        j = int(position.y)
        width = self.graph.graph["map_width"]
        return i+j*width


    def updateEdgeWeights(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        # update the weights in the graph based on the distance to the shortest path between the enemy flag and enemy score location

        for j in range(0, height):
            for i in range(0, width -1):
                a = self.terrain[j][i]
                b = self.terrain[j][i+1]
                if a and b:
                    w = max(255 - 4*(self.distances[a] + self.distances[b]), 0)
                    self.graph[a][b]['weight'] = w

        for j in range(0, height-1):
            for i in range(0, width):
                a = self.terrain[j][i]
                b = self.terrain[j+1][i]
                if a and b:
                    w = max(255 - 4*(self.distances[a] + self.distances[b]), 0)
                    self.graph[a][b]['weight'] = w


    def tick(self):
        for bot in self.game.bots_alive:
            if bot.state == BotInfo.STATE_IDLE:
                if not bot.flag:
                    # go to flag
                    dst = self.game.enemyTeam.flag.position
                    message = 'go to flag'
                else:
                    # go home
                    dst = self.game.team.flagScoreLocation
                    message = 'go home'

                # calculate the shortest path between the bot and the target using our weights
                srcIndex = self.getNodeIndex(bot.position)
                dstIndex = self.getNodeIndex(dst)
                pathNodes = nx.shortest_path(self.graph, srcIndex, dstIndex, 'weight')

                pathLength = len(pathNodes)
                if pathLength > 0:
                    path = [self.positions[p] for p in pathNodes if self.positions[p]]
                    if len(path) > 0:
                        orderPath = path[::10]
                        orderPath.append(path[-1]) # take every 10th point including last point
                        self.issue(commands.Move, bot, orderPath, description = message) 
                        self.paths[bot] = path    # store the path for visualization

        self.visualizer.tick()

    def drawPreWorld(self, visualizer):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        furthest = max([self.distances[n] for n in itertools.chain(*self.terrain) if n])

        for i, j in itertools.product(range(width), range(height)):            
            # average weights of edges connected to this node
            sum, count = 0, 0
            node = self.terrain[j][i]
            if node:
                for offset in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                    ni, nj = i + offset[0], j + offset[1]
                    if ni < 0 or ni >= width or nj < 0 or nj >= height:
                        continue
                    neighbour = self.terrain[nj][ni]
                    if neighbour:
                        sum, count = sum + self.graph[node][neighbour]['weight'], count + 1
            if count:
                d = sum / count
            else:
                d = 32

            if self.level.blockHeights[i][j] == 1:
                visualizer.drawPixel((i, j), QtGui.qRgb(196, 196, 196))
            elif self.level.blockHeights[i][j] >= 2:            
                visualizer.drawPixel((i, j), QtGui.qRgb(64, 64, 64))
            else:
                visualizer.drawPixel((i, j), QtGui.qRgb(d,d,d))
                

    def drawPreBots(self, visualizer):
        for name, bot in self.game.bots.items():
            if bot.position is None:
                continue
            
            if 'Red' in name:
                color = QtGui.qRgb(255,0,0)
                pathColor = QtGui.qRgb(127,0,0)
            else:
                color = QtGui.qRgb(0,0,255)
                pathColor = QtGui.qRgb(0,0,127)
                
            if bot.health <= 0.0:
                color = QtGui.qRgb(0,0,0)

            if (bot.health > 0) and (bot in self.paths) and self.paths[bot]:
                path = self.paths[bot]
                pLast = bot.position
                for p in path:
                    visualizer.drawPixel((int(p.x), int(p.y)), QtGui.qRgb(255,255,0))
                    # visualizer.drawRay(pLast, p, color)
                    pLast = p

    def drawEnd(self, visualizer):
        pass
Пример #5
0
class AmbushCommander(Commander):
    """
        Display current state and predictions on the screen in a PyQT application.
    """
    MODE_VISIBILITY = 0 
    MODE_TRAVELLING = 1
    
    LEFTUP = 0
    LEFTDOWN = 1
    RIGHTUP = 2
    RIGHTDOWN = 3
    TOPLEFT = 4
    TOPRIGHT = 5
    BOTTOMLEFT = 6
    BOTTOMRIGHT = 7
    
    def angledVector(self, vec, angle):
        normalAngle = angle + math.atan2(vec.y, vec.x)
        return Vector2(math.cos(normalAngle), math.sin(normalAngle))
    
    def feq(self, f, s):
        return math.fabs(f - s) < 0.00000001
    
    def veq(self, f, s):
        return self.feq(f.x, s.x) and self.feq(f.y, s.y)
    
    def lineEq(self, start, end, x, y):
        return (end.y - start.y) * x + (start.x - end.x) * y + end.x * start.y - start.x * end.y
    
    def intersects(self, start, end, p, length = 0):
        if length is 0:
            length = start.distance(end)
        if p.distance(start) <= length and p.distance(end) <= length:
            topLeft = self.lineEq(start, end, p.x, p.y)
            topRight = self.lineEq(start, end, p.x + 1, p.y)
            bottomRight = self.lineEq(start, end, p.x + 1, p.y + 1)
            bottomLeft = self.lineEq(start, end, p.x, p.y + 1)
            if self.feq(topLeft, 0) or self.feq(topRight, 0) or self.feq(bottomRight, 0) or self.feq(bottomLeft, 0) or not ((topLeft > 0) is (topRight > 0) is (bottomRight > 0) is (bottomLeft > 0)):
                return True
        return False
    
    def lineIntersection(self, start1, end1, start2, end2):
        denom = ((end1.x - start1.x) * (end2.y - start2.y)) - ((end1.y - start1.y) * (end2.x - start2.x))
 
        if denom is 0:
            return None

        numer = ((start1.y - start2.y) * (end2.x - start2.x)) - ((start1.x - start2.x) * (end2.y - start2.y));
    
        r = numer / denom;
    
        numer2 = ((start1.y - start2.y) * (end1.x - start1.x)) - ((start1.x - start2.x) * (end1.y - start1.y));
    
        s = numer2 / denom;
    
        if r < 0 or r > 1 or s < 0 or s > 1:
            return None
        
        return Vector2(start1.x + (r * (end1.x - start1.x)), start1.y + (r * (end1.y - start1.y)))

    def intersectsWhere(self, start, end, p):
        intersections = []
        intersection = self.lineIntersection(start, end, p, Vector2(p.x + 1, p.y))
        if intersection:
            intersections.append(intersection)
        intersection = self.lineIntersection(start, end, p, Vector2(p.x, p.y + 1))
        if intersection:
            intersections.append(intersection)
        intersection = self.lineIntersection(start, end, Vector2(p.x + 1, p.y), Vector2(p.x + 1, p.y + 1))
        if intersection:
            intersections.append(intersection)
        intersection = self.lineIntersection(start, end, Vector2(p.x, p.y + 1), Vector2(p.x + 1, p.y + 1))
        if intersection:
            intersections.append(intersection)
        
        if not intersections:
            return None
        else:
            return sorted(intersections, key = lambda f: f.distance(start))[0]
    
    def whoBlocks(self, blocked, start, end, length = 0):
        for p in blocked:
            if self.intersects(start, end, p, length):
                return p
        return None
    
    def whoBlocksWhere(self, blocked, start, end):
        for p in blocked:
            intersection = self.intersectsWhere(start, end, p)
            if intersection:
                return intersection
        return None
    
    def freeLoS(self, blocked, start, end):
        return not self.whoBlocks(blocked, start, end)
                        
    def recurseNeighbours(self, x, y, visited):
        if x >= 0 and x < self.level.width and y >= 0 and y < self.level.height:
            if self.level.blockHeights[x][y] < 2:
                return False, set(), set()
            elif not Vector2(x, y) in visited:
                visited.append(Vector2(x, y))
                nEdges, island = set(), set()
                topLeft, topRight, bottomLeft, bottomRight, top, left, right, bottom = True, True, True, True, True, True, True, True
                for i in range(-1, 2):
                    for j in range(-1, 2):
                        if not (i is 0 and j is 0):
                            isBlocked, neighbourRes, islandRes = self.recurseNeighbours(x + i, y + j, visited)
                            nEdges |= neighbourRes
                            island |= islandRes
                            if isBlocked:
                                if i is -1:
                                    if j is 0:
                                        topLeft, bottomLeft, left = False, False, False
                                    elif j is -1:
                                        topLeft = False
                                    else:
                                        bottomLeft = False
                                elif i is 0:
                                    if j is -1:
                                        topLeft, topRight, top = False, False, False
                                    else:
                                        bottomLeft, bottomRight, bottom = False, False, False
                                else:
                                    if j is 0:
                                        topRight, bottomRight, right = False, False, False
                                    elif j is -1:
                                        topRight = False
                                    else:
                                        bottomRight = False
                    
                if topLeft:
                    if x - 0.25 > 0 and y + 1 < self.level.height:
                        nEdges.add((Vector2(x - 0.25, y + 1), self.LEFTUP))
                    if x + 1 < self.level.width and y - 0.25 > 0:
                        nEdges.add((Vector2(x + 1, y - 0.25), self.TOPLEFT))
                if bottomLeft:
                    if x - 0.25 > 0:
                        nEdges.add((Vector2(x - 0.25, y), self.LEFTDOWN))
                    if x + 1 < self.level.width and y + 1.25 < self.level.height:
                        nEdges.add((Vector2(x + 1, y + 1.25), self.BOTTOMLEFT))
                if topRight:
                    if x + 1.25 < self.level.width and y + 1 < self.level.height:
                        nEdges.add((Vector2(x + 1.25, y + 1), self.RIGHTUP))
                    if y - 0.25 > 0:
                        nEdges.add((Vector2(x, y - 0.25), self.TOPRIGHT))
                if bottomRight:
                    if x + 1.25 < self.level.width:
                        nEdges.add((Vector2(x + 1.25, y), self.RIGHTDOWN))
                    if y + 1.25 < self.level.height:
                        nEdges.add((Vector2(x, y + 1.25), self.BOTTOMRIGHT))
                    
                if top or bottom or right or left:
                    island.add(Vector2(x, y))
                            
                return True, nEdges, island
            else:
                return True, set(), set()
        else:
            return True, set(), set()
                        
    def recursePaths(self, p, blocked, deadlines, visited = [], pointsAndLinesByEdge = dict()):
        if p.x >= 0 and p.y >= 0 and p.x < self.level.width and p.y < self.level.height and not p in visited:
            visited.append(p)
            for block in blocked:
                if p.x >= block.x and p.x <= block.x + 1 and p.y >= block.y and p.y <= block.y + 1:
                    return
            for edge, contacts in deadlines.iteritems():
                for contact in contacts:
                    """line = (edge, contact)
                    if p.distance(line[0]) <= line[0].distance(line[1]) and p.distance(line[1]) <= line[0].distance(line[1]) and not (self.veq(line[0], p) or self.veq(line[1], p)):
                        topLeft = self.lineEq(line, p.x, p.y)
                        topRight = self.lineEq(line, p.x + 1, p.y)
                        bottomRight = self.lineEq(line, p.x + 1, p.y + 1)
                        bottomLeft = self.lineEq(line, p.x, p.y + 1)
                        if self.feq(topLeft, 0) or self.feq(topRight, 0) or self.feq(bottomRight, 0) or self.feq(bottomLeft, 0) or not ((topLeft > 0) is (topRight > 0) is (bottomRight > 0) is (bottomLeft > 0)):"""
                    if self.intersects(edge, contact, p):
                        if edge in pointsAndLinesByEdge:
                            pointsAndLinesByEdge[edge].append((p, contact))
                        else:
                            pointsAndLinesByEdge[edge] = [(p, contact)]
                        return
            recalc= []
            for edge in deadlines.keys():
                if p.distance(edge) <= self.level.firingDistance and not self.whoBlocks(blocked, p, edge):
                    sys.stdout.write('removed: ' + str(p) + ' '  + str(edge) + '\n')
                    del deadlines[edge]
                    if edge in pointsAndLinesByEdge:
                        for pointAndLine in pointsAndLinesByEdge[edge]:
                            recalc.append(pointAndLine[0])
                            visited.remove(pointAndLine[0])
                        del pointsAndLinesByEdge[edge]
            for re in recalc:
                self.recursePaths(re, blocked, deadlines, visited, pointsAndLinesByEdge)
                    
            
            
            self.recursePaths(Vector2(p.x - 1, p.y), blocked, deadlines, visited, pointsAndLinesByEdge)
            self.recursePaths(Vector2(p.x, p.y - 1), blocked, deadlines, visited, pointsAndLinesByEdge)
            self.recursePaths(Vector2(p.x + 1, p.y), blocked, deadlines, visited, pointsAndLinesByEdge)
            self.recursePaths(Vector2(p.x, p.y + 1), blocked, deadlines, visited, pointsAndLinesByEdge)
                        
    def newDeadline(self, edge, contact):
        if edge in self.deadlines:
            self.deadlines[edge].add(contact)
        else:
            self.deadlines[edge] = set([contact])
            
    def deadlineFromLine(self, blocked, spawn, start, end):
        intersect = self.whoBlocksWhere(blocked, start, end)
        spawnIntersect = self.whoBlocks(spawn, start, end)
        if intersect and (not spawnIntersect or spawnIntersect.distance(start) > intersect.distance(start)):
            self.newDeadline(start, intersect)
        else:
            intersect = self.lineIntersection(start, end, Vector2(0, 0), Vector2(0, self.level.height))
            if intersect and (not spawnIntersect or spawnIntersect.distance(start) > intersect.distance(start)):
                self.newDeadline(start, intersect)
            else:
                intersect = self.lineIntersection(start, end, Vector2(0, 0), Vector2(self.level.width, 0))
                if intersect and (not spawnIntersect or spawnIntersect.distance(start) > intersect.distance(start)):
                    self.newDeadline(start, intersect)
                else:
                    intersect = self.lineIntersection(start, end, Vector2(0, self.level.height), Vector2(self.level.width, self.level.height))
                    if intersect and (not spawnIntersect or spawnIntersect.distance(start) > intersect.distance(start)):
                        self.newDeadline(start, intersect)
                    else:
                        intersect = self.lineIntersection(start, end, Vector2(self.level.width, 0), Vector2(self.level.width, self.level.height))
                        if intersect and (not spawnIntersect or spawnIntersect.distance(start) > intersect.distance(start)):
                            self.newDeadline(start, intersect)
    
    def drawPreWorld(self, visualizer):
       furthest = max([self.distances[n] for n in itertools.chain(*self.terrain) if n])
       brightest = max([self.visibilities.pixel(i,j) for i, j in itertools.product(range(88), range(50))])
        
        # visible = QtGui.QImage(88, 50, QtGui.QImage.Format_ARGB32)
        # visible.fill(0)

       for i, j in itertools.product(range(88), range(50)):            
            n = self.terrain[j][i]
            if n:
                if self.mode == self.MODE_TRAVELLING:
                    d = self.distances[n] * 255.0 / furthest
                if self.mode == self.MODE_VISIBILITY:
                    d = self.visibilities.pixel(i,j) * 255 / brightest
            else:                
                d = 32
            visualizer.drawPixel((i, j), QtGui.qRgb(d,d,d))
                
    def drawPreBots(self, visualizer):
        for p, o in self.ambushes:
            visualizer.drawCircle(p, QtGui.qRgb(255,255,0), 0.5)
            visualizer.drawRay(p, o, QtGui.qRgb(255,0,0))
        for island in self.islandEdges:
            for p, _ in island:
                visualizer.drawCircle(p, QtGui.qRgb(255,0,0), 0.5)
            
    def keyPressed(self, e):
        if e.key() == QtCore.Qt.Key_Space:
            self.mode = 1 - self.mode

    def initialize(self):
        self.midEnemySpawn = self.game.enemyTeam.botSpawnArea[0].midPoint(self.game.enemyTeam.botSpawnArea[1])
        visited, self.islandEdges, islandOuter = [], [], []
        for x in range(0, len(self.level.blockHeights)):
            for y in range(0, len(self.level.blockHeights[x])):
                _, edges, island = self.recurseNeighbours(x, y, visited)
                if edges:
                    self.islandEdges.append(edges)
                    islandOuter.append(island)
        blocked = [item for sublist in islandOuter for item in sublist]
        #blockedOrSpawn = blocked[:]
        spawn = []
        for x in range(int(self.game.enemyTeam.botSpawnArea[0].x), int(self.game.enemyTeam.botSpawnArea[1].x)):
            for y in range(int(self.game.enemyTeam.botSpawnArea[0].y), int(self.game.enemyTeam.botSpawnArea[1].y)):
                spawn.append(Vector2(x, y))
        
        self.campLines = []
        for island in self.islandEdges:
            for coord, orientation in island:
                if orientation is self.TOPLEFT:
                    self.campLines.append((coord, Vector2(-self.level.firingDistance / 1.0283968, 0.24 * self.level.firingDistance / 1.0283968)))
                elif orientation is self.BOTTOMLEFT:
                    self.campLines.append((coord, Vector2(-self.level.firingDistance / -1.0283968, -0.24 * self.level.firingDistance / 1.0283968)))
                elif orientation is self.LEFTUP:
                    self.campLines.append((coord, Vector2(0.24 * self.level.firingDistance / 1.0283968, -self.level.firingDistance / 1.0283968)))
                elif orientation is self.RIGHTUP:
                    self.campLines.append((coord, Vector2(-0.24 * self.level.firingDistance / 1.0283968, -self.level.firingDistance / 1.0283968)))
                elif orientation is self.TOPRIGHT:
                    self.campLines.append((coord, Vector2(self.level.firingDistance / 1.0283968, 0.24 * self.level.firingDistance / 1.0283968)))
                elif orientation is self.BOTTOMRIGHT:
                    self.campLines.append((coord, Vector2(self.level.firingDistance / 1.0283968, -0.24 * self.level.firingDistance / 1.0283968)))
                elif orientation is self.LEFTDOWN:
                    self.campLines.append((coord, Vector2(0.24 * self.level.firingDistance / 1.0283968, self.level.firingDistance / 1.0283968)))
                elif orientation is self.RIGHTDOWN:
                    self.campLines.append((coord, Vector2(-0.24 * self.level.firingDistance / 1.0283968, self.level.firingDistance / 1.0283968)))
        sys.stdout.write(str(self.campLines) + '\n')
        self.deadlines = dict()
        for i in range(len(self.islandEdges)):
            for coord, orientation in self.islandEdges[i]:
                if orientation is self.TOPLEFT:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x - self.level.firingDistance / 1.0283968, coord.y + 0.24 * self.level.firingDistance / 1.0283968))
                elif orientation is self.BOTTOMLEFT:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x - self.level.firingDistance / -1.0283968, coord.y - 0.24 * self.level.firingDistance / 1.0283968))
                elif orientation is self.LEFTUP:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x + 0.24 * self.level.firingDistance / 1.0283968, coord.y - self.level.firingDistance / 1.0283968))
                elif orientation is self.RIGHTUP:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x - 0.24 * self.level.firingDistance / 1.0283968, coord.y - self.level.firingDistance / 1.0283968))
                elif orientation is self.TOPRIGHT:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x + self.level.firingDistance / 1.0283968, coord.y + 0.24 * self.level.firingDistance / 1.0283968))
                elif orientation is self.BOTTOMRIGHT:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x + self.level.firingDistance / 1.0283968, coord.y - 0.24 * self.level.firingDistance / 1.0283968))
                elif orientation is self.LEFTDOWN:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x + 0.24 * self.level.firingDistance / 1.0283968, coord.y + self.level.firingDistance / 1.0283968))
                elif orientation is self.RIGHTDOWN:
                    self.deadlineFromLine(blocked, spawn, coord, Vector2(coord.x - 0.24 * self.level.firingDistance / 1.0283968, coord.y + self.level.firingDistance / 1.0283968))
                
        sys.stdout.write(str(self.deadlines) + '\n')
        pointsAndLinesByEdge = dict()
        try:
            self.recursePaths(self.midEnemySpawn, blocked, self.deadlines, [], pointsAndLinesByEdge)
        except RuntimeError as e:
            sys.stdout.write(str(e) + '\n')
        self.spawnCamplines = set()
        for edge, pls in pointsAndLinesByEdge.iteritems():
            for _, contact in pls:
                self.spawnCamplines.add((self.level.findNearestFreePosition(edge), contact))
        sys.stdout.write('\n' + str(self.spawnCamplines))
        
        self.spawnCampers = []
        for cl in self.spawnCamplines:
            self.spawnCampers.append([[], cl])
        
        self.mode = self.MODE_VISIBILITY
        self.visualizer = VisualizerApplication(self)

        self.visualizer.setDrawHookPreWorld(self.drawPreWorld)
        self.visualizer.setDrawHookPreBots(self.drawPreBots)
        self.visualizer.setKeyboardHook(self.keyPressed)

        self.makeGraph()
        
        self.graph.add_node("enemy_base")
        start, finish = self.level.botSpawnAreas[self.game.enemyTeam.name]        
        for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))):
            self.graph.add_edge("enemy_base", self.terrain[j][i], weight = 1.0)            


        self.graph.add_node("base")
        start, finish = self.level.botSpawnAreas[self.game.team.name]        
        for i, j in itertools.product(range(int(start.x), int(finish.x)), range(int(start.y), int(finish.y))):
            self.graph.add_edge("base", self.terrain[j][i],weight = 1.0)            


        self.node_EnemyFlagIndex = self.getNodeIndex(self.game.team.flag.position)
        self.node_EnemyScoreIndex = self.getNodeIndex(self.game.enemyTeam.flagScoreLocation)

        # self.node_Bases = self.graph.add_vertex()
        # e = self.graph.add_edge(self.node_Bases, self.node_MyBase)
        # e = self.graph.add_edge(self.node_Bases, self.node_EnemyBase)

        vb2f = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyFlagIndex)
        vf2s = nx.shortest_path(self.graph, source=self.node_EnemyFlagIndex, target=self.node_EnemyScoreIndex)
        #vb2s = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyScoreIndex)

        self.visibilities = QtGui.QImage(88, 50, QtGui.QImage.Format_ARGB32)
        self.visibilities.fill(0)
        path = vb2f+vf2s
        #path = vb2f = nx.shortest_path(self.graph, source="enemy_base", target=self.node_EnemyFlagIndex)
        edgesinpath=zip(path[0:],path[1:])        
        for vt, vf in edgesinpath[:-1]:
            if "position" not in self.graph.node[vf]:
                continue
            position = Vector2(*self.graph.node[vf]["position"])
            if "position" not in self.graph.node[vt]:
                continue
            next_position = Vector2(*self.graph.node[vt]["position"])
            if position == next_position:
                continue
            orientation = (next_position - position).normalized()

            def visible(p):
                delta = (p-position)
                l = delta.length()
                if l > 20.0:
                    return False
                if l < 2.5:
                    return True
                delta /= l
                return orientation.dotProduct(delta) >= 0.5

            cells = []
            w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y)))
            w.compute(position)

            for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]:
                self.visibilities.setPixel(x, y, self.visibilities.pixel(x, y)+1)

        starte, finishe = self.level.botSpawnAreas[self.game.enemyTeam.name]
        startf, finishf = self.level.botSpawnAreas[self.game.team.name]
        points = [self.game.team.flag.position, self.game.enemyTeam.flag.position,
                  self.game.team.flagScoreLocation, self.game.enemyTeam.flagScoreLocation] * 4
        for i, j in list(itertools.product(range(int(starte.x), int(finishe.x)), range(int(starte.y), int(finishe.y)))) \
                    + list(itertools.product(range(int(startf.x), int(finishf.x)), range(int(startf.y), int(finishf.y)))) \
                    + [(int(p.x), int(p.y)) for p in points]:
            n = self.terrain[j][i]
            if not n: continue
            
            position = Vector2(*self.graph.node[n]["position"])
            def visible(p):
                delta = (p-position)
                l = delta.length()
                return l <= 15.0

            cells = []
            w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y)))
            w.compute(position)

            for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]:
                self.visibilities.setPixel(x, y, self.visibilities.pixel(x, y)+1)


        self.node_EnemyBaseToFlagIndex = "enemy_base_to_flag"
        self.graph.add_node(self.node_EnemyBaseToFlagIndex)
        for vertex in vb2f:
            self.graph.add_edge(self.node_EnemyBaseToFlagIndex, vertex, weight = 1.0)
        
        self.node_EnemyFlagToScoreIndex = "enemy_flag_to_score" 
        self.graph.add_node(self.node_EnemyFlagToScoreIndex)
        for vertex in vf2s:
            self.graph.add_edge(self.node_EnemyFlagToScoreIndex, vertex, weight = 1.0)
        
        self.node_EnemyBaseToScoreIndex = "enemy_base_to_score"
        self.graph.add_node(self.node_EnemyBaseToScoreIndex)
       # for vertex in vb2s:
       #     self.graph.add_edge(self.node_EnemyBaseToScoreIndex, vertex, weight = 1.0)

        ## node = self.makeNode(self.game.enemyTeam.flag.position)"""
        self.distances = nx.single_source_shortest_path_length(self.graph, self.node_EnemyFlagToScoreIndex)
        #self.distances = nx.single_source_shortest_path_length(self.graph, self.node_EnemyBaseToFlagIndex)
        self.queue = {}
        self.index = 0
        print "Done with init. Calculating ambush spots"
        self.calculateAmbushes(self.campLines)
        self.aliveEnemies = 0

    def evaluate(self, position, orientation, callback):
        cells = []
        w = Wave((88, 50), lambda x, y: self.level.blockHeights[x][y] > 1, lambda x, y: cells.append((x,y)))
        w.compute(position)

        def visible(p):
            delta = (p-position)
            l = delta.length()
            if l > 15.0:
                return False
            if l < 2.5:
                return True
            delta /= l
            return orientation.dotProduct(delta) > 0.9238

        total = 0.0
        for x, y in [c for c in cells if visible(Vector2(c[0]+0.5, c[1]+0.5))]:
            total += callback(x,y)
        return total

    def findNearby(self, results, candidate, distance = 2.0):
        d = distance * distance
        s, (position, _) = candidate
        for _, (p, _) in results:
            if (p-position).squaredLength() < d:
                return True            
        return False

    def replaceInList(self, candidate, results, maximum = 40):
        results.append(candidate)

        if len(results) < 50:
            return

        copy = results[:]
        copy.sort(key=lambda s: -s[0])

        results[:] = []

        for i, c in enumerate(copy):
            if not self.findNearby(results, c):
                results.append(c)
            if len(results) >= maximum:
                break

    def calculateAmbushes(self, camps):        
        results = []
        for q, _ in camps:
            p = self.level.findNearestFreePosition(q)
            for i in range(10):
                o = self.angledVector(Vector2(1, 0), i * 36 * math.pi / 180)
                #o = Vector2(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5)).normalized()
    
                s = self.evaluate(p, o, lambda x, y: 25.0-square(self.getDistance(x, y))) - square(self.visibilities.pixel(int(p.x), int(p.y)) * 5.0)
                #s = self.evaluate(p, o, lambda x, y: - self.getDistance(x, y) - self.visibilities.pixel(int(p.x), int(p.y)))
                self.replaceInList((s, (p,o)), results)

        self.ambushes = [r for _, r in results]

    def getSituation(self):
        result = None
        score = 0.0
        for i in range(10):
            p = self.level.findRandomFreePositionInBox(self.level.area)
            o = Vector2(random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5)).normalized()
            s = self.evaluate(p, o, lambda x, y: 15.0-self.getDistance(x, y))
                # - self.getDistance(int(p.x), int(p.y)) * 100 
            if s > score or result == None:
                result = (p, o)
                score = s
        print score
        return result

    def getDistance(self, x, y):
        n = self.terrain[y][x]
        if n:
            return self.distances[n]
        else:
            return 0.0

    def tick(self):
        for e in self.game.match.combatEvents[self.index:]:
            if e.type == gameinfo.MatchCombatEvent.TYPE_RESPAWN:
                if e.subject in self.queue:
                    del self.queue[e.subject]
                elif e.subject in self.game.enemyTeam.members:
                    self.aliveEnemies += 1
                    sys.stdout.write(str(self.aliveEnemies) + '\n')
            elif e.type == gameinfo.MatchCombatEvent.TYPE_KILLED and e.subject in self.game.enemyTeam.members:
                self.aliveEnemies -= 1
                sys.stdout.write(str(self.aliveEnemies) + '\n')
        self.index = len(self.game.match.combatEvents)

        for c in self.spawnCampers:
            for derp in c[0][:]:
                if derp[0].health <= 0:
                    c[0].remove(derp)

        if self.aliveEnemies == 0 and self.game.match.timeToNextRespawn > 5:
            for bot in self.game.bots_alive:
                if bot.flag:
                    self.issue(commands.Charge, bot, self.game.team.flagScoreLocation, description = 'straight home')
                else:
                    handled = False
                    for c in self.spawnCampers:
                        for b in c[0]:
                            if bot is b[0]:
                                if not b[1]:
                                    if bot.position.distance(c[1][0]) < 1:
                                        self.issue(commands.Defend, bot, c[1][1] - bot.position)
                                        b[1] = True
                                    else:
                                        self.issue(commands.Charge, bot, c[1][0])
                                handled = True
                                break
                        if handled:
                            break
                    if not handled:
                        myplace = sorted(self.spawnCampers, key = lambda f: len(f[0]))[0]
                        myplace[0].append([bot, False])      
                        self.issue(commands.Charge, bot, myplace[1][0])
        else:
            for bot in self.game.bots_available:
                if bot in self.queue:
                    p, o = self.queue[bot]
                    if (bot.position-p).length() < 1.0:
                        self.issue(commands.Defend, bot, o)
                        continue
                else:
                    p, o = random.choice(self.ambushes)
                    self.queue[bot] = (p, o)
                
                self.issue(commands.Charge, bot, p)
        
        self.visualizer.tick()

    def shutdown(self):
        self.visualizer.quit()
        del self.visualizer

    def makeGraph(self):
        blocks = self.level.blockHeights
        width, height = len(blocks), len(blocks[0])

        g = nx.Graph(directed=False, map_height = height, map_width = width)
        #self.positions = g.new_vertex_property('vector<float>')
        #self.weights = g.new_edge_property('float')
    
        #g.vertex_properties['pos'] = self.positions
        #g.edge_properties['weight'] = self.weights
    
        self.terrain = []
        for j in range(0, height):
            row = []
            for i in range(0,width):
                if blocks[i][j] == 0:
                    g.add_node(i+j*width, position = (float(i)+0.5, float(j)+0.5) )
                    row.append(i+j*width)
                else:
                    row.append(None)
            self.terrain.append(row)
        
        for i, j in itertools.product(range(0, width), range(0, height)):
            p = self.terrain[j][i]
            if not p: continue
    
            if i < width-1:
                q = self.terrain[j][i+1]
                if q:
                    e = g.add_edge(p, q, weight = 1.0)
    
            if j < height-1:
                r = self.terrain[j+1][i]
                if r:
                    e = g.add_edge(p, r, weight = 1.0)
    
        self.graph = g



    def getNodeIndex(self, position):
        i = int(position.x)
        j = int(position.y)
        width = self.graph.graph["map_width"]
        return i+j*width