Add 2022 solutions
This commit is contained in:
151
2022/d15.py
Normal file
151
2022/d15.py
Normal file
@@ -0,0 +1,151 @@
|
||||
import lib
|
||||
import math
|
||||
|
||||
EXAMPLE = """
|
||||
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
|
||||
Sensor at x=9, y=16: closest beacon is at x=10, y=16
|
||||
Sensor at x=13, y=2: closest beacon is at x=15, y=3
|
||||
Sensor at x=12, y=14: closest beacon is at x=10, y=16
|
||||
Sensor at x=10, y=20: closest beacon is at x=10, y=16
|
||||
Sensor at x=14, y=17: closest beacon is at x=10, y=16
|
||||
Sensor at x=8, y=7: closest beacon is at x=2, y=10
|
||||
Sensor at x=2, y=0: closest beacon is at x=2, y=10
|
||||
Sensor at x=0, y=11: closest beacon is at x=2, y=10
|
||||
Sensor at x=20, y=14: closest beacon is at x=25, y=17
|
||||
Sensor at x=17, y=20: closest beacon is at x=21, y=22
|
||||
Sensor at x=16, y=7: closest beacon is at x=15, y=3
|
||||
Sensor at x=14, y=3: closest beacon is at x=15, y=3
|
||||
Sensor at x=20, y=1: closest beacon is at x=15, y=3
|
||||
"""
|
||||
|
||||
def unify_ranges(ranges):
|
||||
# aaaaaaaaaaa
|
||||
# bbbb
|
||||
#
|
||||
# aaa
|
||||
# bbb
|
||||
#
|
||||
# aaa
|
||||
# bbb
|
||||
ranges = sorted(ranges)
|
||||
while True:
|
||||
for i in range(len(ranges) - 1):
|
||||
a, b = ranges[i], ranges[i + 1]
|
||||
if a == b:
|
||||
del ranges[i]
|
||||
break
|
||||
elif a[0] == b[0]:
|
||||
ranges[i] = (a[0], max(a[1], b[1]))
|
||||
del ranges[i + 1]
|
||||
break
|
||||
elif a[1] == b[1]:
|
||||
ranges[i] = (min(a[0], b[0]), b[1])
|
||||
del ranges[i + 1]
|
||||
break
|
||||
elif a[0] < b[0] and a[1] > b[1]:
|
||||
del ranges[i + 1]
|
||||
break
|
||||
elif a[0] > b[0] and a[1] < b[1]:
|
||||
del ranges[i]
|
||||
break
|
||||
elif a[1] < b[0]:
|
||||
pass
|
||||
elif a[0] <= b[1] and a[1] >= b[0]:
|
||||
ranges[i] = (a[0], b[1])
|
||||
del ranges[i + 1]
|
||||
break
|
||||
else:
|
||||
raise Exception("uhoh", a, b)
|
||||
else:
|
||||
return ranges
|
||||
return ranges
|
||||
|
||||
def mdist(dx, dy):
|
||||
return abs(dx) + abs(dy)
|
||||
|
||||
def xdist(dm, dy):
|
||||
x = dm - abs(dy)
|
||||
if x <= 0:
|
||||
return 0
|
||||
return x
|
||||
|
||||
def solve(lines: list[str], yt):
|
||||
sensors = []
|
||||
bacons = set()
|
||||
for (i, line) in enumerate(lines):
|
||||
digits = lib.str_to_ints(line)
|
||||
sx, sy, bx, by = digits
|
||||
sm = mdist(bx - sx, by - sy)
|
||||
sensors.append([sx, sy, sm])
|
||||
bacons.add((bx, by))
|
||||
|
||||
ranges = []
|
||||
for (sx, sy, sm) in sensors:
|
||||
x_range = xdist(sm, yt - sy)
|
||||
if x_range == 0:
|
||||
continue
|
||||
r = (sx - x_range, sx + x_range)
|
||||
# print(f"{sx=} {sy=} {r=}")
|
||||
ranges.append(r)
|
||||
|
||||
ranges = unify_ranges(ranges)
|
||||
r = 0
|
||||
for (a, b) in ranges:
|
||||
r += b - a + 1
|
||||
for (bx, by) in list(bacons):
|
||||
if by == yt and bx >= a and bx <= b:
|
||||
r -= 1
|
||||
# 140:00 I don't know what a Manhattan distance is.
|
||||
return r
|
||||
|
||||
def solve2(lines: list[str], xymax):
|
||||
sensors = []
|
||||
bacons = set()
|
||||
for (i, line) in enumerate(lines):
|
||||
digits = lib.str_to_ints(line)
|
||||
sx, sy, bx, by = digits
|
||||
sm = mdist(bx - sx, by - sy)
|
||||
sensors.append([sx, sy, sm])
|
||||
bacons.add((bx, by))
|
||||
|
||||
finds = []
|
||||
for yt in range(0, xymax):
|
||||
ranges = []
|
||||
for (sx, sy, sm) in sensors:
|
||||
x_range = xdist(sm, yt - sy)
|
||||
if x_range == 0:
|
||||
continue
|
||||
r = (sx - x_range, sx + x_range)
|
||||
ranges.append(r)
|
||||
ranges = unify_ranges(ranges)
|
||||
|
||||
if ranges[0][0] > 0:
|
||||
raise Exception("Bacon at 0.")
|
||||
elif ranges[-1][-1] < xymax:
|
||||
raise Exception("Bacon at xymax.")
|
||||
|
||||
for i in range(len(ranges) - 1):
|
||||
if ranges[i + 1][0] - ranges[i][1] > 1:
|
||||
finds.append((ranges[i][1] + 1, yt))
|
||||
if len(finds) != 1:
|
||||
raise Exception("TOO MANY FINDS")
|
||||
else:
|
||||
x, y = finds[0]
|
||||
return x * 4000000 + y
|
||||
# 10:00
|
||||
|
||||
def main():
|
||||
lines = lib.str_to_lines_no_empty(EXAMPLE)
|
||||
print("Example 1:", solve(lines, 10))
|
||||
|
||||
lines = lib.str_to_lines_no_empty(open("d15.txt").read())
|
||||
print("Solution 1:", solve(lines, 2000000))
|
||||
|
||||
lines = lib.str_to_lines_no_empty(EXAMPLE)
|
||||
print("Example 2:", solve2(lines, 20))
|
||||
|
||||
lines = lib.str_to_lines_no_empty(open("d15.txt").read())
|
||||
print("Solution 2:", solve2(lines, 4000000))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user