script_ok_basic.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. '''
  2. @author: olivier.massot, 2019
  3. '''
  4. import heapq
  5. import itertools
  6. import sys
  7. def log(x):
  8. print(x, file=sys.stderr)
  9. # TODO: can I take ingredients not in order? If I can, find the shortest path trought all elements >> yes, but only one ingredient without a dish.
  10. # TODO: if partner on the way, wait if another path is 4+ cells longer
  11. # TODO: Should I tell wich I am doing to my partner?
  12. # TODO: When should I drop th plate on a table?
  13. # TODO: Check if a plate matching an order is already ready
  14. # TODO: don't take an order that is already taken by partner (how?)
  15. # Cells
  16. BLUEBERRIES_CRATE = "B"
  17. ICE_CREAM_CRATE = "I"
  18. WINDOW = "W"
  19. EMPTY_TABLE = "#"
  20. DISHWASHER = "D"
  21. FLOOR_CELL = "."
  22. # Items
  23. NONE = "NONE"
  24. DISH = "DISH"
  25. ICE_CREAM = "ICE_CREAM"
  26. BLUEBERRIES = "BLUEBERRIES"
  27. location = {DISH: DISHWASHER,
  28. ICE_CREAM: ICE_CREAM_CRATE,
  29. BLUEBERRIES: BLUEBERRIES_CRATE,
  30. WINDOW: WINDOW}
  31. class Base():
  32. def __repr__(self):
  33. return f"<{self.__class__.__name__}: {self.__dict__}>"
  34. class Customer(Base):
  35. def __init__(self, item, award):
  36. self.item = item
  37. self.award = int(award)
  38. class Cook(Base):
  39. def __init__(self, x, y, item):
  40. self.x = int(x)
  41. self.y = int(y)
  42. self.item = item
  43. self.order = ""
  44. @property
  45. def pos(self):
  46. return (self.x, self.y)
  47. def use(self, x, y, msg=""):
  48. print("USE", x, y, msg)
  49. def move(self, x, y):
  50. print("MOVE", x, y)
  51. class Table(Base):
  52. def __init__(self, x, y, item):
  53. self.x = int(x)
  54. self.y = int(y)
  55. self.item = item
  56. class Oven(Base):
  57. def __init__(self, contents, timer):
  58. self.contents = contents
  59. self.timer = int(timer)
  60. class NoPathFound(Exception):
  61. pass
  62. class PathNode(tuple):
  63. def __new__(self, x, y, parent=None):
  64. n = tuple.__new__(self, (x, y))
  65. n.parent = parent
  66. n.cost = 0
  67. return n
  68. class Grid(Base):
  69. def __init__(self, cells):
  70. self.cells = cells
  71. self.w, self.h = len(cells[0]), len(cells)
  72. def at(self, x, y):
  73. return self.cells[y][x]
  74. def is_in(self, x, y):
  75. try:
  76. self.at(x, y)
  77. return True
  78. except IndexError:
  79. return False
  80. def flatten(self):
  81. return [(x, y, c) for y, row in enumerate(self.cells) for x, c in enumerate(row)]
  82. def where_are(self, content):
  83. return [(x, y) for x, y, c in self.flatten() if c == content]
  84. def is_passable(self, x, y):
  85. return self.at(x, y) in (FLOOR_CELL, "0", "1")
  86. def closest(self, from_, content):
  87. return min(self.where_are(content), key=lambda k: (abs(from_[0] - k[0]) + abs(from_[1] - k[1])))
  88. def neighbors(self, x, y):
  89. return [(xn, yn) for xn, yn in [(x - 1, y - 1), (x, y - 1), (x + 1, y - 1), \
  90. (x - 1, y), (x + 1, y) , \
  91. (x - 1, y + 1), (x, y + 1), (x + 1, y + 1)]
  92. if 0 <= xn <= self.w and 0 <= yn <= self.h]
  93. def path_to(self, origin, target):
  94. nodes = []
  95. origin = PathNode(*origin)
  96. heapq.heappush(nodes, (0, origin))
  97. while nodes:
  98. current = heapq.heappop(nodes)[1]
  99. if current == target:
  100. break
  101. for x, y in self.neighbors(*current):
  102. node = PathNode(x, y, current)
  103. if not self.is_passable(*node):
  104. continue
  105. node.cost = current.cost + 1
  106. priority = node.cost + (abs(node[0] - target[0]) + abs(node[1] - target[1]))
  107. heapq.heappush(nodes, (priority, node))
  108. else:
  109. raise NoPathFound("no path were found to the targetted location {}".format(target))
  110. result = [target]
  111. while current != origin:
  112. result.append(tuple(current))
  113. current = current.parent
  114. result.append(origin)
  115. result.reverse()
  116. return result
  117. # input vars
  118. num_all_customers = int(input())
  119. all_customers = [Customer(*input().split()) for _ in range(num_all_customers)]
  120. grid = Grid([list(input()) for i in range(7)])
  121. log(f"{num_all_customers} customers: {all_customers}")
  122. log(f"grid: {grid}")
  123. while True:
  124. turns_remaining = int(input())
  125. player = Cook(*input().split())
  126. log(f"*** player: {player}")
  127. partner = Cook(*input().split())
  128. log(f"*** partner: {partner}")
  129. num_tables_with_items = int(input()) # the number of tables in the kitchen that currently hold an item
  130. tables = [Table(*input().split()) for _ in range(num_tables_with_items)]
  131. log(f"*** tables: {tables}")
  132. oven = Oven(*input().split())
  133. log(f"*** oven: {oven}")
  134. num_customers = int(input()) # the number of customers currently waiting for food
  135. customers = [Customer(*input().split()) for _ in range(num_customers)]
  136. log(f"*** customers: {customers}")
  137. ### SCRIPT
  138. # if no current order, take the most beneficial
  139. if not player.order:
  140. queue = sorted(customers, reverse=True, key=lambda x: x.award)
  141. # what is my partner doing?
  142. player.order = queue[0].item
  143. log(f'>>> new order taken: {player.order}')
  144. todo = player.order.split('-')
  145. log(f"todo: {todo}")
  146. next_task = next([t for t in todo if not t in player.item], WINDOW)
  147. if next_task == WINDOW:
  148. player.order, todo = [], []
  149. log(f"next_task: {next_task}")
  150. target = location[next_task]
  151. log(f"target: {target}")
  152. closest = grid.closest(player.pos, target)
  153. log(f"closest: {closest}")
  154. player.use(*closest)