Beispiel #1
0
class Bot(object):
    '''
    Main bot class
    '''
    def __init__(self):
        '''
        Initializes a map instance and an empty dict for settings
        '''
        self.settings = {}
        self.map = Map()


    def run(self):
        '''
        Main loop
        
        Keeps running while being fed data from stdin.
        Writes output to stdout, remember to flush!
        '''
        while not stdin.closed:
            try:
                rawline = stdin.readline()

                # End of file check
                if len(rawline) == 0:
                    break

                line = rawline.strip()

                # Empty lines can be ignored
                if len(line) == 0:
                    continue

                parts = line.split()

                command = parts[0]

                # All different commands besides the opponents' moves
                if command == 'settings':
                    self.update_settings(parts[1:])

                elif command == 'setup_map':
                    self.setup_map(parts[1:])

                elif command == 'update_map':
                    self.update_map(parts[1:])

                elif command == 'pick_starting_region':
                    stdout.write(self.pick_starting_region(parts[2:]) + '\n')
                    stdout.flush()

                elif command == 'opponent_moves':
                    i=1 # Just ignoring for now

                elif command == 'go':

                    sub_command = parts[1]
                    self.settings['timebank'] = parts[2]

                    if sub_command == 'place_armies':

                        stdout.write(self.place_troops() + '\n')
                        stdout.flush()

                    elif sub_command == 'attack/transfer':

                        stdout.write(self.attack_transfer() + '\n')
                        stdout.flush()

                    else:
                        stderr.write('Unknown sub command: %s\n' % (sub_command))
                        stderr.flush()

                else:
                    stderr.write('Unknown command: %s\n' % (command))
                    stderr.flush()
            except EOFError:
                return
    

    def update_settings(self, options):
        '''
        Method to update game settings at the start of a new game.
        '''
        key = options[0]
        if len(options) > 2:
            value = options[1:]
        else:
            value = options[1]
        self.settings[key] = value


    def setup_map(self, options):
        '''
        Method to set up essential map data given by the server.
        '''
        map_type = options[0]

        for i in range(1, len(options), 2):

            if map_type == 'super_regions':

                super_region = SuperRegion(options[i], int(options[i + 1]))
                self.map.super_regions.append(super_region)

            elif map_type == 'regions':

                super_region = self.map.get_super_region_by_id(options[i + 1])
                region = Region(options[i], super_region)
                
                self.map.regions.append(region)
                super_region.regions.append(region)

            elif map_type == 'neighbors':

                region = self.map.get_region_by_id(options[i])
                neighbours = [self.map.get_region_by_id(region_id) for region_id in options[i + 1].split(',')]

                for neighbour in neighbours:
                    region.neighbours.append(neighbour)
                    neighbour.neighbours.append(region)
            
        if map_type == 'wastelands':

            for i in range(1, len(options)):

                region = self.map.get_region_by_id(options[i])
                region.is_wasteland = True


        if map_type == 'neighbors':
            
            for region in self.map.regions:

                if region.is_on_super_region_border:
                    continue

                for neighbour in region.neighbours:

                    if neighbour.super_region.id != region.super_region.id:

                        region.is_on_super_region_border = True
                        neighbour.is_on_super_region_border = True


    def update_map(self, options):
        '''
        Method to update our map every round.
        '''

        # Make a copy of owned regions
        orig_owned_regions = self.map.get_owned_regions(self.settings['your_bot'])[:]

        for i in range(0, len(options), 3):
            
            region = self.map.get_region_by_id(options[i])
            if region.owner == self.settings['your_bot']:
                orig_owned_regions.remove(region)
            region.owner = options[i + 1]
            region.troop_count = int(options[i + 2])

        # if we own a region that was not in the update, it must have been captured and is now hidden by fog of war
        for region in orig_owned_regions:
            #print region.id + ' was captured'
            region.owner = self.settings['opponent_bot']
                        

    def pick_starting_region(self, options):
        '''
        Method to select our initial starting region.
        
        Currently selects a random region from the list.
        '''
        i = Random.randrange(0,len(options)-1)
        
        return options[i]


    def place_troops(self):
        '''
        Method to place our troops.
        
        Currently keeps places a maximum of two troops on random regions.
        '''
        placements = []
        region_index = 0
        troops_remaining = int(self.settings['starting_armies'])
        
        owned_regions = self.map.get_owned_regions(self.settings['your_bot'])
        duplicated_regions = owned_regions * (3 + int(troops_remaining / 2))
        shuffled_regions = Random.shuffle(duplicated_regions)
        
        while troops_remaining:

            region = shuffled_regions[region_index]
            
            if troops_remaining > 1:

                placements.append([region.id, 2])

                region.troop_count += 2
                troops_remaining -= 2
                
            else:

                 placements.append([region.id, 1])

                 region.troop_count += 1
                 troops_remaining -= 1

            region_index += 1
            
        return ', '.join(['%s place_armies %s %d' % (self.settings['your_bot'], placement[0],
            placement[1]) for placement in placements])


    def attack_transfer(self):
        '''
        Method to attack another region or transfer troops to allied regions.
        
        Currently checks whether a region has more than six troops placed to attack,
        or transfers if more than 1 unit is available.
        '''
        attack_transfers = []
        
        owned_regions = self.map.get_owned_regions(self.settings['your_bot'])
        
        for region in owned_regions:
            neighbours = list(region.neighbours)
            while len(neighbours) > 0:
                target_region = neighbours[Random.randrange(0, len(neighbours))]
                if region.owner != target_region.owner and region.troop_count > 6:
                    attack_transfers.append([region.id, target_region.id, 5])
                    region.troop_count -= 5
                elif region.owner == target_region.owner and region.troop_count > 1:
                    attack_transfers.append([region.id, target_region.id, region.troop_count - 1])
                    region.troop_count = 1
                else:
                    neighbours.remove(target_region)
        
        if len(attack_transfers) == 0:
            return 'No moves'
        
        return ', '.join(['%s attack/transfer %s %s %s' % (self.settings['your_bot'], attack_transfer[0],
            attack_transfer[1], attack_transfer[2]) for attack_transfer in attack_transfers])