Metadata
-
Date
-
Tagged
-
Part of series
- Advent of Code 2022 Day 1
- Advent of Code 2022 Day 2
- Advent of Code 2022 Day 3
- Advent of Code 2022 Day 4
- Advent of Code 2022 Day 5
- Advent of Code 2022 Day 6
- Advent of Code 2022 Day 7
- Advent of Code 2022 Day 8
- Advent of Code 2022 Day 9
- Advent of Code 2022 Day 10
- Advent of Code 2022 Day 11
- Advent of Code 2022 Day 12
- Advent of Code 2022 Day 13
- Advent of Code 2022 Day 14
- Advent of Code 2022 Day 15
- Advent of Code 2022 Day 16
- Advent of Code 2022 Day 17
- Advent of Code 2022 Day 18
- Advent of Code 2022 Day 19
- Advent of Code 2022 Day 20
- Advent of Code 2022 Day 21
- Advent of Code 2022 Day 22
- Advent of Code 2022 Day 23
- Advent of Code 2022 Day 24
- Advent of Code 2022 Day 25
-
Older post
-
Newer post
Advent of Code 2022 Day 13
Day 13: Distress Signal
https://adventofcode.com/2022/day/13
You communication device is receiving a signal, it’s a distress signal!
It receives pairs of packets, and some of those pairs are out of order (because of course they are, it wouldn’t be a puzzle if everything was hunky dory now would it?).
You need to be able to identify when a pair is ordered wrong so you can swap the packets.
Today’s input are the pairs of packets you receive.
An example input looks like this:
Each pair is seperated by an empty line. A packet is that array looking thing on a single line. And they look familiar.
A packet consists of lists and integers.
- A list starts with
[
and ends with]
. - A list can be empty
- Each item in a list is seperated by a
,
The two packets in a pair are called left and right.
A pair where the left packet is smaller than the right packet is in the correct order.
To determine which of two packets is smaller, there are a few rules:
- If both values are integers, the lower integer is smaller.
- If both integers are identical, continue to the next part of the package.
- If both values are lists, compare each value in the 2 lists step by step.
- If the left list runs out of values to compare first, it is smaller.
- If the right list runs out of values to compare first, it is smaller.
- If one value is an integer and the other a list, turn the integer into a list of one integer, and run the comparison again.
Parsing
I parsed the input into a list of pairs.
Each item in a pair is a packet, so I used a Packet
data structure.
The main parse
function splits the input in a double newline.
Parses the 2 packets seperatly, and return a list of those pairs.
Yeah, yeah, … show us
parse_packet
!
Now. If you wanted to be cheeky, every packet is valid JSON. So you could use your favourite way to parse JSON and call it a victory.
I didn’t.
parse_packet
takes a string, and returns a Packet
.
It uses the parse_list
function, what’s that?
It’s one of 2 other helper functions.
A packet is either a Num(u8)
or a List(Vec<Packet>)
.
- The number variant gets parsed by
parse_num
. - The list variant gets parsed by
parse_num
.
They both use the same pattern. It consumes a part of what is passed in, and returns the thing it parsed, and the remaining input after that thing.
- for
parse_num
it returns(Packet::Num(u8), &[char])
- for
parse_list
it returns(Packet::List(Vec<Packet>, &[char])
Where that &[char]
bit is the remaining input.
At the very top, when we first call parse_list
in parse_packet
.
We call parse_list
on an entire packet, the remaining part will be empty.
That’s why I throw it away with that _
.
Part 1
The question asks what the sum of the indices of the pairs that arrived correctly is.
in pseudocode:
It’s that comparison where the next bit of interesting code happens.
I wanted to tell my code how it can compare two Packet
s.
Make it understand what a less than operation means.
The rules for such a comparison are described in the intro.
Helpers
To make that comparison possible, I implemented the Ord
trait in Rust.
Basically, I wrote the code that Rust uses when you do a comparison.
Turns out that you can not only compare 2 numbers, but you can compare 2 lists! And the logic it uses happens to be the same one described in the problem statement. That’s convenient!
I take the inner “thing” out of a Packet
, and call them a
and b
.
Both are either a u8
, or a Vec
.
a.cmp(b)
, and if only one of them is a vec, wrap the other in a vec and compare that instead!
With this trait implemented, that skeleton code from earlier works.
Final code
Part 2
We need to put all packets in the correct order now. Ignoring the empty lines.
Two divider packets are inserted too.
The question asks what the decoder key is.
The decoder key is the product of the indices of those 2 divider packets when all packets are in the correct order.
I reused the parsing logic for pairs.
Since we only care about individual packages, I turned the list of pair into a single list with flatten
.
I parsed those 2 divider packets and inserted them into the list of packets.
Then, sort all packets and search for the divider packets.
The product of their indices (reminder: 1 based indices!) is the answer to part2!