Part 1:
The task involves initializing the Lava Production Facility using an initialization sequence. The sequence consists of steps, each requiring the application of the Holiday ASCII String Helper algorithm (HASH). The HASH algorithm involves turning a string into a single number in the range 0 to 255. The sum of the results of running the HASH algorithm on each step in the initialization sequence is the solution.
The HASH algorithm is a way to turn any string of characters into a single number in the range 0 to 255. To run the HASH algorithm on a string, start with a current value of 0. Then, for each character in the string starting from the beginning:
- Determine the ASCII code for the current character of the string.
- Increase the current value by the ASCII code you just determined.
- Set the current value to itself multiplied by 17.
- Set the current value to the remainder of dividing itself by 256.
For example:
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
This initialization sequence specifies 11 individual steps; the result of running the HASH algorithm on each of the steps is as follows:
rn=1 becomes 30. cm- becomes 253. qp=3 becomes 97. cm=2 becomes 47. qp- becomes 14. pc=4 becomes 180. ot=9 becomes 9. ab=5 becomes 197. pc- becomes 48. pc=6 becomes 214. ot=7 becomes 231.
In this example, the sum of these results is 1320.
#!/usr/bin/env python3
from pathlib import Path
from typing import Iterable
import typer
def hash_line(line: str) -> int:
current = 0
for c in line:
current = (current + ord(c)) * 17 % 256
return current
def hash(line: str) -> int:
return sum(hash_line(pattern) for pattern in line.strip().split(","))
def total_sum(lines: Iterable[str]) -> int:
return sum(map(hash, lines))
def main(initialization_sequence: Path) -> None:
"""Solves Part 1 of Day 15 Advent of Code.
See: https://adventofcode.com/2023/day/15"""
with open(initialization_sequence) as f:
print(total_sum(f))
if __name__ == "__main__":
typer.run(main)
Part 2:
In Part Two, the task extends to configuring lenses in a series of 256 boxes. The initialization sequence specifies operations for inserting or removing lenses from specific boxes. Each lens operation includes a label, an operation character (= or -), and, if applicable, the focal length of the lens. The focusing power of a lens is calculated based on its position in the box, box number, and focal length. The goal is to follow the entire initialization sequence, perform the specified lens operations, and determine the total focusing power of the resulting lens configuration.
Inside each box, there are several lens slots that will keep a lens correctly positioned to focus light passing through the box. The side of each box has a panel that opens to allow you to insert or remove lenses as necessary.
Along the wall running parallel to the boxes is a large library containing lenses organized by focal length ranging from 1 through 9. The reindeer also brings you a small handheld label printer.
The book goes on to explain how to perform each step in the initialization sequence, a process it calls the Holiday ASCII String Helper Manual Arrangement Procedure, or HASHMAP for short.
Each step begins with a sequence of letters that indicate the label of the lens on which the step operates. The result of running the HASH algorithm on the label indicates the correct box for that step.
The label will be immediately followed by a character that indicates the operation to perform: either an equals sign (=) or a dash (-).
If the operation character is a dash (-), go to the relevant box and remove the lens with the given label if it is present in the box. Then, move any remaining lenses as far forward in the box as they can go without changing their order, filling any space made by removing the indicated lens. (If no lens in that box has the given label, nothing happens.)
If the operation character is an equals sign (=), it will be followed by a number indicating the focal length of the lens that needs to go into the relevant box; be sure to use the label maker to mark the lens with the label given in the beginning of the step so you can find it later. There are two possible situations:
If there is already a lens in the box with the same label, replace the old lens with the new lens: remove the old lens and put the new lens in its place, not moving any other lenses in the box. If there is not already a lens in the box with the same label, add the lens to the box immediately behind any lenses already in the box. Don't move any of the other lenses when you do this. If there aren't any lenses in the box, the new lens goes all the way to the front of the box. Here is the contents of every box after each step in the example initialization sequence above:
After "rn=1":
Box 0: [rn 1]
After "cm-":
Box 0: [rn 1]
After "qp=3":
Box 0: [rn 1]
Box 1: [qp 3]
After "cm=2":
Box 0: [rn 1] [cm 2]
Box 1: [qp 3]
After "qp-":
Box 0: [rn 1] [cm 2]
After "pc=4":
Box 0: [rn 1] [cm 2]
Box 3: [pc 4]
After "ot=9":
Box 0: [rn 1] [cm 2]
Box 3: [pc 4] [ot 9]
After "ab=5":
Box 0: [rn 1] [cm 2]
Box 3: [pc 4] [ot 9] [ab 5]
After "pc-":
Box 0: [rn 1] [cm 2]
Box 3: [ot 9] [ab 5]
After "pc=6":
Box 0: [rn 1] [cm 2]
Box 3: [ot 9] [ab 5] [pc 6]
After "ot=7":
Box 0: [rn 1] [cm 2]
Box 3: [ot 7] [ab 5] [pc 6]
All 256 boxes are always present; only the boxes that contain any lenses are shown here. Within each box, lenses are listed from front to back; each lens is shown as its label and focal length in square brackets.
To confirm that all of the lenses are installed correctly, add up the focusing power of all of the lenses. The focusing power of a single lens is the result of multiplying together:
- One plus the box number of the lens in question.
- The slot number of the lens within the box: 1 for the first lens, 2 for the second lens, and so on.
- The focal length of the lens.
- At the end of the above example, the focusing power of each lens is as follows:
rn: 1 (box 0) * 1 (first slot) * 1 (focal length) = 1
cm: 1 (box 0) * 2 (second slot) * 2 (focal length) = 4
ot: 4 (box 3) * 1 (first slot) * 7 (focal length) = 28
ab: 4 (box 3) * 2 (second slot) * 5 (focal length) = 40
pc: 4 (box 3) * 3 (third slot) * 6 (focal length) = 72
So, the above example ends up with a total focusing power of 145.
#!/usr/bin/env python3
from pathlib import Path
from typing import Iterable
import typer
TOTAL_BOXES = 256
def hash_csv(line: str) -> int:
current = 0
for c in line:
current = (current + ord(c)) * 17 % 256
return current
def remove_slot(csv: str, boxes: list[list[list[str | int]]]) -> None:
# label-
label, *_ = csv.split("-")
box_idx = hash_csv(label)
# Loop over a copy to avoid modifying the list whilst iterating over it.
for slot in boxes[box_idx][:]:
if label == slot[0]:
boxes[box_idx].remove(slot)
break
def add_slot(csv: str, boxes: list[list[list[str | int]]]) -> None:
# label=focal_length
label, focal_len = csv.split("=")
box_idx = hash_csv(label)
# If the label already exists, update it. Else, append it to the end.
for slot in boxes[box_idx]:
if label == slot[0]:
slot[1] = int(focal_len)
return
boxes[box_idx].append([label, int(focal_len)])
def build_boxes(line: str, boxes: list[list[list[str | int]]]) -> None:
for csv in line.strip().split(","):
add_slot(csv, boxes) if "=" in csv else remove_slot(csv, boxes)
def calculate_focusing_pow(boxes: list[list[tuple[str, int]]]) -> int:
total = 0
for box_idx, box in enumerate(boxes, 1):
total += sum(
box_idx * slot_idx * slot[1] for slot_idx, slot in enumerate(box, 1)
)
return total
def line_focusing_pow(line: str) -> int:
boxes = [[] for i in range(TOTAL_BOXES)]
build_boxes(line, boxes)
return calculate_focusing_pow(boxes)
def total_focusing_pow(lines: Iterable[str]) -> int:
return sum(map(line_focusing_pow, lines))
def main(initialization_sequence: Path) -> None:
"""Solves Part 2 of Day 15 Advent of Code.
See: https://adventofcode.com/2023/day/15"""
with open(initialization_sequence) as f:
print(total_focusing_pow(f))
if __name__ == "__main__":
typer.run(main)
Review Request:
General coding comments, style, etc. What are some possible simplifications? What would you do differently?
hash. If you call any other function that relies on thehashfunction, you will have a broken program on your hands. \$\endgroup\$