this post was submitted on 05 Dec 2024
25 points (100.0% liked)

Advent Of Code

1227 readers
1 users here now

An unofficial home for the advent of code community on programming.dev! Other challenges are also welcome!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

Everybody Codes is another collection of programming puzzles with seasonal events.

EC 2025

AoC 2025

Solution Threads

M T W T F S S
1 2 3 4 5 6 7
8 9 10 11 12

Visualisations Megathread

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 2 years ago
MODERATORS
 

Day 5: Print Queue

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

(page 2) 7 comments
sorted by: hot top controversial new old
[–] RagingHungryPanda@lemm.ee 1 points 1 year ago* (last edited 1 year ago)

I've got a "smart" solution and a really dumb one. I'll start with the smart one (incomplete but you can infer). I did four different ways to try to get it faster, less memory, etc.

// this is from a nuget package. My Mathy roommate told me this was a topological sort.
// It's also my preferred, since it'd perform better on larger data sets.
return lines
    .AsParallel()
    .Where(line => !IsInOrder(GetSoonestOccurrences(line), aggregateRules))
    .Sum(line => line.StableOrderTopologicallyBy(
            getDependencies: page =>
                aggregateRules.TryGetValue(page, out var mustPreceed) ? mustPreceed.Intersect(line) : Enumerable.Empty<Page>())
        .Middle()
    );

The dumb solution. These comparisons aren't fully transitive. I can't believe it works.

public static SortedSet<Page> Sort3(Page[] line,
    Dictionary<Page, System.Collections.Generic.HashSet<Page>> rules)
{
    // how the hell is this working?
    var sorted = new SortedSet<Page>(new Sort3Comparer(rules));
    foreach (var page in line)
        sorted.Add(page);
    return sorted;
}

public static Page[] OrderBy(Page[] line, Dictionary<Page, System.Collections.Generic.HashSet<Page>> rules)
{
    return line.OrderBy(identity, new Sort3Comparer(rules)).ToArray();
}

sealed class Sort3Comparer : IComparer<Page>
{
    private readonly Dictionary<Page, System.Collections.Generic.HashSet<Page>> _rules;

    public Sort3Comparer(Dictionary<Page, System.Collections.Generic.HashSet<Page>> rules) => _rules = rules;

    public int Compare(Page x, Page y)
    {
        if (_rules.TryGetValue(x, out var xrules))
        {
            if (xrules.Contains(y))
                return -1;
        }

        if (_rules.TryGetValue(y, out var yrules))
        {
            if (yrules.Contains(x))
                return 1;
        }

        return 0;
    }
}
Method Mean Error StdDev Gen0 Gen1 Allocated
Part2_UsingList (literally just Insert) 660.3 us 12.87 us 23.20 us 187.5000 35.1563 1144.86 KB
Part2_TrackLinkedList (wrong now) 1,559.7 us 6.91 us 6.46 us 128.9063 21.4844 795.03 KB
Part2_TopologicalSort 732.3 us 13.97 us 16.09 us 285.1563 61.5234 1718.36 KB
Part2_SortedSet 309.1 us 4.13 us 3.45 us 54.1992 10.2539 328.97 KB
Part2_OrderBy 304.5 us 6.09 us 9.11 us 48.8281 7.8125 301.29 KB
[–] Quant@programming.dev 1 points 1 year ago

Uiua

This is the first one that caused me some headache because I didn't read the instructions carefully enough.
I kept trying to create a sorted list for when all available pages were used, which got me stuck in an endless loop.

Another fun part was figuring out to use memberof (∈) instead of find (βŒ•) in the last line of FindNext. So much time spent on debugging other areas of the code

Run with example input here

FindNext ← βŠ™(
  ⊑1⍉,
  βŠƒβ–½(β–½Β¬)⊸∈
  βŠ™βŠ™(⊑0⍉.)
  :βŠ™(⟜(β–½Β¬βˆˆ))
)

# find the order of pages for a given set of rules
FindOrder ← (
  β—΄β™­.
  []
  ⍒(βŠ‚FindNext|β‹…(>1β§»))
  βŠ™β—ŒβŠ‚
)

PartOne ← (
  &rs ∞ &fo "input-5.txt"
  βˆ©Β°β–‘Β°βŠŸβŠœβ–‘Β¬βŒ•"\n\n".
  βŠ™(⊜(β–‘βŠœβ‹•β‰ @,.)β‰ @\n.β†˜1)
  ⊜(βŠœβ‹•β‰ @|.)β‰ @\n.

  βŠ™.
  Β€
  ⊞(β—‘(Β°β–‘:)
    ⟜:βŠ™(Β°βŠŸβ‰)
    =2+∩∈
    β–½
    FindOrder
    βŠΈβ‰Β°β–‘:
    βŠ™β—Œ
  )
  ≑◇(⊑⌊÷2β§».)β–½β™­
  /+
)

PartTwo ← (
  &rs ∞ &fo "input-5.txt"
  βˆ©Β°β–‘Β°βŠŸβŠœβ–‘Β¬βŒ•"\n\n".
  βŠ™(⊜(β–‘βŠœβ‹•β‰ @,.)β‰ @\n.β†˜1)
  ⊜(βŠœβ‹•β‰ @|.)β‰ @\n.
  βŠ™.
  ⍜€⊞(
    β—‘(Β°β–‘:)
    ⟜:βŠ™(Β°βŠŸβ‰)
    =2+∩∈
    β–½
    FindOrder
    βŠΈβ‰Β°β–‘:
    βŠŸβˆ©β–‘
  )
  βŠ™β—Œ
  βŠƒ(⊑0)(⊑1)⍉
  ≑◇(⊑⌊÷2β§».)▽¬≑°░
  /+
)

&p "Day 5:"
&pf "Part 1: "
&p PartOne
&pf "Part 2: "
&p PartTwo
[–] Hammerheart@programming.dev 1 points 1 year ago* (last edited 1 year ago)

Python

(Part 1) omg I can't believe this actually worked first try!

with open('input') as data:
    parts = data.read().rstrip().split("\n\n")
    ordering_rules = parts[0].split("\n")
    updates = parts[1].split("\n")

correct_updates = []
middle_updates = []

def find_relevant_rules(pg_num: str, rules: list[str]) -> list[str] | None:
    for rule in rules:
        return list(filter(lambda x: x.split("|")[0] == pg_num, rules))

def interpret_rule(rule: str) -> list[str]:
    return rule.split("|")

def interpret_update(update: str) -> list[str]:
    return update.split(",")

def find_middle_update_index(update: list[str]) -> int:
    num_of_elements = len(update)
    return num_of_elements // 2

for update in updates:
    is_correct = True
    for i, page in enumerate(interpret_update(update)):
       rules_to_check = find_relevant_rules(page, ordering_rules) 
       for rule in rules_to_check:
           if rule.split("|")[1] in interpret_update(update)[:i]:
               is_correct = False
    if is_correct:
        correct_updates.append(update)

for update in correct_updates:
    split_update = update.split(",")
    middle_updates.append(int(split_update[find_middle_update_index(split_update)]))
print(sum(middle_updates))
[–] morrowind@lemmy.ml 1 points 1 year ago

Smalltalk

parsing logic is duplicated between the two, and I probably could use part2's logic for part 1, but yeah

part 1

day5p1: in
	| rules pages i j input |

	input := in lines.
	i := input indexOf: ''.
	rules := ((input copyFrom: 1 to: i-1) collect: [:l | (l splitOn: '|') collect: #asInteger]).
	pages := (input copyFrom: i+1 to: input size) collect: [:l | (l splitOn: ',') collect: #asInteger].
	
	^ pages sum: [ :p |
		(rules allSatisfy: [ :rule |
			i := p indexOf: (rule at: 1).
			j := p indexOf: (rule at: 2).
			(i ~= 0 & (j ~= 0)) ifTrue: [ i < j ] ifFalse: [ true ]
		])
			ifTrue: [p at: ((p size / 2) round: 0) ]
			ifFalse: [0].
	]

part 2

day5p2: in
	| rules pages i pnew input |

	input := in lines.
	i := input indexOf: ''.
	rules := ((input copyFrom: 1 to: i-1) collect: [:l | (l splitOn: '|') collect: #asInteger]).
	pages := (input copyFrom: i+1 to: input size) collect: [:l | (l splitOn: ',') collect: #asInteger].
	
	^ pages sum: [ :p |
		pnew := p sorted: [ :x :y | 
			rules anySatisfy: [ :r | (r at: 1) = x and: [ (r at: 2) = y]]
		].
		pnew ~= p
			ifTrue: [ pnew at: ((pnew size / 2) round: 0) ]
			ifFalse: [0].
	]
[–] sleeplessone@lemmy.ml 0 points 1 year ago

Rust

Kinda sorta got day 5 done on time.

use std::cmp::Ordering;

use crate::utils::{bytes_to_num, read_lines};

pub fn solution1() {
    let mut lines = read_input();
    let rules = parse_rules(&mut lines);

    let middle_rules_sum = lines
        .filter_map(|line| {
            let line_nums = rule_line_to_list(&line);
            line_nums
                .is_sorted_by(|&a, &b| is_sorted(&rules, (a, b)))
                .then_some(line_nums[line_nums.len() / 2])
        })
        .sum::<usize>();

    println!("Sum of in-order middle rules = {middle_rules_sum}");
}

pub fn solution2() {
    let mut lines = read_input();
    let rules = parse_rules(&mut lines);

    let middle_rules_sum = lines
        .filter_map(|line| {
            let mut line_nums = rule_line_to_list(&line);

            (!line_nums.is_sorted_by(|&a, &b| is_sorted(&rules, (a, b)))).then(|| {
                line_nums.sort_by(|&a, &b| {
                    is_sorted(&rules, (a, b))
                        .then_some(Ordering::Less)
                        .unwrap_or(Ordering::Greater)
                });

                line_nums[line_nums.len() / 2]
            })
        })
        .sum::<usize>();

    println!("Sum of middle rules = {middle_rules_sum}");
}

fn read_input() -> impl Iterator<Item = String> {
    read_lines("src/day5/input.txt")
}

fn parse_rules(lines: &mut impl Iterator<Item = String>) -> Vec<(usize, usize)> {
    lines
        .take_while(|line| !line.is_empty())
        .fold(Vec::new(), |mut rules, line| {
            let (a, b) = line.as_bytes().split_at(2);
            let a = bytes_to_num(a);
            let b = bytes_to_num(&b[1..]);

            rules.push((a, b));

            rules
        })
}

fn rule_line_to_list(line: &str) -> Vec<usize> {
    line.split(',')
        .map(|s| bytes_to_num(s.as_bytes()))
        .collect::<Vec<_>>()
}

fn is_sorted(rules: &[(usize, usize)], tuple: (usize, usize)) -> bool {
    rules.iter().any(|&r| r == tuple)
}

Reusing my bytes_to_num function from day 3 feels nice. Pretty fun challenge.

load more comments
view more: β€Ή prev next β€Ί