def genmoves(logfn, game): moves = {} past = {} lr = 0.4 pf = 0.7 while True: env = yield moves moves = {} for aI, (aN, aO) in env.myid.iteritems(): # weighted average of all previous moves if aI in past: aOr, aOc = aO pr, pc = past[aI] past[aI] = (aOr * lr + pr * (1.0 - lr), aOc * lr + pc * (1.0 - lr)) else: past[aI] = aO pr, pc = past[aI] # average of visible water water = env.digest('water', aN) wr = fsum(r for d2, (r, c) in water) / max(len(water), 1) wc = fsum(c for d2, (r, c) in water) / max(len(water), 1) # weighted average of water and move history target = (pr * pf + wr * (1.0 - pf), pc * pf + wc * (1.0 - pf)) c = choice(am.naive_dir(target, aN)) if c != '=': moves[aI] = c moves = env.supplement(moves)
def genmoves(logfn, game): battle = game['attackradius'] holddist = (battle + 2) ** 2 moves = {} rec = {} while True: env = yield moves moves = {} rec = {} for e in env.enemyant: mine = env.digest('myant', e) while mine: d2, m = mine.pop() aN = env.wrap(m) if d2 > holddist and env.ray(m, e): if aN not in rec: rec[aN] = [] v1, v2 = am.naive_dir(m, e) rec[aN].append(v1 if random() < 0.65 else v2) for aI, (aN, _) in env.myid.iteritems(): if aN in rec: moves[aI] = choice(rec[aN]) moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for aI, (aN, _) in env.myid.iteritems(): goals = env.digest('myant', aN) if goals: d2, gloc = goals[0] if 2 ** 2 < d2 < 4 ** 2 and env.ray(aN, gloc): moves[aI] = am.naive_dir(aN, gloc) moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for aI, (aN, aO) in env.myid.iteritems(): localfood = env.digest('food', aN) if env.food and not localfood: sumr = math.fsum(r for r, c in env.food) sumc = math.fsum(c for r, c in env.food) target = sumr / len(env.food), sumc / len(env.food) moves[aI] = random.choice(antmath.naive_dir(aN, target)) moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for aI, (aN, _) in env.myid.iteritems(): food = env.digest('food', aN) while food: d2, f = food.pop(0) if env.ray(aN, f): v1, v2 = am.naive_dir(aN, f) moves[aI] = v1 if random() < 0.75 else v2 break moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for aI, (aN, aO) in env.myid.iteritems(): ants = [gloc for d2, gloc in \ env.digest('myant', aN) + env.digest('enemyant', aN) \ if d2 > 2.5 ** 2] # don't consider your clump if ants: sumr = fsum(r for r, c in ants) sumc = fsum(c for r, c in ants) target = sumr / len(ants), sumc / len(ants) v1, v2 = am.naive_dir(target, aN) moves[aI] = v1 if random() < 0.75 else v2 moves = env.supplement(moves)
def genmoves(logfn, game): battle = game['attackradius'] moveback = (battle + 2) ** 2 moves = {} # id --> vect (ant ids to vector distributions) while True: env = yield moves moves = {} for aI, (aN, _) in env.myid.iteritems(): goals = env.digest('enemyant', aN) if goals: d2, target = goals[0] if d2 <= moveback and env.ray(aN, target): v1, v2 = am.naive_dir(target, aN) # favor an indirect retreat to retain ground moves[aI] = v1 if random() < 0.25 else v2 moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for f in env.food.iterkeys(): ants = env.digest('myant', f) while ants: d2, a = ants.pop(0) aN = env.wrap(a) aI, aO = env.myant[aN] if aI not in moves and env.ray(a, f): v1, v2 = am.naive_dir(a, f) moves[aI] = v1 if random() < 0.75 else v2 break moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for aI, (aN, _) in env.myid.iteritems(): hill = env.digest('myhill', aN) enemy = env.digest('enemyant', aN) if hill and enemy: hill = hill[0][1] enemy = enemy[0][1] if env.ray(aN, enemy): hr, hc = hill er, ec = enemy target = (hr + er) / 2.0, (hc + ec) / 2.0 if env.ray(aN, target): v1, v2 = am.naive_dir(aN, target) moves[aI] = v1 if random() < 0.75 else v2 moves = env.supplement(moves)
def ray(self, origin, target): '''Is there a direct path from the origin to the target?''' origin = self.wrap(self.int(origin)) target = self.unwrap(origin, self.int(target)) # return a stored answer try: return self.rays[origin, target] except KeyError: pass # trivial if origin == target: return True # don't check long paths if self.dist2(origin, target) > self.rad2: return False # check path o = [origin] t = [target] # this loop has a bug and sometimes ran forever as a while loop # changed it to a for loop because the contest end was near! for _ in xrange(150): v, _ = am.naive_dir(o[-1], t[-1]) o.append(self.wrap(am.displace_loc(v, o[-1]))) t.append(self.unwrap(o[-1], t[-1])) if o[-1] == t[-1]: break # did the path pass through water? if self.water.viewkeys() & o: return False # remember the result for co, ct in itertools.izip(o[:-1], t[:-1]): self.rays[co, ct] = True return self.rays[origin, target]
def genmoves(logfn, game): moves = {} arounds = {} while True: env = yield moves moves = {} if not arounds: for h in env.myhill: arounds[h] = set() for n in am.neighbors(h): arounds[h] = arounds[h].union(am.eightsquare(n)) arounds[h] = arounds[h].difference([h] + am.neighbors(h)) for aI, (aN, _) in env.myid.iteritems(): hills = env.digest('myhill', aN) if hills: d2, h = hills[0] if aN == h or aN in am.neighbors(h): moves[aI] = choice('NESW') elif aN in arounds[h]: moves[aI] = choice(am.naive_dir(h, aN)) moves = env.supplement(moves)
def genmoves(logfn, game): moves = {} while True: env = yield moves moves = {} for aI, (aN, _) in env.myid.iteritems(): if aI not in moves: friends = env.digest('myant', aN) enemies = env.digest('enemyant', aN) if friends and enemies: t2, target = enemies[0] if env.ray(aN, target): enemies = env.digest('enemyant', target)[1:] myclump = [env.myant[f][0] for d2, f in friends \ if d2 < 3 ** 2 and f in env.myant] enclump = [e for d2, e in enemies \ if d2 < 3 ** 2] + [target] if len(myclump) > len(enclump): v1, v2 = am.naive_dir(aN, target) vect = v1 if random() < 0.75 else v2 for aI in myclump + [aI]: moves[aI] = vect moves = env.supplement(moves)
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