Beispiel #1
0
class Bot(object):
    def __init__(self):
        self.name = ""
        self.map = Map()
        self.start_armies = 0
        self.opponent_name = ""

    """
    Updates each super region with the number of remaining
    regions in them that are left to capture
    """
    def update_super_regions(self):
        for super_region in self.map.super_regions.values():
            super_region.remaining_regions = 0
            for region in super_region.children:
                if region.occupant != self.name:
                    super_region.remaining_regions += 1


    """
    Tries and group picks into the same super region
    Consider evaluating the distances between all picks as well
    """
    def start_pick(self,regions):
        count = {}
        picks = {}
        picks_left = 6
        #self.map.weight_super_regions()
        for region in regions:
            super_region = self.map.regions[region].super_region
            if not super_region in count:
                count[super_region] = 0
                picks[super_region] = []
            count[super_region] +=  super_region.bonus
            picks[super_region].append(region)
        outStr = ""
        for w in sorted(count,key=count.get):
            #print(w.id,count[w])
            for reg in picks[w]:
                outStr += reg + " "
                picks_left -= 1
                if picks_left == 0:
                    break
            #for loop will normally trigger else
            #if break gets called in the inner loop
            #it will skip the else
            else:
                continue
            break
        print (outStr)

    """
    Calls the map function to 'score' each region
    Keeps the top 6 and recalculates after each placement
    """
    def place_armies(self,armies):
        ranks = {}
        top_ranks = {}
        outStr = ""

        for region_id in self.map.visible_regions:
            region = self.map.regions[region_id]
            if region.occupant == self.name:
                ranks[region] = self.map.get_placement_score(region,self.name,self.opponent_name)
        #get the top 6 picks
        count = 0
        for region in sorted(ranks,key=ranks.get,reverse=True):
            top_ranks[region] = ranks[region]
            count += 1
            if count >= 6:
                break

        while armies > 0:
            for region in sorted(top_ranks,key=top_ranks.get,reverse=True):
                outStr += self.name + " place_armies " + str(region.id)
                outStr += " " + str(1) +","
                region.armies += 1
                break
            #reevaluate
            #for region in top_ranks:
            #    top_ranks[region] = self.map.get_placement_score(region,self.name,self.opponent_name)
            armies -= 1

        if outStr == "":
            print ("ERROR: unplaced armies" , file=sys.stderr)
            outStr += "No moves"
        print (outStr)




        """
        threat = {}
        armies_left = armies
        regions = self.map.regions
        outStr = ""
        SAFETY_FACTOR = 1.5
        MIN_ARMIES = 1
        for region_id in self.map.visible_regions:
            if regions[region_id].occupant ==  self.name:
                for neighbor in regions[region_id].neighbors:
                    if neighbor.occupant == self.opponent_name:
                        if not region_id in threat:
                            threat[region_id] = 0
                        threat[region_id] += int(neighbor.armies)
        for region_id in sorted(threat,key=threat.get,reverse=True):
            if not armies_left:
                break
            if threat[region_id] > regions[region_id].armies * SAFETY_FACTOR/2:
                outStr += self.name + " place_armies " + str(region_id)
                placed_count = 0
                while armies_left > 0:
                    placed_count += 1
                    armies_left -= 1
                outStr += " " + str(placed_count) + ","

        for region_id in self.map.visible_regions:
            if armies_left  <= MIN_ARMIES:
                break
            if regions[region_id].occupant == self.name:
                for neighbor in regions[region_id].neighbors:
                    if armies_left  < 2:
                        break
                    if neighbor.occupant == 'neutral':
                        armies_left -= 1
                        outStr += self.name + " place_armies " + str(region_id)
                        outStr += " " + str(1) +","
        #If we are here, all regions are taken
        #Reinforice the area closest to the strongest enemy
        #region
        if outStr == "":
            for region_id in sorted(threat,key=threat.get,reverse=True):
                outStr += self.name + " place_armies " + str(region_id)
                outStr += " " + str(armies) + ","
                break
        """
    """
        #Scan through all visible regions belonging to us
        #Attack the neighbor with the highest amount of enemy units
        #But only if we have more units
        #If we have no enemy neighbors
        #Scout out surrounding locations
        FIXME Optimize these loops so that the only
        access our own stored locations
    """
    def attack(self):
        regions = self.map.regions
        outStr = ""
        SAFETY_FACTOR = 1.5
        SCOUT_FORCE = 4
        for region_id in self.map.visible_regions:
            if regions[region_id].occupant ==  self.name:
                target = None
                to_scout = []
                safe_region = True
                for neighbor in regions[region_id].neighbors:
                    if neighbor.occupant == self.opponent_name:
                        safe_region = False
                        if target == None or neighbor.armies > target.armies:
                            target = neighbor
                    elif neighbor.occupant == 'neutral':
                        safe_region = False
                        to_scout.append(neighbor)
###################ATTACK ADJACENT ARMIES###############################################
                if target and target.armies * SAFETY_FACTOR < regions[region_id].armies:
                    outStr += (self.name + " attack/transfer " + region_id + " "
                            + target.id + " " +  str(regions[region_id].armies - 1)+ ",")
##########################################################################################
            #FIXME- if we have a region that is surrounded by friendly regions
            #       we need to send all the armies from that regions to reinforce
            #       the closest region in danger
##########################SCOUTING###############################################
                elif target == None and len(to_scout):
                    armies = regions[region_id].armies
                    sorted(to_scout,key=lambda neighbor: neighbor.super_region \
                        == regions[region_id].super_region,reverse=True)
                    #Send two armies to each region and the remaining to the last unscouted region
                    #This will leave only one army in the current region
                    for i in range(len(to_scout)):
                        if armies  <= SCOUT_FORCE :
                            break
                        if i == (len(to_scout) - 1):
                            to_send = armies - 1
                        else:
                            to_send = SCOUT_FORCE
                        outStr += (self.name + " attack/transfer " + region_id +
                                 " " +  to_scout[i].id + " " +str(to_send) + ",")
                        armies -= to_send
                ##Relocate armies to regions in need
                elif safe_region and regions[region_id].armies > 1:
                    path = self.map.closest_unowned_region(regions[region_id])
                    outStr += (self.name + " attack/transfer " + region_id + " "
                            + str(path[-1]) + " " +  str(regions[region_id].armies - 1)+ ",")

        if outStr == "":
            outStr += "No moves"
        print (outStr)

    def process_input(self,cmd):
        if cmd[0] == 'settings':
            if cmd[1] == 'your_bot':
                self.name = cmd[2]
            elif cmd[1] == 'opponent_bot':
                self.opponent_name = cmd[2]
            elif cmd[1] == 'starting_armies':
                self.start_armies = int(cmd[2])

        elif cmd[0] == 'pick_starting_regions':
            self.start_pick(cmd[2:])
        elif cmd[0] == 'setup_map':
            if cmd[1] == 'super_regions':
                #jump i by 2 because super regions are even
                #and bonuses are odd
                for i in range(2,len(cmd),2):
                    self.map.add_super_region(cmd[i],cmd[i+1])

            elif cmd[1] == 'regions':
                for i in range(2,len(cmd),2):
                    self.map.add_region(cmd[i],cmd[i+1])
            elif cmd[1] == 'neighbors':
                for i in range(2,len(cmd),2):
                    self.map.add_neighbors(cmd[i],cmd[i+1].split(','))
        elif cmd[0] == 'update_map':
            #clear all entries from the previous round
            self.map.visible_regions = []
            for i in range(1,len(cmd),3):
                self.map.visible_regions.append(cmd[i])
                self.map.update_region(cmd[i],cmd[i+1],cmd[i+2])
            self.update_super_regions()

        elif len(cmd) == 3 and cmd[0] == 'go':
            if cmd[1] == 'place_armies':
                self.place_armies(self.start_armies)
            elif cmd[1] == "attack/transfer":
                self.attack()
        stdout.flush()


    def run(self):
        while not stdin.closed:
            raw = stdin.readline().strip()
            if len(raw) == 0:
                continue
            else:
                eng_text = raw.split()

            self.process_input(eng_text)