15.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. from itertools import combinations
  2. lines = [[chunk.split("=") for chunk in line.split()] for line in open("15.input")]
  3. lines = [(int(line[2][1][:-1]), int(line[3][1][:-1]), int(line[8][1][:-1]), int(line[9][1])) for line in lines]
  4. def dist(a, b):
  5. return abs(a[0] - b[0]) + abs(a[1] - b[1])
  6. sensors = set()
  7. beacons = set()
  8. ranges = {}
  9. for sx, sy, bx, by in lines:
  10. sensors.add((sx, sy))
  11. beacons.add((bx, by))
  12. ranges[(sx, sy)] = dist((sx, sy), (bx, by))
  13. def row_coverage(sensor, y):
  14. dy = abs(sensor[1] - y)
  15. if ranges[sensor] < dy:
  16. return None
  17. dx = abs(ranges[sensor] - dy)
  18. return (sensor[0] - dx, sensor[0] + dx + 1)
  19. def col_coverage(sensor, x):
  20. dx = abs(sensor[0] - x)
  21. if ranges[sensor] < dx:
  22. return None
  23. dy = abs(ranges[sensor] - dx)
  24. return (sensor[1] - dy, sensor[1] + dy + 1)
  25. def join_segments(a):
  26. b = []
  27. for begin,end in sorted(a):
  28. if b and b[-1][1] >= begin:
  29. b[-1] = (b[-1][0], max(b[-1][1], end))
  30. else:
  31. b.append((begin, end))
  32. # print((begin, end), b)
  33. return b
  34. def part1(y):
  35. coverage = [row_coverage(sensor, y) for sensor in sensors]
  36. coverage = [c for c in coverage if c is not None]
  37. joined = join_segments(coverage)
  38. print("Part 1:", sum(max(0, seg[1] - seg[0] - 1) for seg in joined))
  39. #part1(y=10)
  40. part1(y=2000000)
  41. def possible_positions(covered):
  42. result = []
  43. current = 0
  44. for start, end in covered:
  45. for x in range(current, start):
  46. result.append(x)
  47. if end > 4000000:
  48. break
  49. current = end
  50. return result
  51. def part2(max_y):
  52. # Brute force let's gooooooo
  53. for y in range(0, max_y):
  54. # This takes a few minutes, so better log the progress
  55. if y % (max_y / 100) == 0:
  56. print(y / max_y * 100, "%")
  57. y_coverage = [row_coverage(sensor, y) for sensor in sensors]
  58. y_coverage = [c for c in y_coverage if c is not None]
  59. y_joined = join_segments(y_coverage)
  60. # Here we can actually be a bit smart, only check the columns
  61. # which are not already covered
  62. for x in possible_positions(y_joined):
  63. x_coverage = [col_coverage(sensor, x) for sensor in sensors]
  64. x_coverage = [c for c in x_coverage if c is not None]
  65. x_joined = join_segments(x_coverage)
  66. if y in possible_positions(x_joined):
  67. return (x, y)
  68. #x, y = part2(20)
  69. x, y = part2(4000000 )
  70. print("Part 2:", x * 4000000 + y)