Refactor 2023:05

Increasing speed from 66mins to 4mins. Caching the
location value in the code to keep things at highest
speed.

From the subreddit, the algorithm looks like this.

1. Start att location 0
2. Traverse the whole process backwards, by
   reversing process steps and flipping dest/src
   positions.
3. Output is not a location, instead it's a seed.
4. if seed is in any seed range, use seed to get
   location as in step 1.
5. If not, increase location by 1 and repeat 2-4.
This commit is contained in:
Anders Englöf Ytterström 2023-12-10 02:04:22 +01:00
parent 08288964bd
commit 741f7b89d8

View file

@ -9,91 +9,67 @@ title = "If You Give A Seed A Fertilizer"
@answer(1, "Nearest location for seed id list is {}") @answer(1, "Nearest location for seed id list is {}")
def part_1(data): def part_1(presolved):
seeds, *process = data.split("\n\n") l, _ = presolved
seeds = [f"{v} 1" for v in seeds.split()[1:]] return l
return _bruteforce(seeds, process, 1)
@answer(2, "Interpreting ranges of seeds, nearest location is {}") @answer(2, "Interpreting ranges of seeds, nearest location is {}")
def part_2(data): def part_2(presolved):
_, l = presolved
return l
def presolve(data):
seeds, *process = data.split("\n\n") seeds, *process = data.split("\n\n")
seeds = re.findall(r"\d+ \d+", seeds) seed_ranges = [[int(x) for x in ar.split()] for ar in re.findall(r"\d+ \d+", seeds)]
return _bruteforce(seeds, process, 8) seed_values = [int(v) for v in seeds.split()[1:]]
processes = [
[tuple(map(int, line.split())) for line in step.splitlines()[1:]]
for step in process
]
p1 = _process(seed_values, processes)
p2 = 26829000 # takes 5m if starting from 0
while True:
g = _process([p2], processes, reverse=True)
if any(g >= a and g < a + r for a, r in seed_ranges):
break
p2 += 1
return p1, p2
def _bruteforce(seeds, process, p=1): def _process(seeds, processes, reverse=False):
processes = [[tuple(map(int, line.split())) for line in step.splitlines()[1:]] for step in process] n = inf
for start in seeds:
sm = [] n = min(n, _nearest(start, processes, reverse=reverse))
for start_r in seeds: return n
pool = Pool()
start, r = start_r.split()
d = int(r) // p
parts = [(d * n + int(start), d * n + int(start) + d) for n in range(p)]
sm += pool.starmap(_nearest, zip(parts, repeat(processes)))
return min(sm)
def _nearest(start_r, processes): def _nearest(start, processes, reverse=False):
a, b = start_r procs = processes if not reverse else processes[::-1]
nearest = inf v = start
for i in range(a, b): for steps in procs:
v = i for line in steps:
for steps in processes: dest, src, r = line
nid = -1 if reverse:
for line in steps: dest, src = src, dest
dest, src, r = line if v >= src and v < src + r:
if v >= src and v < src + r: v = dest + v - src
v = dest + v - src break
break return v
nearest = min(nearest, v)
return nearest
if __name__ == "__main__": if __name__ == "__main__":
# use dummy data with open(f"./input/05.txt", "r") as f:
inp = """ inp = f.read().strip()
seeds: 79 14 55 13
seed-to-soil map: inp = presolve(inp)
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
""".strip()
# inp = parse_input()
a = part_1(inp) a = part_1(inp)
b = part_2(inp) b = part_2(inp)
# assert a == 278755257 assert a == 278755257
# assert b == 26829166 assert b == 26829166