Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import sys
- import math
- import itertools
- def log(to_log, newline=True):
- print(to_log, file=sys.stderr, flush=True, end='\n' if newline else '')
- class UnitType:
- REAPER = 0
- DESTROYER = 1
- DOOF = 2
- TANKER = 3
- WRECK = 4
- class Point():
- def __init__(self, x, y):
- self.x = x
- self.y = y
- class Entity(Point):
- def __init__(self, id, x, y, player):
- super().__init__(x, y)
- self.id = id
- self.player = player
- def update(self, vx, vy, mass, r, extra, extra2):
- self.vx = vx
- self.vy = vy
- self.mass = mass
- self.r = r
- self.next_pos = (self.x + self.vx, self.y + self.vy)
- self.extra = extra
- self.extra2 = extra2
- class Reaper(Entity):
- def __init__(self, id, x, y, player):
- super().__init__(id, x, y, player)
- self.mass = 0.5
- self.friction = 0.2
- class Destroyer(Entity):
- def __init__(self, id, x, y, player):
- super().__init__(id, x, y, player)
- self.mass = 1.5
- self.friction = 0.3
- class Tanker(Entity):
- def __init__(self, id, x, y, player):
- super().__init__(id, x, y, player)
- self.mass = 2.5
- self.friction = 0.4
- class Doof(Entity):
- def __init__(self, id, x, y, player):
- super().__init__(id, x, y, player)
- self.mass = 1
- self.friction = 0.25
- class Wreck(Entity):
- def __init__(self, id, x, y, player):
- super().__init__(id, x, y, player)
- def magic_formula(x, y, vx, vy):
- return int(x - 1.5 * vx), int(y - 1.5 * vy)
- def get_closest(entity, entities):
- closest = None
- best = sys.maxsize
- for e in entities:
- dist = distance2(e, entity)
- if dist < best:
- closest = e
- best = dist
- return closest
- def distance(e1, e2):
- return distance_coord(e1.x, e2.x, e1.y, e2.y)
- def distance2(e1, e2):
- return distance_coord2(e1.x, e2.x, e1.y, e2.y)
- def distance_coord(x1, x2, y1, y2):
- return math.sqrt(distance_coord2(x1, x2, y1, y2))
- def distance_coord2(x1, x2, y1, y2):
- return (x2 - x1) ** 2 + (y2 - y1) ** 2
- def is_in_range(coord, entities):
- return any(distance_coord(e.x, coord[0], e.y, coord[1]) <= e.r for e in entities)
- def find_overlaps(entities):
- overlaps = []
- for i, j in itertools.combinations(entities, 2):
- log(distance_coord(i.x, j.x, i.y, j.y))
- log(i.r+j.r)
- if distance_coord(i.x, j.x, i.y, j.y) < i.r+j.r:
- overlaps.append((i, j))
- log(overlaps)
- return overlaps
- class Player():
- def __init__(self):
- pass
- def play(self):
- # game loop
- while True:
- self.my_units = []
- self.their_units = []
- self.wrecks = []
- self.tankers = []
- my_score = int(input())
- enemy_score_1 = int(input())
- enemy_score_2 = int(input())
- my_rage = int(input())
- enemy_rage_1 = int(input())
- enemy_rage_2 = int(input())
- unit_count = int(input())
- for i in range(unit_count):
- unit_id, unit_type, player, mass, r, x, y, vx, vy, extra, extra_2 = input().split()
- unit_id = int(unit_id)
- unit_type = int(unit_type)
- player = int(player)
- mass = float(mass)
- r = int(r)
- x = int(x)
- y = int(y)
- vx = int(vx)
- vy = int(vy)
- extra = int(extra)
- extra_2 = int(extra_2)
- if unit_type == UnitType.REAPER:
- e = Reaper(unit_id, x, y, player)
- elif unit_type == UnitType.TANKER:
- e = Tanker(unit_id, x, y, player)
- elif unit_type == UnitType.DOOF:
- e = Doof(unit_id, x, y, player)
- elif unit_type == UnitType.DESTROYER:
- e = Destroyer(unit_id, x, y, player)
- else:
- e = Wreck(unit_id, x, y, player)
- e.update(vx, vy, mass, r, extra, extra_2)
- if player == 0:
- self.my_units.append(e)
- if isinstance(e, Reaper):
- my_reaper = e
- elif isinstance(e, Destroyer):
- my_destroyer = e
- elif isinstance(e, Doof):
- my_doof = e
- elif player == -1:
- if isinstance(e, Tanker):
- self.tankers.append(e)
- else:
- self.wrecks.append(e)
- else:
- self.their_units.append(e)
- stronger_opponent = 1 if enemy_score_1 > enemy_score_2 else 2
- # TODO - sort the reaper move by the gain in X number of moves - so you would not leave one wreck for another etc
- reaper_target = self.find_best_wreck_overlap()
- if reaper_target is None and len(self.wrecks) > 0:
- reaper_target = self.find_best_wreck(my_reaper)
- tankers_inside = list(filter(lambda t: distance_coord(0, t.next_pos[0], 0, t.next_pos[1]) < 6000, self.tankers))
- is_reaper_target_tanker = False
- if reaper_target is None and len(tankers_inside) > 0:
- max_values = [x for x in tankers_inside if x.extra == max(map(lambda t:t.extra, tankers_inside))]
- reaper_target = get_closest(my_destroyer, max_values)
- is_reaper_target_tanker = True
- # Reaper move
- if reaper_target is not None:
- print("{0} {1} {2}".format(*magic_formula(reaper_target.x, reaper_target.y, my_reaper.vx, my_reaper.vy), 300))
- else:
- print("{0} {1} {2}".format(my_destroyer.x, my_destroyer.y, 300))
- stronger_opp_reaper = next(filter(lambda e: isinstance(e, Reaper) and e.player == stronger_opponent, self.their_units))
- # Destroyer move
- if reaper_target is not None and is_reaper_target_tanker:
- print("{0} {1} {2}".format(*magic_formula(*reaper_target.next_pos, my_destroyer.vx, my_destroyer.vy), 300))
- # TODO don't spam spell in the same place
- elif stronger_opp_reaper is not None:
- if distance_coord(my_destroyer.x, my_destroyer.y, stronger_opp_reaper.next_pos[0], stronger_opp_reaper.next_pos[1]) < 3400 and my_rage > 60:
- print("{0} {1} {2}".format("SKILL", *stronger_opp_reaper.next_pos))
- else:
- print("{0} {1} {2}".format(*magic_formula(*stronger_opp_reaper.next_pos, my_destroyer.vx, my_destroyer.vy), 300))
- else:
- print("WAIT")
- # Doof move
- # closest_opp_reaper = get_closest(my_destroyer, filter(lambda e: isinstance(e, Reaper), self.their_units))
- if stronger_opp_reaper is not None:
- if distance(my_doof, stronger_opp_reaper) < 3400 and my_rage > 30 and is_in_range(stronger_opp_reaper.next_pos, self.wrecks):
- print("{0} {1} {2}".format("SKILL", *stronger_opp_reaper.next_pos))
- else:
- print("{0} {1} {2}".format(*magic_formula(*stronger_opp_reaper.next_pos, my_doof.vx, my_doof.vy), 300))
- else:
- print("WAIT")
- def find_best_wreck(self, my_reaper):
- closest_wreck = get_closest(my_reaper, self.wrecks)
- # TODO - remove once we have better move sorting
- # don't leave a wreck we are already close to
- if distance(my_reaper, closest_wreck) < closest_wreck.r + 600:
- return closest_wreck
- max_values = [x for x in self.wrecks if x.extra == max(map(lambda t: t.extra, self.wrecks))]
- return get_closest(my_reaper, max_values)
- def find_best_wreck_overlap(self):
- overlaps = find_overlaps(self.wrecks)
- # wreck overlap with most water
- reaper_target = None
- if len(overlaps) > 0:
- max_overlap = max(overlaps, key=lambda o : o[0].extra + o[1].extra)
- log(max_overlap)
- w1 = max_overlap[0]
- w2 = max_overlap[1]
- # NB! this is midpoint between the wrecks, this does not work if the circles are of very different size
- reaper_target = Point((w1.x + w2.x) / 2, (w1.y + w2.y) / 2)
- return reaper_target
- if __name__ == '__main__':
- p = Player()
- p.play()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement