44from utils .aoc_utils import report_results , AoCResult , input_for_day
55
66LooRollGrid = list [list [str ]]
7+ RollCoord = tuple [int , int ]
78
89ORIGINAL_EXAMPLE : str = """..@@.@@@@.
910@@@.@.@.@@
2122DATA : LooRollGrid = [list (x ) for x in INPUT_DATA ]
2223
2324
24- def parse_loogrid_p1 (data : LooRollGrid ) -> int :
25- """Navigate through the Loo Roll Grid for AOCD4P1.
26-
27- Insert an extra layer of blank padding, slide a
28- 3x3 window and count adjacent loo rolls.
29- If less than 4 adjacent loo rolls, count it!
25+ def forklift (data : LooRollGrid ) -> list [RollCoord ]:
26+ """Forklift operations. Go through grid, find '@',
27+ get window and check adjacent '@'.
28+ If valid - add to list of valid coordinates.
3029
3130 Args:
32- data (LooRollGrid): List of lists, @ = loo roll .
31+ data (LooRollGrid): Puzzle input as a list of lists .
3332
3433 Returns:
35- int: Count of valid positions .
34+ list[RollCoord]: list of valid coordinates .
3635 """
37- forklift_access : int = 0
38- # add an extra padding 0 and -1
39- for row in data :
40- row .insert (0 , "." )
41- row .insert (len (data [0 ]), "." )
42-
43- # add an extra layer of padding...
44- data .insert (0 , list ("." * len (data [0 ])))
45- data .insert (len (data ), list ("." * len (data [0 ])))
46-
4736 # trundle through the grid
37+ coords : list [RollCoord ] = []
38+ row_idx : int
39+ col_idx : int
40+
4841 for row_idx , row in enumerate (data [1 :- 1 ], 1 ):
4942 # print(ri, row[1:-1])
5043 for col_idx , col in enumerate (row [1 :- 1 ], 1 ):
@@ -59,18 +52,81 @@ def parse_loogrid_p1(data: LooRollGrid) -> int:
5952 # deduct the initial @
6053 num_rolls : int = join_window .count ("@" ) - 1
6154 if num_rolls < 4 :
62- forklift_access += 1
63- return forklift_access
55+ coords .append ((row_idx , col_idx ))
56+
57+ return coords
58+
59+
60+ def pad_data (data : LooRollGrid ) -> LooRollGrid :
61+ """Pad initial grid with blanks.
62+
63+ Args:
64+ data (LooRollGrid): Puzzle input grid.
65+
66+ Returns:
67+ LooRollGrid: Padded puzzle grid.
68+ """
69+ # add an extra padding 0 and -1
70+ padded_data : LooRollGrid = data .copy ()
71+ for row in padded_data :
72+ row .insert (0 , "." )
73+ row .insert (len (data [0 ]), "." )
74+
75+ # add an extra layer of padding...
76+ padded_data .insert (0 , list ("." * len (padded_data [0 ])))
77+ padded_data .insert (len (padded_data ), list ("." * len (padded_data [0 ])))
78+
79+ return padded_data
80+
81+
82+ def solve_p1 (data : LooRollGrid ) -> int :
83+ """Solve P1. Iterate once - find valid coords.
84+
85+ Args:
86+ data (LooRollGrid): Puzzle input.
87+
88+ Returns:
89+ int: Number of valid loo roll coords.
90+ """
91+ padded_data = pad_data (data )
92+ valid_rolls = forklift (padded_data )
93+ return len (valid_rolls )
94+
95+
96+ def solve_p2 (data : LooRollGrid ) -> int :
97+ """Recursively search for valid coords,
98+ add to coordinate list. Replace those coords with 'x',
99+ then repeat until no more can be replaced.
100+
101+ Args:
102+ data (LooRollGrid): Puzzle input.
103+
104+ Returns:
105+ int: Total valid loo roll removals.
106+ """
107+ padded_data : LooRollGrid = pad_data (data )
108+ total_removed : int = 0
109+
110+ while True :
111+ coords : list [RollCoord ] = forklift (padded_data )
112+ if not coords :
113+ break
114+
115+ for x in coords :
116+ padded_data [x [0 ]][x [1 ]] = 'x'
117+ total_removed += len (coords )
118+
119+ return total_removed
64120
65121
66122@report_results
67123def solveday (data : Any ) -> AoCResult :
68- p1 : int = parse_loogrid_p1 ( data )
69- p2 : int = 0
124+ p1 : int = solve_p1 ([ row . copy () for row in data ] )
125+ p2 : int = solve_p2 ([ row . copy () for row in data ])
70126 return p1 , p2
71127
72128
73- expected_test_results : AoCResult = (13 , 0 )
129+ expected_test_results : AoCResult = (13 , 43 )
74130
75131
76132def tests (test_input : Any ) -> None :
0 commit comments