| 1 |  |  | import pathlib | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | import re | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | from typing import cast, List, Tuple | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | MOVE_REGEX = re.compile(r'^move (\d+) from (\d+) to (\d+)$') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | def parse_initial_state(state_lines): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |     stack_ids = list(map(int, state_lines.pop().split())) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |     stacks = {i: [] for i in sorted(stack_ids)} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |     def split_x(chunk_size): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |         return [line[i:i + chunk_size] for i in range(0, len(line), chunk_size + 1)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |     for line in reversed(state_lines): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |         for create, stack in zip(split_x(3), stack_ids): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |             if create == '   ': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |             stacks[stack].append(create) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |     return stacks | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  | def parse_moves(lines) -> List[Tuple[int, int, int]]: | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |     return cast( | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |         List[Tuple[int, int, int]], | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |         [ | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |             tuple(map(int, re.match(MOVE_REGEX, line).groups())) | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |             for line in lines | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |         ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |     ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  | def parse(lines): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |     split_idx = lines.index('') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |     return ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         parse_initial_state(lines[:split_idx]), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |         parse_moves(lines[split_idx + 1:]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |     ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  | def solve(init_state, moves, pick_group): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |     state = {k: v[:] for k, v in init_state.items()} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |     for n, from_, to in moves: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         pick = [state[from_].pop() for _ in range(n)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         if pick_group: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |             pick.reverse() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |         state[to].extend(pick) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |     return state | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  | def collect_output(state): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     return ''.join(g[-1][1] for g in state.values()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  | def main(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     content = pathlib.Path('./input.txt').read_text() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     initial_state, moves = parse(content.splitlines()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |     print("Part 1:", collect_output(solve(initial_state, moves, False))) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |     print("Part 2:", collect_output(solve(initial_state, moves, True))) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  | if __name__ == '__main__': | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 67 |  |  |     main() | 
            
                                                        
            
                                    
            
            
                | 68 |  |  |  |