def unwrapped_dir(self, origin, target): '''Find the shortest path to the target. Return closest unwrapped location and its distance squared as a tuple: (distance2, location) ''' h = self.g['rows'] w = self.g['cols'] r, c = target options = [target, (r-h, c), (r+h, c), (r, c-w), (r, c+w)] return min([(antmath.distance2(origin, t), t) for t in options])
def think(self, dirt, food, enemyhill, enemyant, myhill, myant, mydead): '''Return a dict with the keys of myant mapped to lists of NESW=.''' # build a list of goals goaltime = DateTime.now() # active goals active = {} active.update({loc:self.ENEMYHILL for loc in enemyhill}) if len(myant) > 1.35 * len(enemyant): active.update({loc:self.ENEMYANTBATTLE for loc in enemyant}) else: active.update({loc:self.ENEMYANT for loc in enemyant}) # log about active goals self.logfn('\nactive goals: {}'.format(active)) if self.logfn else None # passive goals passive = {} if len(myant) < 125: passive.update({loc:self.FOOD for loc in food}) # increase age of passive goals; keep ages of old and visible ones self.age = {loc:age + 1 for loc, age in self.age.iteritems() \ if age > self.MAXAGE or loc in passive} # track age new passive goals new = {loc:0 for loc in passive} new.update(self.age) self.age = new # filter passive goals which are old passive = {loc:rad for loc, rad in passive.iteritems() \ if loc in self.age and self.age[loc] <= self.MAXAGE} # if there are enemies near a hill, protect the hill if any(any(antmath.nearest_unwrapped_loc(hill, self.size, e)[0] \ <= self.PERIMETER for e in enemyant) \ for hill in myhill): passive.update({loc:self.MYHILL for loc in myhill}) # log about passive goals self.logfn('\npassive goals: {}\nages: {}'.format(passive, self.age) ) if self.logfn else None # combine goal lists, giving active goals priority passive.update(active) goals = passive # log about goal descision time self.logfn('goal time: {}ms'.format( (DateTime.now() - goaltime).total_seconds() * 1000.0) ) if self.logfn else None # assign moves to ants if goals: if len(goals) > 1: # divide ants by location into len(goals) groups clustime = DateTime.now() squads = self.cluster(1, goals.keys(), myant.keys()) assert sum(map(len, squads.values())) == len(myant) self.logfn('cluster: {}ms'.format( (DateTime.now() - clustime).total_seconds() * 1000.0) ) if self.logfn else None else: # all ants are in one supercluster self.logfn('supercluster') if self.logfn else None rows, cols = zip(*myant.keys()) r = float(sum(rows)) / len(myant) c = float(sum(cols)) / len(myant) squads = {(r, c): myant.keys()} # assign each squad the closest goal for sM, sA in squads.iteritems(): dist, gloc = min([self.unwrapped_dir(sM, loc) for loc in goals]) gradmin, gradmax = goals[self.wrap(gloc)] for aN in sA: # make ants keep the right distance from goals vect = antmath.naive_dir(aN, gloc) dist = antmath.distance2(aN, gloc) if dist > gradmax and dist < 7 * self.g['viewradius2']: myant[aN] = vect random.shuffle(myant[aN]) if gradmax != gradmin else None myant[aN] += [antmath.reverse_dir(v) for v in vect] elif dist < gradmin: myant[aN] = [antmath.reverse_dir(v) for v in vect] random.shuffle(myant[aN]) if gradmax != gradmin else None myant[aN] += vect else: myant[aN] = self.v[:] random.shuffle(myant[aN]) else: # move each ant individually randomly self.logfn('brownian') if self.logfn else None for aN, (aI, aO) in myant.iteritems(): random.shuffle(self.v) myant[aN] = self.v[:] return myant
def dist2(a, b): return am.distance2(a, b)