> [!META]- Inline Metadata > [tags:: #advent-of-code/2022] > [status:: done] > [link::] > [up:: [[Advent of Code 2022 MOC]]] ## Problem ### Part 1 The expedition can depart as soon as the final supplies have been unloaded from the ships. Supplies are stored in stacks of marked _crates_, but because the needed supplies are buried under many other crates, the crates need to be rearranged. The ship has a _giant cargo crane_ capable of moving crates between stacks. To ensure none of the crates get crushed or fall over, the crane operator will rearrange them in a series of carefully-planned steps. After the crates are rearranged, the desired crates will be at the top of each stack. The Elves don't want to interrupt the crane operator during this delicate procedure, but they forgot to ask her _which_ crate will end up where, and they want to be ready to unload them as soon as possible so they can embark. They do, however, have a drawing of the starting stacks of crates _and_ the rearrangement procedure (your puzzle input). For example: ``` [D] [N] [C] [Z] [M] [P] 1 2 3 move 1 from 2 to 1 move 3 from 1 to 3 move 2 from 2 to 1 move 1 from 1 to 2 ``` In this example, there are three stacks of crates. Stack 1 contains two crates: crate `Z` is on the bottom, and crate `N` is on top. Stack 2 contains three crates; from bottom to top, they are crates `M`, `C`, and `D`. Finally, stack 3 contains a single crate, `P`. Then, the rearrangement procedure is given. In each step of the procedure, a quantity of crates is moved from one stack to a different stack. In the first step of the above rearrangement procedure, one crate is moved from stack 2 to stack 1, resulting in this configuration: ``` [D] [N] [C] [Z] [M] [P] 1 2 3 ``` In the second step, three crates are moved from stack 1 to stack 3. Crates are moved _one at a time_, so the first crate to be moved (`D`) ends up below the second and third crates: ``` [Z] [N] [C] [D] [M] [P] 1 2 3 ``` Then, both crates are moved from stack 2 to stack 1. Again, because crates are moved _one at a time_, crate `C` ends up below crate `M`: ``` [Z] [N] [M] [D] [C] [P] 1 2 3 ``` Finally, one crate is moved from stack 1 to stack 2: ``` [Z] [N] [D] [C] [M] [P] 1 2 3 ``` The Elves just need to know _which crate will end up on top of each stack_; in this example, the top crates are `C` in stack 1, `M` in stack 2, and `Z` in stack 3, so you should combine these together and give the Elves the message `_CMZ_`. _After the rearrangement procedure completes, what crate ends up on top of each stack?_ ## Scratchpad ### Part 1 #### Parsing Split into two separate strings: stacks and directions. For stacks: - split into list of strings, each representing a "row" - Scan last string (stack numbers), get numbers and take max - Or strip all whitespace and get last character (did this) - for each item in each string, if there's a value, add it to corresponding list (prepend) ## Solution ### Mine ```python from collections import deque import re from typing import Tuple, List, Deque TEST_INPUT = """ [D] [N] [C] [Z] [M] [P] 1 2 3 move 1 from 2 to 1 move 3 from 1 to 3 move 2 from 2 to 1 move 1 from 1 to 2 """ def move_crates(input_string: str) -> str: stacks, directions = input_string.split("\n\n") built_stacks = _build_stacks(stacks) built_directions = _build_directions(directions) for idx, direction in enumerate(built_directions): # Move crates according to directions for _ in range(direction[0]): built_stacks[direction[2] - 1].appendleft( built_stacks[direction[1] - 1].popleft() ) return "".join([stack[0] for stack in built_stacks]) # Part 2 def move_crates_9001(input_string: str) -> str: stacks, directions = input_string.split("\n\n") built_stacks = _build_stacks(stacks) built_directions = _build_directions(directions) for idx, direction in enumerate(built_directions): # Like above, but move crates together temp_deque = deque() for _ in range(direction[0]): temp_deque.appendleft(built_stacks[direction[1] - 1].popleft()) built_stacks[direction[2] - 1].extendleft(temp_deque) return "".join([stack[0] for stack in built_stacks]) def _build_stacks(stacks: str) -> List[Deque]: split_stacks = [ split.replace("[", " ").replace("]", " ") for split in stacks.split("\n") ] num_stacks = int( split_stacks[-1].strip()[-1] ) # Get total number of stacks from last row of stacks parsed_stacks = [deque() for _ in range(num_stacks)] for row in split_stacks[:-1]: for idx, val in enumerate(row): # "Top" of each stack will be at the beginning of these if val != " ": parsed_stacks[int(split_stacks[-1][idx]) - 1].append(val) return parsed_stacks def _build_directions(directions: str) -> List[Tuple]: """ Builds list of tuples, 0th element is quantity to move, 1st is where to move qty from and 2nd where to move qty to """ split_dirs = directions.strip().split("\n") direction_list = [] for split_dir in split_dirs: direction_list.append( tuple([int(char) for char in split_dir.split() if char.isdigit()]) ) return direction_list if __name__ == "__main__": print(move_crates(TEST_INPUT)) print(f"Move crates pt. 2 test input {move_crates_9001(TEST_INPUT)}") with open("input.txt", "r") as f: input_string = f.read() print(move_crates(input_string)) print(move_crates_9001(input_string)) ``` ## Things I Learned