Advertisement
philRG

Fantastic bits (Silver)

Apr 3rd, 2022
735
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.45 KB | None | 0 0
  1. import sys
  2. import math
  3. from inspect import currentframe
  4. import numpy
  5. import time
  6. from numpy import array
  7.  
  8.  
  9. class DebugTool:
  10.     def __init__(self):
  11.         try:
  12.             self.fd = open(r"/Users/display/PycharmProjects/Fantastic-Bits/input.txt")
  13.         except (ImportError, OSError):
  14.             self.debug_mode = False
  15.         else:
  16.             import matplotlib.pyplot as plt
  17.             self.plt = plt
  18.             self.fg = None
  19.             self.ax = None
  20.             self.debug_mode = True
  21.  
  22.     def input(self):
  23.         if self.debug_mode:
  24.             data = self.fd.readline()
  25.         else:
  26.             data = input()
  27.         print(data, file=sys.stderr, flush=True)
  28.         return data
  29.  
  30.     def start_timer(self):
  31.         self.timer = time.time()
  32.  
  33.     def elapsed_time(self):
  34.         end_time = time.time()
  35.         interval = end_time - self.timer
  36.         self.stderr(interval * 1000, "m sec")
  37.  
  38.     @staticmethod
  39.     def stderr(*args):
  40.         cf = currentframe()
  41.         print(*args, "@" + str(cf.f_back.f_lineno), file=sys.stderr, flush=True)
  42.  
  43.     def plot_vector_clock(self, vct, clr="b", txt=""):
  44.         # todo: refactor in OO style
  45.         self.plt.plot((0, vct[0]), (0, vct[1]), color=clr)
  46.         self.plt.text(vct[0], vct[1], txt)
  47.  
  48.  
  49. class Entity:
  50.     def __init__(self, entity_id, entity_type, x, y, vx, vy, state):
  51.         self.entity_id = int(entity_id)
  52.         self.entity_type = str(entity_type)
  53.         self.x = int(x)
  54.         self.y = int(y)
  55.         self.location = array([self.x, self.y])
  56.         self.vx = int(vx)
  57.         self.vy = int(vy)
  58.         self.velocity = array([self.vx, self.vy])
  59.         self.state = int(state)
  60.  
  61.         self.command = ""
  62.         self.target = None  # type: Entity
  63.         self.magic_cost = 0
  64.         self.obliviate_effect = 0
  65.  
  66.     def __lt__(self, other):
  67.         return self.entity_id < other.entity_id
  68.  
  69.     def throw(self):
  70.         # always shoot to the mid of the goal
  71.         self.command = "THROW {0} {1} {2}".format(opp_goal_x, int(FIELD_LENGTH_Y / 2), 500)
  72.  
  73.     def thrust_to(self, x, y, thrust=150):
  74.         self.command = "MOVE {0} {1} {2}".format(x, y, thrust)
  75.  
  76.     def move_to_target(self):
  77.         self.thrust_to(*(self.target.location + self.target.velocity - self.velocity))
  78.  
  79.     def accio_to_target(self):
  80.         self.command = "ACCIO {0}".format(self.target.entity_id)
  81.         self.magic_cost = 20
  82.  
  83.     def predict_distance(self, ent):
  84.         return numpy.linalg.norm((ent.predict_location()) - (self.predict_location()))
  85.  
  86.     def predict_location(self):
  87.         vctr = self.vector_of_command()
  88.         return self.location + self.velocity + vctr
  89.  
  90.     def set_throw_target(self, snaffles, wizards, role="ALL"):
  91.         # NEW LOGIC PENDING
  92.         # distance_list=[] # type:list[int, Entity]
  93.         # for wiz in wizards:
  94.         #     distance_list.append(wiz.list_distance(snaffles))
  95.  
  96.         if len(snaffles) == 1:
  97.             self.target = snaffles[0]
  98.         else:
  99.             # remove snaffles already targeted
  100.             snfls = [snf for snf in snaffles if snf not in [wiz.target for wiz in wizards]]
  101.  
  102.             # filter snaffles by field position
  103.             if role == "FWD":
  104.                 snfls1 = [snf for snf in snfls if abs(snf.x - opp_goal_x) <= (FIELD_LENGTH_X * 1 / 4)]
  105.                 if snfls1:
  106.                     snfls = snfls1
  107.             elif role == "BACK":
  108.                 snfls1 = [snf for snf in snfls if abs(snf.x - opp_goal_x) > (FIELD_LENGTH_X * 1 / 4)]
  109.                 if snfls1:
  110.                     snfls = snfls1
  111.             # set target closest one as in next turn
  112.             self.target = min([[snf.predict_distance(self), snf] for snf in snfls])[1]
  113.  
  114.     def command_for_throw(self, opponents):
  115.         # use ACCIO if condition below matched
  116.         # distance to target, distance opponent to target, direction of target, spell_gauge
  117.         if (self.predict_distance(self.target) >
  118.                 min(min([opp.predict_distance(self.target) for opp in opponents]), 4000)) \
  119.                 and abs(self.target.x - opp_goal_x) > abs(self.x - opp_goal_x) \
  120.                 and magic_gauge > 20 + 20:
  121.             self.accio_to_target()
  122.         else:
  123.             self.move_to_target()
  124.  
  125.     def dodge_bludgers(self, bludgers):
  126.         close_bld_dist = min([[self.predict_distance(bld), bld] for bld in bludgers])
  127.         if close_bld_dist[0] < BLUDGER_SIZE + WIZARD_SIZE:
  128.             bld = close_bld_dist[1]  # type: Entity
  129.             direction = self.predict_location() - bld.predict_location()
  130.             norm = numpy.linalg.norm(direction)
  131.             dodge_vector = direction / norm * ((BLUDGER_SIZE + WIZARD_SIZE) * 2 - close_bld_dist[0])
  132.             print(dodge_vector, file=sys.stderr)
  133.  
  134.             # adjust if move command already ordered
  135.             dodge_vector += self.vector_of_command()
  136.             print(dodge_vector, file=sys.stderr)
  137.             print(self.vector_of_command(), file=sys.stderr)
  138.  
  139.             self.thrust_to(int(dodge_vector[0]), int(dodge_vector[1]), min(int(numpy.linalg.norm(dodge_vector)), 150))
  140.  
  141.             print("{0}, {1}, {2}".format(dodge_vector[0], dodge_vector[1],
  142.                                          int(numpy.linalg.norm(dodge_vector))), file=sys.stderr)
  143.  
  144.     def vector_of_command(self):
  145.         cmd_list = self.command.split()
  146.         if len(cmd_list) > 0 and cmd_list[0] == "MOVE":
  147.             direction = array([int(cmd_list[1]), int(cmd_list[2])]) - self.location
  148.             norm = numpy.linalg.norm(direction)
  149.             vector = direction / norm * int(cmd_list[3])
  150.             # print(self.entity_id, file=sys.stderr)
  151.             # print(cmd_list, file=sys.stderr)
  152.             # print(numpy.linalg.norm(vector), file=sys.stderr)
  153.         else:
  154.             vector = array([0, 0])
  155.         return vector
  156.  
  157.     def obliviate_bludgers(self, bludgers):
  158.         close_bld_dist = min([[self.predict_distance(bld), bld] for bld in bludgers])
  159.         print(close_bld_dist[0], file=sys.stderr)
  160.         if self.obliviate_effect <= 0 and close_bld_dist[0] < (BLUDGER_SIZE + WIZARD_SIZE) * 2 and magic_gauge > 20 + 5:
  161.             self.command = "OBLIVIATE {0}".format(close_bld_dist[1].entity_id)
  162.             self.magic_cost = 5
  163.             self.obliviate_effect = 3
  164.         else:
  165.             self.obliviate_effect -= 1
  166.             self.dodge_bludgers(bludgers)
  167.  
  168.     def is_obstacle(self, start, end, size1=0, size2=0):
  169.         vctr1 = array(end - start)
  170.         vctr2 = array(self.location - start)
  171.         distance = abs(numpy.cross(vctr1, vctr2) / numpy.linalg.norm(vctr1))
  172.         if distance <= size1 + size2:
  173.             return True
  174.  
  175.     def search_flipendo_target(self, snaffles, obstruct):
  176.         # able to goal or not
  177.         if magic_gauge > 20 + 20:
  178.             for snf in snaffles:
  179.                 vctr = ((snf.predict_location() - self.predict_location()) *
  180.                         (opp_goal_x - self.predict_location()[0]) / (
  181.                             snf.predict_location()[0] - self.predict_location()[0]))
  182.  
  183.                 print(snf.entity_id, vctr, self.predict_location(), file=sys.stderr)
  184.                 print(snf.predict_location() - self.predict_location(),
  185.                       int((opp_goal_x - self.predict_location()[0]) / (
  186.                           snf.predict_location()[0] - self.predict_location()[0])),
  187.                       self.predict_location()[1] + vctr[1],
  188.                       file=sys.stderr)
  189.  
  190.                 if TOP_GOAL_Y < self.predict_location()[1] + vctr[1] < BOTTOM_GOAL_Y \
  191.                         and (opp_goal_x - self.predict_location()[0]) / (
  192.                                     snf.predict_location()[0] - self.predict_location()[0]) > 0 \
  193.                         and self.predict_distance(snf) > 2000:
  194.                     if not [obs for obs in obstruct
  195.                             if obs.is_obstacle(self.predict_location(), self.predict_location() + vctr, 700)]:
  196.                         self.target = snf.entity_id
  197.                         return snf.entity_id
  198.         return None
  199.  
  200.     def flipend_to_target(self):
  201.         self.command = "FLIPENDO {0}".format(self.target)
  202.         self.magic_cost = 20
  203.  
  204.  
  205. def vector_size_of(vctr, size):
  206.     norm = numpy.linalg.norm(vctr)
  207.     return vctr / norm * size
  208.  
  209.  
  210. def output_command(list_of_entity):
  211.     for ent in list_of_entity:  # type:Entity
  212.         print(ent.command)
  213.  
  214.  
  215. DT = DebugTool()
  216.  
  217. # constants
  218. FIELD_LENGTH_X = 16001
  219. FIELD_LENGTH_Y = 7501
  220. LEFT_GOAL_X = 0
  221. RIGHT_GOAL_X = 16000
  222. TOP_GOAL_Y = int((FIELD_LENGTH_Y - 4000 + 300 + 150) / 2)
  223. BOTTOM_GOAL_Y = int(3750 + 4000 - 300 / 2 - 150 / 2)
  224. BLUDGER_SIZE = 200
  225. WIZARD_SIZE = 400
  226.  
  227. # global var
  228. magic_gauge = 0
  229. turn_count = 0
  230.  
  231. # game start
  232. my_team_id = int(DT.input())  # if 0 you need to score on the right of the map, if 1 , on the left
  233. if my_team_id == 0:
  234.     opp_goal_x = RIGHT_GOAL_X
  235.     my_goal_x = LEFT_GOAL_X
  236. else:
  237.     opp_goal_x = LEFT_GOAL_X
  238.     my_goal_x = RIGHT_GOAL_X
  239.  
  240. # game loop
  241. while True:
  242.     my_score, my_magic_point = map(int, DT.input().split())
  243.     opp_score, opp_magic_point = map(int, DT.input().split())
  244.     number_of_entities = int(DT.input())
  245.  
  246.     entities = []  # type:list[Entity]
  247.     for i in range(number_of_entities):  # type:int
  248.         entities.append(Entity(*(DT.input().split())))
  249.  
  250.     # WARNING! entity_id  NOT EQUAL to list index
  251.     wizs = [entity for entity in entities if entity.entity_type == "WIZARD"]
  252.     snfs = [entity for entity in entities if entity.entity_type == "SNAFFLE"]
  253.     blds = [entity for entity in entities if entity.entity_type == "BLUDGER"]
  254.     opps = [entity for entity in entities if entity.entity_type == "OPPONENT_WIZARD"]
  255.  
  256.     # choose forward
  257.     forward = max([[wiz.x, wiz] for wiz in wizs])[1]
  258.  
  259.     for wiz in wizs:
  260.         if wiz.state == 0:
  261.             if wiz.search_flipendo_target(snfs, blds + opps):
  262.                 wiz.flipend_to_target()
  263.             else:
  264.                 if wiz is forward:
  265.                     wiz.set_throw_target(snfs, wizs, "FWD")
  266.                 else:
  267.                     wiz.set_throw_target(snfs, wizs, "BACK")
  268.                 wiz.command_for_throw(opps)
  269.                 # wiz.obliviate_bludgers(blds)
  270.                 # wiz.dodge_bludgers(blds)
  271.  
  272.         else:
  273.             wiz.throw()
  274.  
  275.     # for debug, print(afo, file=sys.stderr)
  276.     print(magic_gauge, file=sys.stderr)
  277.  
  278.     output_command(wizs)
  279.     for wiz in wizs:
  280.         magic_gauge -= wiz.magic_cost
  281.     magic_gauge = min(magic_gauge + 1, 100)
  282.     turn_count += 1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement