Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from math import *
- from model.FireType import FireType
- from model.TankType import TankType
- from model.BonusType import BonusType
- from model.ShellType import ShellType
- from model.Unit import Unit
- # some geometry for simple interset detection
- class Vec2D:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- def dot(self, vec2d):
- return self.x*vec2d.x + self.y*vec2d.y
- def squaredLength(self):
- return self.x*self.x + self.y*self.y
- def intr_line_2_circle(origin, direction, center, squaredRadius):
- diff = Vec2D(origin.x - center.x, origin.y - center.y)
- a0 = diff.squaredLength() - squaredRadius
- a1 = direction.dot(diff)
- discr = a1*a1 - a0
- if discr < 0.0:
- return False
- return True
- def ray_test_unit_angle(origin, angle, u):
- line_origin = Vec2D(origin.x, origin.y)
- line_dir = Vec2D(cos(angle), sin(angle))
- cir_center = Vec2D(u.x, u.y)
- cir_rr = (u.width*u.width)/4
- return intr_line_2_circle(line_origin,line_dir,cir_center,cir_rr)
- #def ray_test_unit_point(p1, p2, u):
- # line_origin = Vec2D(origin.x, origin.y)
- # line_dir = Vec2D(cos(angle), sin(angle))
- # cir_center = Vec2D(u.x, u.y)
- # cir_rr = (u.width*u.width + u.height*u.height)/2
- # return intr_line_2_circle(line_origin,line_dir,cir_center,cir_rr)
- def normalize_angle(angle):
- while angle > pi:
- angle -= 2.0 * pi
- while angle < -pi:
- angle += 2.0 * pi
- return angle
- class Line2D:
- def __init__(self, a,b,c):
- self.a = a;
- self.b = b;
- self.c = c;
- def point_in_rect(p, p1,p2):
- eps = 0.000001
- res = (fabs(p.x -min(p1.x, p2.x)) < eps or min(p1.x, p2.x) <= p.x) \
- and (fabs(max(p1.x, p2.x) - p.x) < eps or max(p1.x, p2.x)>=p.x) \
- and (fabs(p.y - min(p1.y, p2.y)) < eps or min(p1.y, p2.y)<=p.y) \
- and (fabs(max(p1.y, p2.y) - p.y) < eps or max(p1.y, p2.y)>=p.y)
- return res
- def to_line(p1, p2):
- a = p2.y - p1.y
- b = p1.x - p2.x
- return Line2D(a,b, -a*p1.x - b*p1.y)
- def is_parallel_line(l1,l2):
- return fabs(l1.a*l2.b - l2.a*l1.b) <=0.00001
- def is_equal_line(l1,l2):
- is_equal = fabs(l1.a*l2.b - l2.a*l1.b) <=0.00001 \
- and fabs(l1.a*l2.c - l2.a*l1.c) <=0.00001 \
- and fabs(l1.b*l2.c - l2.b*l1.c) <=0.00001
- return is_equal
- def cross_line(l1, l2, p):
- if is_parallel_line(l1,l2): return 2
- if is_equal_line(l1,l2): return 0
- p.x = (l2.b * l1.c - l1.b * l2.c) / (l2.a * l1.b - l1.a * l2.b);
- if (l1.b !=0):
- p.y = (- l1.c - l1.a * p.x) / l1.b
- else:
- p.y = (- l2.c - l2.a * p.x) / l2.b
- return 1
- def cross_segment_line(p1, p2, l, p):
- t = to_line(p1,p2)
- res = cross_line(l,t,p)
- if not point_in_rect(p,p1,p2):res = 0
- return res
- #======================== end of geometry
- def shell_test_path(shell, startPos, endPos):
- #r = 40
- sx = shell.x + shell.x*cos(shell.angle)
- sy = shell.y + shell.y*sin(shell.angle)
- l = to_line(Vec2D(shell.x, shell.y), Vec2D(sx,sy))
- p = Vec2D(0,0)
- res = cross_segment_line(startPos, endPos, l, p)
- print(res, p.x, p.y)
- ######################################################################
- ######################################################################
- ######################################################################
- def get_dangerous(x, y, enemy_tanks, shells):
- tank_koeff_dangerous = 0.0
- shell_koeff_dangerous = 0.0
- koeff_dist = 0.0
- koeff_angle = 0.0
- max_dist = hypot(1280, 800)
- for t in enemy_tanks:
- koeff_dist=1-(t.get_distance_to(x,y)/max_dist)
- koeff_angle= cos(t.get_turret_angle_to(x,y))
- #koeff_angle= 1
- tank_koeff_dangerous += koeff_dist*koeff_angle*t.crew_health/t.crew_max_health
- for s in shells:
- koeff_dist=1-(s.get_distance_to(x,y)/max_dist)
- koeff_angle=cos(s.get_angle_to(x,y))
- koeff_angle=1
- shell_koeff_dangerous+= koeff_dist*koeff_angle
- return tank_koeff_dangerous*shell_koeff_dangerous
- def get_usefullness(x,y, bonuses):
- koeff_dist = 0.0
- max_dist = hypot(1280, 800)
- for b in bonuses:
- koeff_dist+=1-(b.get_distance_to(x,y)/max_dist)
- return koeff_dist
- def get_min_dangerous_for(x, y, r, enemy_tanks, shells):
- test_points = []
- for ang in range(0,360,45):
- tx = x+r*cos(ang*pi/180)
- ty = y+r*sin(ang*pi/180)
- if (tx < 50) or (tx > 1230):tx=x
- if (ty < 50) or (ty > 750):ty = y
- dangerous = get_dangerous(tx,ty, enemy_tanks, shells)
- test_points.append([tx,ty,dangerous])
- test_points = sorted(test_points, key = lambda dangerous:dangerous[2])
- res = [test_points[0]]+[p for p in test_points[1:] if (fabs(test_points[0][0]-p[0]) > 0.0001) and (fabs(test_points[0][1]-p[1]))>0.0001]
- #test center point
- ## cnt = 0
- ## test_unit = create_unit(x,y,80,80)
- ## # cnt = 0 k = 1
- ## for s in shells:
- ## for p in res:
- ## if (p[0]-x > 0.00001) and (p[1]-y > 0.00001)
- ## ray_test_unit_angle(s, s.angle,test_unit)
- ## #print("test points = ", test_points )
- #print("res points = ", res )
- return res
- ######################################################################
- ######################################################################
- ######################################################################
- #=================================================================================
- # game info
- def get_live_enemy_tanks(tanks):
- return [tank for tank in tanks if (tank.crew_health > 0 and tank.hull_durability > 0) and not tank.teammate]
- def get_dead_tanks(tanks):
- return [tank for tank in tanks if not (tank.crew_health > 0 and tank.hull_durability > 0)]
- def get_team_tanks(tanks, me_id):
- return [tank for tank in tanks if (tank.crew_health > 0 and tank.hull_durability > 0) and tank.teammate and tank.id != me_id]
- def get_enemy_shells(shells, name):
- return [shell for shell in shells if shell.player_name != name]
- def get_bonus_list(bonuses, bonus_type):
- return [b for b in bonuses if b.type == bonus_type]
- def get_nearest(target_unit, units):
- if (len(units)):
- min_dist_unit = units[0];
- min_dist = target_unit.get_distance_to_unit(min_dist_unit)
- for u in units[1:]:
- dist = target_unit.get_distance_to_unit(u)
- if dist < min_dist:
- min_dist_unit = u
- min_dist = dist
- return (min_dist_unit, min_dist)
- else:
- return (None,-1);
- def test_obstacles(me, target, obstacles):
- angle_to_enemy = me.get_angle_to_unit(target) + me.angle
- for o in obstacles:
- angle_to_obstacle = me.get_angle_to_unit(o) + me.angle
- if (fabs(angle_to_enemy - angle_to_obstacle) < pi/4):
- dist_to_enemy = me.get_distance_to_unit(target)
- dist_to_obstacle = me.get_distance_to_unit(o)
- if (dist_to_enemy > dist_to_obstacle):
- #if ray_test_unit_angle(Vec2D(me.x,me.y), 2*pi-angle_to_enemy, o):
- if ray_test_unit_angle(Vec2D(me.x,me.y), angle_to_enemy, o):
- return True
- return False
- def get_premium_shells(shells):
- return [s for s in shells if s.type == ShellType.PREMIUM]
- def create_point_unit(x,y):
- return Unit(-1,0,0,x,y,0,0,0,0)
- def create_unit(x,y,w,h,angle):
- return Unit(-1,w,h,x,y,0,0,angle,0)
- class Point:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- class StrategyState:
- CORNER_DEF = 0
- SIMPLE = 1
- MOVE_CORNER = 2
- BONUS_RIDE = 3
- USE_MAP = 4
- IN_DMG_ZONE = 5
- class MoveType:
- FRONT = 0
- BACK = 1
- TURN = 2
- def test_point(p, p0, r):
- return p0.get_distance_to_unit(p) < fabs(r)
- ##def write_list_2_file(inputList, w,h, outputFile):
- ## for i in range(0,w*h):
- ## if i%w==0 and i >= w: outputFile.write("\n");
- ## outputFile.write("%3.2f\t" % inputList[i])
- ## outputFile.write("\n");
- class MyStrategy:
- def __init__(self):
- self.state = StrategyState.USE_MAP
- self.enemy_list = []
- self.cnt = 5
- self.dange_map = []
- self.tank_map = []
- self.shell_map = []
- self.target = None
- self.dist_target = 0.0
- self.needed_bonus = None;
- self.medkit_bonus = None;
- self.repair_bonus = None;
- self.ammo_bonus = None;
- self.point_list = [];
- self.strategy_point = None;
- self.vis_bonuses = [];
- #self.point_list = [];
- def get_in_visible_area(self, me, world, eye_angle):
- visible_bonuses = []
- for b in world.bonuses:
- angle_b = me.get_turret_angle_to_unit(b)
- if fabs(angle_b) < eye_angle/2:
- dist_b = me.get_distance_to_unit(b)
- if dist_b < self.dist_target:
- visible_bonuses.append(b)
- return visible_bonuses
- def _test_tth(self, me, world, move):
- if (len(self.point_list) > 0):
- destPt = self.point_list[0];
- angleToPt = me.get_angle_to(destPt.x, destPt.y)
- if test_point(destPt, me, 40):
- self.point_list = self.point_list[1:]
- self.move_to_point(me, destPt, move)
- #print("move by point_list ", [destPt.x, destPt.y])
- else:
- if not test_point(self.strategy_point, me, 40):
- self.move_to_point(me, self.strategy_point, move)
- #print("move to strategy pt ", [self.strategy_point.x, self.strategy_point.y])
- elif self.target != None:
- move = self.turn_to_point(me, self.target, move)
- ## =============== rotate in corner =========
- #elif self.state == StrategyState.CORNER_DEF:
- # move = self.turn_to_point(me, create_point_unit(me.x ,world.height/2), move)
- return move
- ## def test_bullet_zone(self, me, world, bullets):
- ##
- ## if len(bullets) > 0:
- ## for s in bullets:
- ## shell_angle = s.get_angle_to(me.x, me.y)
- ## me_shell_angle = me.get_angle_to_unit(s)
- ## if fabs(shell_angle) < pi/10:
- ## if ray_test_unit_angle(Vec2D(s.x, s.y), -s.angle, me):
- ## row,col = get_unit_zone(me,world.width, world.height, self.cnt)
- ## self.dange_map[int(row*self.cnt+col)]+=3
- ## #print("pos dist = ", [me.x, me.y, s.x, s.y, dist] )
- ## #print("speed angle= ", [s.speedX, s.speedY, s.angle])
- def turn_to_point(self, me, position, move):
- angle = me.get_angle_to(position.x,position.y)
- if angle < -pi/24:
- move.left_track_power = -1.0
- move.right_track_power = 1.0*me.engine_rear_power_factor
- elif angle > pi/24:
- move.left_track_power = 1.0*me.engine_rear_power_factor
- move.right_track_power = -1.0
- return move
- def move_to_point(self, tank, destPoint, move):
- angle_to_point = tank.get_angle_to(destPoint.x, destPoint.y);
- if fabs(angle_to_point) < pi/2:
- if fabs(angle_to_point) < pi/4:
- move.left_track_power = 1;
- move.right_track_power = cos(fabs(angle_to_point));
- else:
- move.left_track_power = 1*tank.engine_rear_power_factor;
- move.right_track_power = -1;
- #print("turn front");
- else:
- if (pi - fabs(angle_to_point)) < pi/4:
- move.left_track_power = -1;
- move.right_track_power = -cos(pi-fabs(angle_to_point));
- #print("move full back = ", move.left_track_power, move.right_track_power);
- else:
- move.left_track_power = -1;
- move.right_track_power = 1*tank.engine_rear_power_factor;
- if (angle_to_point < 0):
- swp = move.left_track_power;
- move.left_track_power = move.right_track_power;
- move.right_track_power = swp;
- #print("move ", [move.left_track_power,move.right_track_power, angle_to_point])
- return move;
- def select_target(self, me, world):
- self.target, self.dist_target = None, 0.0
- open_candidates = []
- dead_tanks = get_dead_tanks(world.tanks)
- team_tanks = get_team_tanks(world.tanks, me.id)
- obstacles = world.bonuses + dead_tanks + team_tanks + world.obstacles
- for t in self.enemy_list:
- if not test_obstacles(me, t, obstacles):
- open_candidates.append(t)
- #print("enemy = {0} {1} {2}".format(world.tick, me.id, self.enemy_list))
- #print("open can = {0}".format(open_candidates))
- turret_candidates = []
- for t in open_candidates:
- angle_turret_target = t.get_turret_angle_to_unit(me)
- if fabs(angle_turret_target) < pi/12:
- turret_candidates.append(t)
- if (len(turret_candidates) > 0):
- self.target, self.dist_target = get_nearest(me, turret_candidates)
- if self.dist_target > 700:
- self.target, self.dist_target = get_nearest(me, open_candidates)
- else:
- self.target, self.dist_target = get_nearest(me, open_candidates)
- def strategy_attack(self, me, world, move):
- #self.select_target(me, world.tanks)
- self.select_target(me, world)
- if (self.target != None):
- turret_angle = me.get_turret_angle_to_unit(self.target)
- if turret_angle > pi/180:
- move.turret_turn = 1
- elif turret_angle < -pi/180:
- move.turret_turn = -1
- else:
- if (self.dist_target < 450):
- move.fire_type = FireType.PREMIUM_PREFERRED
- else:
- move.fire_type = FireType.REGULAR
- def get_bonus_info(self, tank, bonuses):
- medkit_list = get_bonus_list(bonuses, BonusType.MEDIKIT)
- self.medkit_bonus, dist_medkit = get_nearest(tank,medkit_list)
- repair_list = get_bonus_list(bonuses, BonusType.REPAIR_KIT)
- self.repair_bonus, dist_repair = get_nearest(tank,repair_list)
- ammo_list = get_bonus_list(bonuses, BonusType.AMMO_CRATE)
- self.ammo_bonus, dist_ammo = get_nearest(tank,ammo_list)
- def strategy_bonus(self, me, world):
- self.get_bonus_info(me, world.bonuses)
- needed_bonus = None
- if (me.crew_health/me.crew_max_health) < 0.6:
- needed_bonus = self.medkit_bonus
- elif (me.hull_durability/me.hull_max_durability) < 0.5:
- needed_bonus = self.repair_bonus
- else:
- needed_bonus = self.ammo_bonus
- if (needed_bonus == None and self.medkit_bonus != None):
- needed_bonus = self.medkit_bonus
- self.point_list = []
- if needed_bonus != None:
- enemy_shells = get_enemy_shells(world.shells, me.player_name)
- dist_bonus = me.get_distance_to_unit(needed_bonus)
- me_danger = get_dangerous(me.x, me.y, self.enemy_list, enemy_shells)
- bonus_danger = get_dangerous(needed_bonus.x, needed_bonus.y, self.enemy_list, enemy_shells)
- if ( dist_bonus < 250 or (needed_bonus.type == BonusType.MEDIKIT and (bonus_danger - me_danger < 0.5))) :
- self.point_list = [needed_bonus]
- elif (dist_bonus < 550):
- #print("bonus info", bonus_danger, me_danger)
- if bonus_danger - me_danger < 0.3:
- self.point_list = [needed_bonus]
- def select_strategy_point(self, me, world):
- if len(self.enemy_list)>3:
- corner_points = [create_point_unit(100,100), create_point_unit(world.width-100,100),
- create_point_unit(100,world.height-100), create_point_unit(world.width-100,world.height-100)]
- cp, cp_dist = get_nearest(me, corner_points)
- self.strategy_point = cp
- else:
- #print("cp ", [cp.x, cp.y])
- enemy_shells = get_enemy_shells(world.shells, me.player_name)
- if self.state == StrategyState.USE_MAP or self.state == StrategyState.IN_DMG_ZONE:
- dange_points = get_min_dangerous_for(me.x, me.y, 100, self.enemy_list, enemy_shells)
- dange_points = get_min_dangerous_for(dange_points[0][0], dange_points[0][1], 100, self.enemy_list, enemy_shells)
- dange_points = get_min_dangerous_for(dange_points[0][0], dange_points[0][1], 100, self.enemy_list, enemy_shells)
- #get_next_dangerous
- usefullness = []
- for p in dange_points:
- usefullness.append(get_usefullness(p[0], p[1], world.bonuses))
- #if world.tick%10==0:
- ## print("tick info ==== ", world.tick )
- ## print( me.x, me.y )
- ## print( list(zip(dange_points, usefullness)))
- self.strategy_point = create_point_unit(dange_points[0][0],dange_points[0][1])
- if len(dange_points)>1:
- if (usefullness[0] < usefullness[1]):
- self.strategy_point = create_point_unit(dange_points[1][0],dange_points[1][1])
- ## ## if test_point(self.strategy_point, me, 40):
- ## for es in enemy_shells:
- ## if ray_test_unit_angle(Vec2D(es.x, es.y), es.angle, me):
- ## shell_test_path(es, Vec2D(me.x, me.y), self.strategy_point)
- ## if world.tick%10==0:
- ## print("alarm", world.tick, [self.strategy_point.x, self.strategy_point.y], [me.speedX, me.speedY])
- def move(self, me, world, move):
- self.enemy_list = get_live_enemy_tanks(world.tanks)
- self.state = StrategyState.USE_MAP
- enemy_shells = get_enemy_shells(world.shells, me.player_name)
- self.strategy_bonus(me, world)
- self.select_strategy_point(me, world)
- ## if (len(enemy_shells) > 0 and world.tick%5==0):
- ## print([enemy_shells[0].id, world.tick])
- ## a = open("log.txt", "a")
- ## a.write("=============== Tick {0} =============== \n".format(world.tick))
- ## write_list_2_file(self.dange_map.field, ws,hs, a)
- ## a.write("=============== SP [{0}, {1}] [{2}, {3}]=============== \n".format(self.strategy_point.x, self.strategy_point.y, me.x, me.y))
- ## a.close()
- move = self._test_tth(me, world, move)
- self.strategy_attack(me, world, move)
- def select_tank(self, tank_index, team_size):
- return TankType.MEDIUM
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement