15_boxes.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. #!/usr/bin/env python3
  2. import sys
  3. def parse(f):
  4. walls = set()
  5. boxes = {}
  6. for y, line in enumerate(f):
  7. if line == '\n':
  8. break
  9. for x, cell in enumerate(line):
  10. if cell == '#':
  11. walls.add((x, y))
  12. elif cell == 'O':
  13. boxes[x, y] = (x, y),
  14. elif cell == '@':
  15. yield x, y
  16. yield walls
  17. yield boxes
  18. yield [((0, -1), (0, 1), (-1, 0), (1, 0))['^v<>'.index(c)]
  19. for line in f for c in line if c != '\n']
  20. def push(robot, walls, boxes, moves):
  21. for dx, dy in moves:
  22. move = lambda xy: (xy[0] + dx, xy[1] + dy)
  23. nb = move(robot)
  24. if nb not in walls:
  25. pushed = set()
  26. work = [nb]
  27. while work:
  28. xy = work.pop()
  29. box = boxes.get(xy, None)
  30. if box and box not in pushed:
  31. pushed.add(box)
  32. for xy in box:
  33. work.append(move(xy))
  34. if all(move(xy) not in walls for box in pushed for xy in box):
  35. for box in pushed:
  36. for xy in box:
  37. del boxes[xy]
  38. for box in pushed:
  39. newbox = tuple(move(xy) for xy in box)
  40. for xy in newbox:
  41. boxes[xy] = newbox
  42. robot = nb
  43. return sum(100 * y + x for box in set(boxes.values()) for x, y in box[:1])
  44. def widen(robot, walls, boxes):
  45. x, y = robot
  46. yield x * 2, y
  47. yield {(x * 2, y) for x, y in walls} | {(x * 2 + 1, y) for x, y in walls}
  48. newboxes = {}
  49. for x, y in boxes:
  50. l = x * 2, y
  51. r = x * 2 + 1, y
  52. newboxes[l] = newboxes[r] = l, r
  53. yield newboxes
  54. robot, walls, boxes, moves = parse(sys.stdin)
  55. print(push(robot, walls, boxes, moves))
  56. print(push(*widen(robot, walls, boxes), moves))