Clean day 17.

This commit is contained in:
Mikaël Capelle 2022-12-18 16:46:00 +01:00
parent ea5b757180
commit b8e2faa8c9
3 changed files with 29 additions and 46 deletions

View File

@ -1,31 +1,5 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
"""
Part 2:
The idea is to find a repeatable tower to not have to calculate up to the given
number.
The issue here is that you can consume a variable number of jets per rock, so you
cannot simply build a tower of hight LCM(len(ROCKS), len(JETS)), you need to find
a repeat point. The easiest repeat point is one where the incoming rock is the
first one (horizontal line) at the same place in the jet sequence.
The first rock cannot pass any rock present in the tower, so we know if we start
with the same sequence of jets, it will end at the exact same positions (bottom)
and following rocks will follow the same pattern.
What I did:
1. Place rocks as in part 1 but keep tracks of the (rock 0, jet) previously done
(where jet is the index in the sequence, not just '<' or '>'). When a
(rock 0, jet) pair gets repeats, stop the process.
2. At this points, you have places N rocks and the number of rocks between the
two (rock 0, jet) points is K. You have 1000... - N rocks to place, and you
can repeat sequence of K blocks by building towers of hight K starting with
rock 0 and at position "jet" in the sequence of jets.
3. Once this is done, you are left with (1000... - N) % K rocks to place, starting
again at index "jet" in the sequence of jets.
"""
import sys import sys
from typing import Sequence, TypeVar from typing import Sequence, TypeVar
@ -45,7 +19,7 @@ def print_tower(tower: np.ndarray, out: str = "#"):
print("+" + "-" * tower.shape[1] + "+") print("+" + "-" * tower.shape[1] + "+")
def tower_hight(tower: np.ndarray) -> int: def tower_height(tower: np.ndarray) -> int:
return int(tower.shape[0] - tower[::-1, :].argmax(axis=0).min() - 1) return int(tower.shape[0] - tower[::-1, :].argmax(axis=0).min() - 1)
@ -74,12 +48,13 @@ def build_tower(
jets: str, jets: str,
early_stop: bool = False, early_stop: bool = False,
init: np.ndarray = np.ones(WIDTH, dtype=bool), init: np.ndarray = np.ones(WIDTH, dtype=bool),
) -> tuple[np.ndarray, int, tuple[int, int], int]: ) -> tuple[np.ndarray, int, int, dict[int, int]]:
tower = EMPTY_BLOCKS.copy() tower = EMPTY_BLOCKS.copy()
tower[0, :] = init tower[0, :] = init
done_at: dict[tuple[int, int], int] = {} done_at: dict[tuple[int, int], int] = {}
heights: dict[int, int] = {}
i_jet, i_rock = 0, 0 i_jet, i_rock = 0, 0
rock_count = 0 rock_count = 0
@ -119,38 +94,32 @@ def build_tower(
rock_y += 1 rock_y += 1
break break
heights[rock_count] = tower_height(tower)
tower[rock_y, rock_x] = True tower[rock_y, rock_x] = True
return tower, rock_count, (i_rock, i_jet), done_at.get((i_rock, i_jet), -1) return tower, rock_count, done_at.get((i_rock, i_jet), -1), heights
line = sys.stdin.read().strip() line = sys.stdin.read().strip()
tower, *_ = build_tower(2022, line) tower, *_ = build_tower(2022, line)
answer_1 = tower_hight(tower) answer_1 = tower_height(tower)
print(f"answer 1 is {answer_1}") print(f"answer 1 is {answer_1}")
TOTAL_ROCKS = 1_000_000_000_000 TOTAL_ROCKS = 1_000_000_000_000
tower_1, n_rocks_1, (i_rocks_1, i_jet_1), prev_1 = build_tower(TOTAL_ROCKS, line, True) tower_1, n_rocks_1, prev_1, heights_1 = build_tower(TOTAL_ROCKS, line, True)
assert prev_1 > 0
# shift the line # 2767 1513
line = line[i_jet_1:] + line[:i_jet_1]
# remaining rocks
remaining_rocks = TOTAL_ROCKS - n_rocks_1 remaining_rocks = TOTAL_ROCKS - n_rocks_1
n_repeat_rocks = n_rocks_1 - prev_1 n_repeat_rocks = n_rocks_1 - prev_1
# repeated tower
n_repeat_towers = remaining_rocks // n_repeat_rocks n_repeat_towers = remaining_rocks // n_repeat_rocks
tower_repeat, *_ = build_tower(n_repeat_rocks, line)
# remaining tower base_height = heights_1[prev_1]
remaining_rocks = remaining_rocks % n_repeat_rocks repeat_height = heights_1[prev_1 + n_repeat_rocks - 1] - heights_1[prev_1]
tower_remaining, *_ = build_tower(remaining_rocks, line) remaining_height = (
heights_1[prev_1 + remaining_rocks % n_repeat_rocks] - heights_1[prev_1]
answer_2 = (
tower_hight(tower_1)
+ tower_hight(tower_repeat) * n_repeat_towers
+ tower_hight(tower_remaining)
) )
answer_2 = base_height + (n_repeat_towers + 1) * repeat_height + remaining_height
print(f"answer 2 is {answer_2}") print(f"answer 2 is {answer_2}")

1
2022/tests/day17.txt Normal file
View File

@ -0,0 +1 @@
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>

13
2022/tests/day18.txt Normal file
View File

@ -0,0 +1,13 @@
2,2,2
1,2,2
3,2,2
2,1,2
2,3,2
2,2,1
2,2,3
2,2,4
2,2,6
1,2,5
3,2,5
2,1,5
2,3,5