def parse_message(self, message): print(message) self._think_mode = False if message.find("(init") is not -1: self.init_dlog(message) if message.find("server_param") is not -1: ServerParam.i().parse(message) elif message.find("fullstate") is not -1 or message.find("player_type") is not -1 or message.find( "sense_body") is not -1 or message.find("(init") is not -1: self._full_world.parse(message) dlog._time = self.world().time() elif message.find("think") is not -1: self._think_mode = True
def create_ball_cache(self, wm): SP = ServerParam.i() pitch_max_x = SP.pitch_half_length() + 5 pitch_max_y = SP.pitch_half_width() + 5 ball_decay = SP.ball_decay() ball_pos: Vector2D = wm.ball().pos() ball_vel: Vector2D = wm.ball().vel() self._ball_cache.append(ball_pos) for cycle in range(1, self._max_cycle + 1): # dlog.add_point(Level.INTERCEPT, pos=ball_pos, color=Color(string='blue')) dlog.add_circle(Level.INTERCEPT, r=0.1, center=ball_pos, fill=True, color=Color(string="blue")) dlog.add_text(Level.INTERCEPT, f"ballpos: {ball_pos}") ball_pos += ball_vel ball_vel *= ball_decay self._ball_cache.append(ball_pos) if cycle >= 5 and ball_vel.r() < 0.01**2: # ball stopped break if ball_pos.absX() > pitch_max_x or ball_pos.absY() > pitch_max_y: # out of pitch break # TODO if len == 1 push ball pos again :| why?? if len(self._ball_cache) == 1: self._ball_cache.append(ball_pos)
def simulate_wait(self, player_type: PlayerType): SP = ServerParam.i() # recovery if self._stamina <= SP.recover_dec_thr_value(): if self._recovery > SP.recover_min(): self._recovery -= SP.recover_dec() self._recovery = max(self._recovery, SP.recover_min()) # effort if self._stamina <= SP.effort_dec_thr_value(): if self._effort > player_type.effort_min(): self._effort -= SP.effort_dec() self._effort = max(self._effort, player_type.effort_min()) elif self._stamina >= SP.effort_inc_thr_value(): if self._effort < player_type.effort_max(): self._effort += SP.effort_inc() self._effort = min(self._effort, player_type.effort_max()) stamina_inc = min(player_type.stamina_inc_max() * self._recovery, SP.stamina_max() - self._stamina) if SP.stamina_capacity() >= 0: self._stamina += min(stamina_inc, self._capacity) self._capacity -= stamina_inc self._capacity = max(0, self._capacity) else: self._stamina += stamina_inc self._stamina = min(self._stamina, SP.stamina_max()) # kirm tu in mohasebat :|
def __init__(self, stamina=None, effort=None, recovery=None, capacity=None): SP = ServerParam.i() self._stamina: float = float(stamina) if stamina else SP.stamina_max() self._effort: float = float(effort) if effort else SP.effort_init() self._recovery: float = float( recovery) if recovery else SP.recover_init() self._capacity: float = float(capacity) if capacity else -1
def get_one_step_dash_power(self, next_ball_rel: Vector2D, dash_angle: AngleDeg, max_forward_accel_x: float, max_back_accel_x): wm = self._wm dash_rate = wm.self().dash_rate() * ServerParam.i().dash_dir_rate( dash_angle.degree()) ptype = wm.self().player_type() best_ctrl_dist_forward = ptype.player_size( ) + ptype.kickable_margin() / 2 + ServerParam.i().ball_size() best_ctrl_dist_backward = ptype.player_size( ) + 0.3 * ptype.kickable_margin() + ServerParam.i().ball_size() # y diff is longer than best dist. # just put the ball on player's side if next_ball_rel.absY() > best_ctrl_dist_forward: return next_ball_rel.x() / dash_rate forward_trap_accel_x = next_ball_rel.x() - (best_ctrl_dist_forward**2 - next_ball_rel.y()**2)**0.5 backward_trap_accel_x = next_ball_rel.x() + ( best_ctrl_dist_backward**2 - next_ball_rel.y()**2)**0.5 best_accel_x = 10000 min_power = 10000 x_step = (backward_trap_accel_x - forward_trap_accel_x) / 5 for accel_x in frange(forward_trap_accel_x, backward_trap_accel_x, x_step): if (0 <= accel_x < max_forward_accel_x) or \ (max_back_accel_x < accel_x < 0): power = accel_x / dash_rate if abs(power) < abs(min_power): best_accel_x = accel_x min_power = power if min_power < 1000: return min_power return -1000
def predict_one_step(self, self_cache): wm = self._wm ball_next: Vector2D = wm.ball().pos() + wm.ball().vel() goalie_mode: bool = self.is_goalie_mode(ball_next) control_area: float = wm.self().player_type().catchable_area() if \ goalie_mode else \ wm.self().player_type().kickable_area() # dist is to far never reach with one dash if wm.ball().dist_from_self() > \ ServerParam.i().ball_speed_max() \ + wm.self().player_type().real_speed_max() \ + control_area: return if self.predict_no_dash(self_cache): return self.predict_one_dash(self_cache)
def init_additional_params(self): self._kickable_area = self.player_size() + self.kickable_margin() + SP.i().ball_size() # TODO in cpp base define this in SP?!?!?! catch_stretch_length_x = (self.catchable_area_l_stretch() - 1.0) * SP.i().catch_area_l() catch_length_min_x = SP.i().catch_area_l() - catch_stretch_length_x catch_length_max_x = SP.i().catch_area_l() + catch_stretch_length_x catch_half_width2 = math.pow(SP.i().catch_area_w() / 2.0, 2) self._reliable_catchable_dist = math.sqrt(math.pow(catch_length_min_x, 2) + catch_half_width2) self._max_catchable_dist = math.sqrt( math.pow(catch_length_max_x, 2) + catch_half_width2) # TODO catch_length_max_x { / 2} ?! accel = SP.i().max_dash_power() * self.dash_power_rate() * self.effort_max() self._real_speed_max = accel / (1.0 - self.player_decay()) if self._real_speed_max > self.player_speed_max(): self._real_speed_max = self.player_speed_max() speed = 0.0 dash_power = SP.i().max_dash_power() reach_dist = 0.0 self._dash_distance_table.clear() self._dash_distance_table = [0 for i in range(50)] for c in range(50): if speed + accel > self.player_speed_max(): accel = self.player_speed_max() - speed dash_power = min(SP.i().max_dash_power(), accel / (self.dash_power_rate() * 1.0)) # should change speed += accel reach_dist += speed self._dash_distance_table[c] = reach_dist if self._cycles_to_reach_max_speed < 0 and speed >= self.real_speed_max() - 0.01: self._cycles_to_reach_max_speed = c # stamina_model.simulateDash(*this, dash_power); # # if (stamina_model.stamina() <= 0.0) # { # break; # } # speed *= self.player_decay()
def predict_short_step(self, max_cycle, save_recovery, self_cache): tmp_cache = [] max_loop = min(self._max_short_step, max_cycle) SP = ServerParam.i() wm = self._wm ball = wm.ball() me = wm.self() ptype = me.player_type() pen_area_x = SP.our_penalty_area_line_x() - 0.5 pen_area_y = SP.penalty_area_half_width() - 0.5 ball_to_self = (me.pos() - ball.pos()).rotated_vector(ball.vel().th()) min_cycle = int( ceil(ball_to_self.absY() - ptype.kickable_area()) / ptype.real_speed_max()) if min_cycle >= max_loop: return if min_cycle < 2: min_cycle = 2
def generate_direct_pass(self, wm: WorldModel, unum, action_candidates): simple_direct_pass = KickAction() if wm.our_player(unum).unum() is 0: return tm = wm.our_player(unum) if tm.unum() == wm.self().unum(): return intercept_cycle = 0 if wm.self().is_kickable(): intercept_cycle = 0 simple_direct_pass.type = KickActionType.Pass simple_direct_pass.start_ball_pos = wm.ball().pos() simple_direct_pass.target_ball_pos = tm.pos() simple_direct_pass.target_unum = unum simple_direct_pass.start_ball_speed = 2.0 pass_dist = simple_direct_pass.start_ball_pos.dist( simple_direct_pass.target_ball_pos) ball_speed = simple_direct_pass.start_ball_speed ball_vel: Vector2D = Vector2D.polar2vector( ball_speed, (simple_direct_pass.target_ball_pos - simple_direct_pass.start_ball_pos).th()) print(type(ball_vel)) ball_pos: Vector2D = simple_direct_pass.start_ball_pos travel_dist = 0 cycle = 0 print(ball_pos) print(simple_direct_pass.target_ball_pos) print(pass_dist) while travel_dist < pass_dist and ball_speed >= 0.1: dlog.add_circle(Level.PASS, Circle2D(ball_pos, 1)) cycle += 1 travel_dist += ball_speed ball_speed *= SP.i().ball_decay() ball_pos += ball_vel ball_vel.set_length(ball_speed) if self.can_opps_cut_ball(wm, ball_pos, cycle): return action_candidates.append(simple_direct_pass)
def init(self, player_type: PlayerType): SP = ServerParam.i() self._stamina = SP.stamina_max() self._effort = player_type.effort_max() self._recovery = SP.recover_init() self._capacity = SP.stamina_capacity()
def dash_rate(self, effort, rel_dir): return self.dash_rate(effort) * SP.i().dash_dir_rate(rel_dir) # TODO bug :|
def predict_one_dash(self, self_cache): tmp_cache = [] SP = ServerParam.i() wm: WorldModel = self._wm ball: BallObject = wm.ball() me: PlayerObject = wm.self() ptype: PlayerType = me.player_type() ball_next: Vector2D = ball.pos() + ball.vel() goalie_mode: bool = self.is_goalie_mode(ball_next) control_area: float = ptype.catchable_area() if \ goalie_mode else \ ptype.kickable_area() dash_angle_step: float = max(5, SP.dash_angle_step()) min_dash_angle = SP.min_dash_angle() if -180 < SP.max_dash_angle() < 180 else \ dash_angle_step * int(-180 / dash_angle_step) max_dash_angle = SP.max_dash_angle() + dash_angle_step * 0.5 if \ -180 < SP.max_dash_angle() < 180 else \ dash_angle_step * int(180 / dash_angle_step) - 1 dlog.add_text( Level.INTERCEPT, f"self pred on dash min_angle={min_dash_angle}, max_angle={max_dash_angle}" ) for dirr in frange(min_dash_angle, max_dash_angle, dash_angle_step): dash_angle: AngleDeg = me.body() + SP.discretize_dash_angle( SP.normalize_dash_angle(dirr)) dash_rate: float = me.dash_rate() * SP.dash_dir_rate(dirr) dlog.add_text( Level.INTERCEPT, f"self pred one dash dir={dirr}, angle={dash_angle}, dash_rate={dash_rate}" ) # check recovery save dash forward_dash_power = bound( 0, me.stamina() - SP.recover_dec_thr_value() - 1, SP.max_dash_power()) back_dash_power = bound( SP.min_dash_power(), (me.stamina() - SP.recover_dec_thr_value() - 1) * -0.5, 0) max_forward_accel = Vector2D.polar2vector( forward_dash_power * dash_rate, dash_angle) max_back_accel = Vector2D.polar2vector(back_dash_power * dash_rate, dash_angle) ptype.normalize_accel(me.vel(), max_forward_accel) ptype.normalize_accel(me.vel(), max_back_accel) info: InterceptInfo = InterceptInfo() if self.predict_one_dash_adjust(dash_angle, max_forward_accel, max_back_accel, control_area, info): dlog.add_text(Level.INTERCEPT, "Register 1 dash intercept(1)") tmp_cache.append(info) continue # check max_power_dash if abs(forward_dash_power - SP.max_dash_power()) < 1 and \ abs(back_dash_power - SP.min_dash_power()) < 1: continue max_forward_accel = Vector2D.polar2vector( SP.max_dash_power() * dash_rate, dash_angle) max_back_accel = Vector2D.polar2vector( SP.min_dash_power() * dash_rate, dash_angle) ptype.normalize_accel(me.vel(), max_forward_accel) ptype.normalize_accel(me.vel(), max_back_accel) if self.predict_one_dash_adjust(dash_angle, max_forward_accel, max_back_accel, control_area, info): dlog.add_text(Level.INTERCEPT, "Register 1 dash intercept(2)") tmp_cache.append(info) continue if len(tmp_cache) == 0: return safety_ball_dist = max( control_area - 0.2 - ball.vel().r() * SP.ball_rand(), ptype.player_size() + SP.ball_size() + ptype.kickable_margin() * 0.4) best: InterceptInfo = tmp_cache[0] for it in tmp_cache: if best.ball_dist() < safety_ball_dist and \ it.ball_dist() < safety_ball_dist: if best.stamina() < it.stamina(): best = it elif best.ball_dist() > it.ball_dist() or \ (abs(best.ball_dist() - it.ball_dist()) < 0.001 and best.stamina() < it.stamina()): best = it self_cache.append(best)
def kick_rate(self, ball_dist, dir_diff): return (self.kick_power_rate() * (1.0 - 0.25 * math.fabs(dir_diff) / 180.0 - ( 0.25 * (ball_dist - SP.i().ball_size() - self.player_size()) / self.kickable_margin())))
def predict_one_dash_adjust(self, dash_angle: AngleDeg, max_forward_accel: Vector2D, max_back_accel: Vector2D, control_area: float, info: InterceptInfo): SP = ServerParam.i() wm = self._wm me = wm.self() control_buf = control_area - 0.075 dash_dir: AngleDeg = dash_angle - me.body() ball_next = wm.ball().pos() + wm.ball().vel() me_next = me.pos() + me.vel() ball_rel: Vector2D = (ball_next - me_next).rotated_vector(-dash_angle) forward_accel_rel: Vector2D = max_forward_accel.rotated_vector( -dash_angle) back_accel_rel: Vector2D = max_back_accel.rotated_vector(-dash_angle) dash_rate = me.dash_rate() * SP.dash_dir_rate(dash_dir.degree()) dlog.add_text( Level.INTERCEPT, f"self pred one dash adjust dir={dash_dir}, ball_rel={ball_rel}") dlog.add_text( Level.INTERCEPT, f"_____ max_forward_accel={max_forward_accel} rel={forward_accel_rel}" ) dlog.add_text( Level.INTERCEPT, f"_____ max_back_accel={max_back_accel} rel={back_accel_rel}") if ball_rel.absY() > control_buf or \ Segment2D(forward_accel_rel, back_accel_rel).dist(ball_rel) > control_buf: return False dash_power = -1000 # small x difference # player can put the ball on his side if back_accel_rel.x() < ball_rel.x() < forward_accel_rel.x(): dash_power = self.get_one_step_dash_power(ball_rel, dash_angle, forward_accel_rel.x(), back_accel_rel.x()) dlog.add_text( Level.INTERCEPT, f"self pred one dash adjust (1). dash_power={dash_power}") # big x difference x (>0) if dash_power < -999 and \ forward_accel_rel.x() < ball_rel.x: enable_ball_dist = ball_rel.dist(forward_accel_rel) if enable_ball_dist < control_buf: dash_power = forward_accel_rel.x() / dash_rate dlog.add_text( Level.INTERCEPT, f"self pred one dash adjust (2). not best." + f"next_ball_dist={enable_ball_dist}, dash_power={dash_power}" ) # big x difference (<0) if dash_power < -999 and \ ball_rel.x() < back_accel_rel.x(): enable_ball_dist = ball_rel.dist(ball_rel) if enable_ball_dist < control_buf: dash_power = back_accel_rel.x() / dash_rate dlog.add_text( Level.INTERCEPT, f"self pred one dash adjust (3). not best." + f"next_ball_dist={enable_ball_dist}, dash_power={dash_power}" ) # check if adjustable if dash_power < -999 and \ back_accel_rel.x() < ball_rel.x() < forward_accel_rel.x(): dash_power = ball_rel.x() / dash_rate dlog.add_text( Level.INTERCEPT, f"self pred one dash adjust (4). not best." + f"just adjust X. dash_power={dash_power}") # register if dash_power < -999: dlog.add_text(Level.INTERCEPT, "self pred one dash adjust XXX FAILED") return False mode = InterceptInfo.Mode.NORMAL accel = Vector2D.polar2vector(dash_power * dash_rate, dash_angle) my_vel = me.vel() + accel my_pos = me.pos() + my_vel stamina_model = me.stamina_model() stamina_model.simulate_dash(me.player_type(), dash_power) if stamina_model.stamina() < SP.recover_dec_thr_value() and \ not stamina_model.capacity_is_empty(): mode = InterceptInfo.Mode.EXHAUST info.init(mode, 0, 1, dash_power, dash_dir.degree(), my_pos, my_pos.dist(ball_next), stamina_model.stamina()) dlog.add_text( Level.INTERCEPT, f"self pred one dash adjust Success! " f"power={info.dash_power()}, " f"rel_dir={info.dash_angle()}, " f"angle={dash_angle.degree()}" f"my_pos={my_pos}" f"ball_dist={info.ball_dist()}" f"stamina={stamina_model.stamina()}") return True
def effort(self): # TODO update effort return SP.i().effort_init()
def predict_no_dash(self, self_cache) -> bool: SP = ServerParam.i() wm: WorldModel = self._wm me: PlayerObject = wm.self() my_next: Vector2D = me.pos() + me.vel() ball_next: Vector2D = wm.ball().pos() + wm.ball().vel() goalie_mode: bool = self.is_goalie_mode(ball_next) control_area: float = me.player_type().catchable_area() if \ goalie_mode else \ me.player_type().kickable_area() next_ball_rel: Vector2D = (ball_next - my_next).rotated_vector( -me.body()) # WHAT THE FUUCKKKK ball_noise: float = wm.ball().vel().r() * SP.ball_rand() next_ball_dist: float = next_ball_rel.r() # out of control area if next_ball_dist > control_area - 0.15 - ball_noise: dlog.add_text(Level.INTERCEPT, "self pred no dash out of control area") return False # if goalie immediately success if goalie_mode: stamina_model: StaminaModel = me.stamina_model() stamina_model.simulate_wait(me.player_type()) self_cache.append( InterceptInfo(InterceptInfo.Mode.NORMAL, 1, 0, 0, 0, my_next, next_ball_dist, stamina_model.stamina())) dlog.add_text(Level.INTERCEPT, "self pred no dash goalie mode success") return True # check kick effectiveness ptype: PlayerType = me.player_type() if next_ball_dist > ptype.player_size() + SP.ball_size(): kick_rate: float = ptype.kick_rate(next_ball_dist, next_ball_rel.th().degree()) next_ball_vel: Vector2D = wm.ball().vel() * SP.ball_decay() if SP.max_power() * kick_rate <= next_ball_vel.r() * SP.ball_decay( ) * 1.1: dlog.add_text( Level.INTERCEPT, "self pred no dash kickable, but maybe not control") return False # at least, player can stop the ball stamina_model = me.stamina_model() self_cache.append( InterceptInfo( InterceptInfo.Mode.NORMAL, 1, 0, # 1 turn 0, 0, my_next, next_ball_dist, stamina_model.stamina())) dlog.add_text(Level.INTERCEPT, "self pred no dash success") return True
def is_goalie_mode(self, ball_next) -> bool: wm = self._wm return wm.self().goalie() and \ wm.last_kicker_side() != wm.our_side() and \ ball_next.x() < ServerParam.i().our_penalty_area_line_x() and \ ball_next.absY() < ServerParam.i().penalty_area_half_width()