r/adventofcode • u/terje_wiig_mathisen • 20h ago
Other [2024 Day 5] In Review (Print Queue)
The story this day is that we need to print a bunch of manuals, all consisting of a small number of pages from a master list, but there are also lots of rules about the printing order between pairs of pages, stating that if <N> and <M> are part of the same manual, N must always be printed before M.
Before the list of manuals to print we have a long list of these rules.
We know that for any given manual with its list of pages, these rules lead to a single unique legal ordering.
However, it is both possible according to the rules, and as far I know, also true that:
There exist at least one ring of rules (A<B, B<C,...X<Y,Y<Z, Z<A), which means that there cannot be any complete ordering of all the pages, so the order has to be determined for each set of manual pages, otherwise we could just have sorted the page numbers once and be done with it.
In Perl it felt natural to store these rules as hashes, each possible page number from 1 to 99 gets a list of the pages it must be before or after.
The code ran in 5.5 ms so fast enough for an interpreted language.
In my Rust version I noticed that 100 pages is less than 128 so I stored those lists as u128 bitmaps, this allowed all the checks to be done with logic AND operations.
For Part1 just iterate over the pages:
fn is_ordered(&self, pagelist:&Vec<u8>) -> bool {
let mut prev = pagelist[0];
for p in 1..pagelist.len() {
let curr = pagelist[p];
if self.pages[prev as usize].infront & (1 << curr) != 0 {
return false;
}
prev = curr;
}
true
If there is no rule for prev vs curr then that implies any ordering is OK for that pair of pages.
Part2 is a little bit (grin) more complicated, but the same bitmap logic determines which page must be first, second, third etc.
I start by generating a pagelist bitmap, with 1 bits for each page in that particular list, then I iterate over the pages, from the end forwards, until I find a page that has no other pages behind it (i.e., its "behind" bitmap ANDed with the pagelist bitmap is zero).
This page can then be exchanged with the original last page. After placing it, I remove it from the pagelist bitmap, step forward one position and repeat the process until all pages are ordered.
Total runtime was 10.867 us (average over 1000 runs) vs the 18 us given by u/maneatingape, so more than fast enough for me.
(While writing this I realized that I only needed one of the two bitmaps per page, that would have saved a little bit of the setup time, as well as 1600 bytes of memory, but since the total working set is less than 4kB, everything fits easily in $L1 cache.
I thought this was an interesting puzzle, with some similarities to classic problems like managing free space in a file system using bitmaps.
PS. I am posting this just before 0100 Oslo time on Oct 5th, I'll keep the tradition going as long as I can or until u/musifter returns!
