| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import heapq
- import sys
- def log(*msg):
- print(*msg, file=sys.stderr)
- class Queue():
- def __init__(self):
- self.items = []
-
- def __bool__(self):
- return bool(self.items)
- def __repr__(self):
- return str(self.items)
- def values(self):
- return (v for _, v in self.items)
- def put(self, item, priority):
- heapq.heappush(self.items, (priority, item))
- def fput(self, item, priority):
- while priority in [p for p, _ in self.items]:
- priority += 1
- self.put(item, priority)
- def get(self):
- return heapq.heappop(self.items)[1]
- class PathNode(tuple):
- def __new__(self, x, y, parent=None):
- n = tuple.__new__(self, (x, y))
- n.parent = parent
- n.cost = 0
- return n
-
- def __repr__(self):
- return f"<{self[0]}, {self[1]}, c:{self.cost}>"
- h, w, n = [int(input()) for _ in range(3)]
- log("INIT: ", h, w, n)
- LEFT = "E"
- RIGHT = "A"
- DOWN = "D"
- UP = "C"
- STAY = "B"
- ACTIONS = [LEFT, RIGHT, DOWN, UP, STAY]
- MOVES = [UP, RIGHT, DOWN, LEFT] # WARNING: order matters here
- class Grid():
- UNKNOWN = 0
- WALL = 1
- GROUND = 2
-
- VECT = {UP: (0,-1), RIGHT: (1,0), DOWN: (0,1), LEFT: (-1,0)}
- INV = {UP: DOWN, RIGHT: LEFT, LEFT: RIGHT, DOWN: UP, STAY: STAY}
-
- def __init__(self, w, h):
- self.w = w
- self.h = h
- self.cells = {(x, y): Grid.UNKNOWN for x in range(self.w) for y in range(self.h)}
- self.player = []
- self.ghosts = []
- self.deadends = []
-
- def update(self, player, ghosts, available_moves):
- self.player = player
- self.ghosts = ghosts
- self.available_moves = available_moves
-
- for p in [self.player] + self.ghosts:
- self.cells[p] = Grid.GROUND
-
- for m in MOVES:
- p = grid.pos_after(self.player, m)
- self.cells[p] = Grid.GROUND if m in available_moves else Grid.WALL
- self.propagate()
- def _repr_cell(self, p):
- if p == self.player:
- return "P"
- elif p in self.ghosts:
- return "G"
- elif self.cells[p] == Grid.WALL:
- return "x"
- elif self.cells[p] == Grid.GROUND:
- return "_"
- else:
- return "."
-
- def graph(self):
- return "\n".join(["".join([self._repr_cell((x, y)) for x in range(self.w)]) for y in range(self.h) if abs(y - self.player[1]) < 15])
- def set_visited(self, p):
- self.cells[p] = Grid.GROUND
-
- def set_wall(self, p):
- self.cells[p] = Grid.WALL
- @staticmethod
- def pos_after(current, move):
- x, y = current
- dx, dy = Grid.VECT[move]
- return x + dx, y + dy
- @staticmethod
- def dist(p1, p2):
- xa, ya = p1
- xb, yb = p2
- return abs(xa - xb) + abs(ya - yb)
- def neighbors(self, x, y, diags=False):
- neighs = [(x, y - 1), (x - 1, y), (x + 1, y), (x, y + 1)]
- if diags:
- neighs += [(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)]
- return [(x, y) for x, y in neighs if 0 <= x < self.w and 0 <= y < self.h]
- def path(self, start, target):
- nodes = Queue()
- origin = PathNode(*start)
- nodes.put(origin, 0)
- neighbors = []
- while nodes:
- current = nodes.get()
-
- if current == target:
- path = []
- previous = current
- while previous:
- if previous != start:
- path.insert(0, previous)
- previous = previous.parent
- return path
- neighbors = self.neighbors(*current)
- for x, y in neighbors:
- if (x, y) == current.parent:
- continue
-
- if self.cells[(x, y)] == Grid.WALL:
- continue
- cost = current.cost + 1
- priority = cost + Grid.dist((x, y), target)
-
- node = PathNode(x, y, current)
- node.cost = cost
- nodes.put(node, priority)
-
- return None
- def propagate(self):
- self.propagation = {}
- for m in self.available_moves:
- self.propagation[m] = 0
- visited= set()
- start = self.pos_after(self.player, m)
-
- buffer = [start]
- visited |= set(buffer)
-
- while buffer:
- new_buffer = []
- if any(p in self.ghosts for p in buffer):
- break
- for p in buffer:
- for n in self.neighbors(*p):
- if not n in visited and \
- not n in new_buffer and \
- not n == self.player and \
- not self.cells[n] == Grid.WALL:
- new_buffer.append(n)
- visited.add(n)
- self.propagation[m] += 2 if self.cells[n] == Grid.UNKNOWN else 1
- buffer = new_buffer
-
- grid = Grid(w, h)
- turn = 0
- previous = STAY
- while True:
- turn += 1
- available_moves = [m for m in MOVES if input() == "_"]
- log(available_moves)
-
- l = [tuple([int(j) for j in input().split()]) for _ in range(n)]
- *ghosts, player= l
- grid.update(player, ghosts, available_moves)
- log(player, ghosts)
-
- log(grid.graph())
- log(grid.propagation)
-
- q = Queue()
- for m in available_moves:
- visited = 20*(m == grid.INV[previous])
-
- danger = sum([grid.dist(grid.pos_after(player, m), e) for e in ghosts])
- danger = 100 * danger // (len(ghosts) * (w + h))
-
- perspective = grid.propagation[m]
- perspective = 100 * perspective // (max(grid.propagation.values()) or 1)
-
- interest = visited - danger - perspective
-
- log(m, visited, danger, perspective, interest)
- q.fput(m, interest)
-
- move = q.get()
- previous = move
- print(move)
|