def will_meet(): if q.collinear(shell_speed): #TODO: may be bug good_direction = sign(shell_speed.x) != sign( q.x) and sign(shell_speed.y) != sign(q.y) if good_direction: return (True, (shell_v - tank_v).length() / (shell_speed.length() + INITIAL_SHELL_VELOCITY)) else: return (False, -1) else: d_tank, d_shell = intersect_lines( tank_v, q, shell_v, shell_speed.normalize()) d_tank = d_tank - 40 if d_tank < 0 or d_shell < 0: return (False, -1) t_tank = solve_quadratic(SHELL_ACCELERATION / 2, INITIAL_SHELL_VELOCITY, -d_tank) t_shell = solve_quadratic(SHELL_ACCELERATION / 2, shell_speed.length(), -d_shell) if fabs(t_tank - t_shell) < 1.5: return (True, t_tank) else: return (False, -1)
def estimate_time_to_position(self, x, y, tank): dist = tank.get_distance_to(x, y) vt = Vector(tank.speedX, tank.speedY) tank_v = Vector(tank.x, tank.y) pt_v = Vector(x, y) d = pt_v - tank_v if d.is_zero(): return 0 tank_d_v = Vector(1, 0).rotate(tank.angle) if vt.is_zero() or d.is_zero(): vd_angle = 0 else: vd_angle = vt.angle(d) if tank_d_v.is_zero() or d.is_zero(): d_angle = 0 else: d_angle = tank_d_v.angle(d) # Short distances fix if dist < 100: if fabs(d_angle) < LOW_ANGLE: v0 = vt.projection(d) return solve_quadratic(FICTIVE_ACCELERATION/2, v0, -dist) #return dist/6 elif PI - fabs(d_angle) < LOW_ANGLE: v0 = vt.projection(d) return solve_quadratic(FICTIVE_ACCELERATION/2 * 0.75, v0, -dist) #return dist/6 /0.75 if d.is_zero(): values = (0, 0, 0, 0, 0, 0, 0, 1) else: values = ( d_angle, dist, vd_angle, vt.length(), tank.angular_speed, tank.crew_health/tank.crew_max_health, d_angle ** 2, 1 ) return sum([x * y for (x, y) in zip(values, TIME_ESTIMATION_COEF)])
def estimate_time_to_position(self, x, y, tank): dist = tank.get_distance_to(x, y) vt = Vector(tank.speedX, tank.speedY) tank_v = Vector(tank.x, tank.y) pt_v = Vector(x, y) d = pt_v - tank_v if d.is_zero(): return 0 tank_d_v = Vector(1, 0).rotate(tank.angle) if vt.is_zero() or d.is_zero(): vd_angle = 0 else: vd_angle = vt.angle(d) if tank_d_v.is_zero() or d.is_zero(): d_angle = 0 else: d_angle = tank_d_v.angle(d) # Short distances fix if dist < 100: if fabs(d_angle) < LOW_ANGLE: v0 = vt.projection(d) return solve_quadratic(FICTIVE_ACCELERATION / 2, v0, -dist) #return dist/6 elif PI - fabs(d_angle) < LOW_ANGLE: v0 = vt.projection(d) return solve_quadratic(FICTIVE_ACCELERATION / 2 * 0.75, v0, -dist) #return dist/6 /0.75 if d.is_zero(): values = (0, 0, 0, 0, 0, 0, 0, 1) else: values = (d_angle, dist, vd_angle, vt.length(), tank.angular_speed, tank.crew_health / tank.crew_max_health, d_angle**2, 1) return sum([x * y for (x, y) in zip(values, TIME_ESTIMATION_COEF)])
def will_meet(): if q.collinear(shell_speed): #TODO: may be bug good_direction = sign(shell_speed.x) != sign(q.x) and sign(shell_speed.y) != sign(q.y) if good_direction: return (True, (shell_v - tank_v).length()/(shell_speed.length() + INITIAL_SHELL_VELOCITY)) else: return (False, -1) else: d_tank, d_shell = intersect_lines(tank_v, q, shell_v, shell_speed.normalize()) d_tank = d_tank - 40 if d_tank < 0 or d_shell < 0: return (False, -1) t_tank = solve_quadratic(SHELL_ACCELERATION/2, INITIAL_SHELL_VELOCITY, -d_tank) t_shell = solve_quadratic(SHELL_ACCELERATION/2, shell_speed.length(), -d_shell) if fabs(t_tank - t_shell) < 1.5: return (True, t_tank) else: return (False, -1)
def shell_will_hit_tank_going_to(self, shell, tank, x, y, et=None): if et is None: et = self.estimate_time_to_position(x, y, tank) dist = tank.get_distance_to(x, y) v0 = hypot(shell.speedX, shell.speedY) a = SHELL_ACCELERATION d = tank.get_distance_to_unit(shell) #d = shell.get_distance_to(x, y) t = solve_quadratic(a / 2, v0, -d) if self.shell_will_hit(shell, tank, factor=1.05) and (et > t): return 1 #self.max_move_distance(fabs(v0), FICTIVE_ACCELERATION, 3, t) < dist): if dist < 150: # short distance result = self.shell_will_hit(shell, fictive_unit(tank, x, y), factor=1.05) if result: pt_v = Vector(x, y) tank_v = Vector(tank.x, tank.y) dir = pt_v - tank_v shell_speed = Vector(shell.speedX, shell.speedY) if dir.is_zero() or shell_speed.is_zero(): return float(result) if dir.angle(shell_speed) < PI / 8 and shell.get_distance_to( x, y) > d: return 0.6 return result else: # long distance, check if our direction is intersecting segment between shell and shell + v_shell*t pt_v = Vector(x, y) tank_v = Vector(tank.x, tank.y) dir = tank_v - pt_v shell_v = Vector(shell.x, shell.y) shell_speed = Vector(shell.speedX, shell.speedY) next_shell = shell_v + shell_speed * (t + 5) if sign((shell_v - tank_v).cross_product(dir)) == sign( dir.cross_product(next_shell - tank_v)): return True else: return False
def shell_will_hit_tank_going_to(self, shell, tank, x, y, et=None): if et is None: et = self.estimate_time_to_position(x, y, tank) dist = tank.get_distance_to(x, y) v0 = hypot(shell.speedX, shell.speedY) a = SHELL_ACCELERATION d = tank.get_distance_to_unit(shell) #d = shell.get_distance_to(x, y) t = solve_quadratic(a/2, v0, -d) if self.shell_will_hit(shell, tank, factor=1.05) and (et > t): return 1 #self.max_move_distance(fabs(v0), FICTIVE_ACCELERATION, 3, t) < dist): if dist < 150: # short distance result = self.shell_will_hit(shell, fictive_unit(tank, x, y), factor=1.05) if result: pt_v = Vector(x, y) tank_v = Vector(tank.x, tank.y) dir = pt_v - tank_v shell_speed = Vector(shell.speedX, shell.speedY) if dir.is_zero() or shell_speed.is_zero(): return float(result) if dir.angle(shell_speed) < PI/8 and shell.get_distance_to(x, y) > d: return 0.6 return result else: # long distance, check if our direction is intersecting segment between shell and shell + v_shell*t pt_v = Vector(x, y) tank_v = Vector(tank.x, tank.y) dir = tank_v - pt_v shell_v = Vector(shell.x, shell.y) shell_speed = Vector(shell.speedX, shell.speedY) next_shell = shell_v + shell_speed * (t + 5) if sign((shell_v - tank_v).cross_product(dir)) == sign(dir.cross_product(next_shell - tank_v)): return True else: return False
def _make_turn(self, tank, world, move): # Precalc for estimation self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks)) self.allies = list(filter(ALLY_TANK(tank.id), world.tanks)) self.health_fraction = tank.crew_health / tank.crew_max_health self.hull_fraction = tank.hull_durability / tank.hull_max_durability self.enemies_count = len(self.enemies) self.est_time_cache = {} positions = [] for pg in self.position_getters: positions += pg.positions(tank, world) self.debug('Got %d positions' % len(positions)) if not positions: return for e in self.position_estimators: e.context = self pos_and_values = [(pos, sum([e.value(pos) for e in self.position_estimators])) for pos in positions] if self.debug_mode: top_pos = [item[0] for item in list(reversed(sorted(pos_and_values, key=operator.itemgetter(1))))[:6]] self.debug(' ' * 50, end='') for e in self.position_estimators: self.debug('%14s' % e.NAME, end='') self.debug('%14s' % 'RESULT', end='') self.debug('') def out_pos(pos): self.debug('%-50s' % (str(pos) + ' : '), end='') res = 0 for e in self.position_estimators: v = e.value(pos) self.debug('%14.2f' % v, end='') res += v self.debug('%14.2f' % res, end='') self.debug('') for pos in top_pos: out_pos(pos) self.debug('=' * 16) for pos in positions: if pos.name.find('BONUS') != -1: out_pos(pos) self.debug('=' * 16) for pos in positions: if pos.name == 'FORWARD' or pos.name == 'BACKWARD' or pos.name == 'CURRENT': out_pos(pos) self.debug('=' * 16) for pos in positions: if pos.name.find('BORDER') != -1: out_pos(pos) next_position = None position_iteration = 0 #average_F = sum([pos[0] for pos in pos_f])/len(pos_f) pos_queue = PriorityQueue() for p_v in pos_and_values: pos_queue.put( (-p_v[1] + random() * 1e-3, p_v[0]) ) while True: cur = pos_queue.get()[1] if not self.physics.position_is_blocked(cur.x, cur.y, tank, world) or position_iteration >= MAX_POSITION_ITERATIONS: next_position = cur break position_iteration += 1 self.debug('!!! Skipping best position, iteration %d' % position_iteration) if self.debug_mode: self.debug('(blocked by %s)' % str(self.physics.position_is_blocked(cur.x, cur.y, tank, world))) self.debug("GOING TO [%10s] (%8.2f, %8.2f); distance=%8.2f, ETA=%8.2f" % (next_position.name, next_position.x, next_position.y, self.tank.get_distance_to(next_position.x, next_position.y), self.physics.estimate_time_to_position(next_position.x, next_position.y, tank)) ) self.memory.last_target_position[tank.id] = next_position self.physics.move_to_position(next_position.x, next_position.y, tank, move) self.debug('=' * 16) if self.debug_mode: for shell in world.shells: v0 = hypot(shell.speedX, shell.speedY) a = SHELL_ACCELERATION d = tank.get_distance_to_unit(shell) tank_v = Vector(tank.x, tank.y) shell_v = Vector(shell.x, shell.y) shell_speed = Vector(shell.speedX, shell.speedY) #d = shell.get_distance_to(x, y) t = solve_quadratic(a/2, v0, -d) self.debug('SHELL [%12s] (%8.2f, %8.2f) v=%s, will hit=%s, hit time=%8.2f' % (shell.player_name, shell.x, shell.y, shell_speed.length(), str(self.physics.shell_will_hit(shell, tank, factor=1.05)), t) ) self.debug('=' * 16)
def _make_turn(self, tank, world, move): # Precalc for estimation self.enemies = list(filter(ALIVE_ENEMY_TANK, world.tanks)) self.allies = list(filter(ALLY_TANK(tank.id), world.tanks)) self.health_fraction = tank.crew_health / tank.crew_max_health self.hull_fraction = tank.hull_durability / tank.hull_max_durability self.enemies_count = len(self.enemies) self.est_time_cache = {} positions = [] for pg in self.position_getters: positions += pg.positions(tank, world) self.debug('Got %d positions' % len(positions)) if not positions: return for e in self.position_estimators: e.context = self pos_and_values = [ (pos, sum([e.value(pos) for e in self.position_estimators])) for pos in positions ] if self.debug_mode: top_pos = [ item[0] for item in list( reversed(sorted(pos_and_values, key=operator.itemgetter( 1))))[:6] ] self.debug(' ' * 50, end='') for e in self.position_estimators: self.debug('%14s' % e.NAME, end='') self.debug('%14s' % 'RESULT', end='') self.debug('') def out_pos(pos): self.debug('%-50s' % (str(pos) + ' : '), end='') res = 0 for e in self.position_estimators: v = e.value(pos) self.debug('%14.2f' % v, end='') res += v self.debug('%14.2f' % res, end='') self.debug('') for pos in top_pos: out_pos(pos) self.debug('=' * 16) for pos in positions: if pos.name.find('BONUS') != -1: out_pos(pos) self.debug('=' * 16) for pos in positions: if pos.name == 'FORWARD' or pos.name == 'BACKWARD' or pos.name == 'CURRENT': out_pos(pos) self.debug('=' * 16) for pos in positions: if pos.name.find('BORDER') != -1: out_pos(pos) next_position = None position_iteration = 0 #average_F = sum([pos[0] for pos in pos_f])/len(pos_f) pos_queue = PriorityQueue() for p_v in pos_and_values: pos_queue.put((-p_v[1] + random() * 1e-3, p_v[0])) while True: cur = pos_queue.get()[1] if not self.physics.position_is_blocked( cur.x, cur.y, tank, world) or position_iteration >= MAX_POSITION_ITERATIONS: next_position = cur break position_iteration += 1 self.debug('!!! Skipping best position, iteration %d' % position_iteration) if self.debug_mode: self.debug('(blocked by %s)' % str( self.physics.position_is_blocked(cur.x, cur.y, tank, world))) self.debug( "GOING TO [%10s] (%8.2f, %8.2f); distance=%8.2f, ETA=%8.2f" % (next_position.name, next_position.x, next_position.y, self.tank.get_distance_to(next_position.x, next_position.y), self.physics.estimate_time_to_position(next_position.x, next_position.y, tank))) self.memory.last_target_position[tank.id] = next_position self.physics.move_to_position(next_position.x, next_position.y, tank, move) self.debug('=' * 16) if self.debug_mode: for shell in world.shells: v0 = hypot(shell.speedX, shell.speedY) a = SHELL_ACCELERATION d = tank.get_distance_to_unit(shell) tank_v = Vector(tank.x, tank.y) shell_v = Vector(shell.x, shell.y) shell_speed = Vector(shell.speedX, shell.speedY) #d = shell.get_distance_to(x, y) t = solve_quadratic(a / 2, v0, -d) self.debug( 'SHELL [%12s] (%8.2f, %8.2f) v=%s, will hit=%s, hit time=%8.2f' % (shell.player_name, shell.x, shell.y, shell_speed.length(), str(self.physics.shell_will_hit(shell, tank, factor=1.05)), t)) self.debug('=' * 16)
def get_hit_time(): v0 = INITIAL_SHELL_VELOCITY a = SHELL_ACCELERATION d = max(0, tank.get_distance_to_unit(target) - 60) return solve_quadratic(a / 2, v0, -d)
def get_hit_time(): v0 = INITIAL_SHELL_VELOCITY a = SHELL_ACCELERATION d = max(0, tank.get_distance_to_unit(target) - 60) return solve_quadratic(a/2, v0, -d)