main.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import sys
  2. import math
  3. import time
  4. debug = True
  5. t0 = time.time()
  6. def log(*msg):
  7. if debug:
  8. print("{} - ".format(str(time.time() - t0)[1:5]), *msg, file=sys.stderr, flush=True)
  9. def time_to(total, step):
  10. """ number of steps to reach total """
  11. return total // step + (1 if total % step > 0 else 0)
  12. class BaseClass:
  13. def __repr__(self):
  14. return f"<{self.__class__.__name__}: {self.__dict__}>"
  15. class Player(BaseClass):
  16. def __init__(self, id_):
  17. self.id = id_
  18. ME = Player(int(input())) # Input gives the player id: 0 plays first
  19. OPPONENT = Player(1 - ME.id)
  20. PLAYERS_INDEX = {p.id: p for p in [ME, OPPONENT]}
  21. PLAYERS_ORDER = sorted([ME, OPPONENT], key=lambda p: p.id)
  22. class Unit(BaseClass):
  23. TYPE_CULTIST = 0
  24. TYPE_CULT_LEADER = 1
  25. OWNER_0 = 0
  26. OWNER_1 = 1
  27. NO_OWNER = 2
  28. SHOOTING_RANGE = 6
  29. SHOOTING_MAX_DAMAGE = 7
  30. def __init__(self, id_):
  31. self.id = id_
  32. self.hp = 10
  33. self.x = None
  34. self.y = None
  35. self.owner = None
  36. @property
  37. def owned(self):
  38. return self.owner == ME.id
  39. @property
  40. def opponent(self):
  41. return self.owner == OPPONENT.id
  42. @property
  43. def neutral(self):
  44. return self.owner == self.NO_OWNER
  45. class CultLeader(Unit):
  46. pass
  47. class Grid(BaseClass):
  48. def __init__(self, width, height):
  49. self.width = width
  50. self.height = height
  51. self.obstacles = []
  52. self.index = {}
  53. self.units = {}
  54. self.round = 0
  55. def update_unit(self, id_, type_, hp, x, y, owner):
  56. if id_ not in self.units:
  57. self.units[id_] = Unit(id_) if type_ != Unit.TYPE_CULT_LEADER else CultLeader(id_)
  58. unit = self.units[id_]
  59. unit.hp = hp
  60. unit.x = x
  61. unit.y = y
  62. unit.owner = owner
  63. def update_index(self):
  64. self.index = {}
  65. for unit in self.units:
  66. self.index[(unit.x, unit.y)] = unit
  67. def in_grid(self, pos):
  68. return 0 <= pos[0] < self.width and 0 <= pos[1] < self.height
  69. def can_see_trough(self, pos):
  70. return self.in_grid(pos) and pos not in self.obstacles + list(self.index.values())
  71. def can_move_on(self, pos):
  72. return self.in_grid(pos) and pos not in self.obstacles + list(self.index.values())
  73. @staticmethod
  74. def manhattan(from_, to_):
  75. xa, ya = from_
  76. xb, yb = to_
  77. return abs(xa - xb) + abs(ya - yb)
  78. @classmethod
  79. def line(cls, from_, to_):
  80. """ Implementation of bresenham's algorithm """
  81. xa, ya = from_
  82. xb, yb = to_
  83. if (xa, ya) == (xb, yb):
  84. return [(xa, ya)]
  85. # diagonal symmetry
  86. vertically_oriented = (abs(yb - ya) > abs(xb - xa))
  87. if vertically_oriented:
  88. ya, xa, yb, xb = xa, ya, xb, yb
  89. # horizontal symmetry
  90. reversed_sym = (xa > xb)
  91. if reversed_sym:
  92. xb, yb, xa, ya = xa, ya, xb, yb
  93. # angle
  94. dx, dy = xb - xa, yb - ya
  95. alpha = (abs(dy) / dx)
  96. offset = 0.0
  97. step = 1 if dy > 0 else -1
  98. result = []
  99. y_ = ya
  100. for x_ in range(xa, xb + 1):
  101. result.append((y_, x_) if vertically_oriented else (x_, y_))
  102. offset += alpha
  103. if offset > 0.5:
  104. y_ += step
  105. offset -= 1.0
  106. if reversed_sym:
  107. result.reverse()
  108. return result
  109. # Create grid
  110. GRID = Grid(*[int(i) for i in input().split()])
  111. GRID.obstacles = [(i, j) for i in range(GRID.height) for j, val in enumerate(input()) if val == 'x']
  112. class Action(BaseClass):
  113. pass
  114. class ActionWait(Action):
  115. def exec(self):
  116. print("WAIT")
  117. class ActionMove(Action):
  118. def exec(self, id_, pos):
  119. x, y = pos
  120. print(f"{id_} MOVE {x} {y}")
  121. class ActionShoot(Action):
  122. def exec(self, id_, target_id):
  123. print(f"{id_} SHOOT {target_id}")
  124. class ActionConvert(Action):
  125. def exec(self, id_, target_id):
  126. print(f"{id_} CONVERT {target_id}")
  127. while 1:
  128. for _ in range(int(input())):
  129. GRID.update_unit(*[int(j) for j in input().split()])
  130. GRID.update_index()
  131. log(GRID.units)
  132. GRID.round += 1