CameronDev

joined 2 years ago
MODERATOR OF

I think the hack was just skipping the entire second set of paths, but yeah, splitting was an nice optimisation. Might not scale as well if that path had to hit multiple intermediate nodes though.

[โ€“] CameronDev@programming.dev 1 points 1 week ago* (last edited 1 week ago)

Yeah, ill have to bust out the pen and paper as well. Good learning excercise though :) Edit: If you find any good resources, please share :)

[โ€“] CameronDev@programming.dev 2 points 1 week ago (3 children)

I also broke up the pathing, mine has zero paths from DAC to FFT. If I join DAC directly FFT, i get a stackoverflow, so maybe its intentional.

Rust

Finally got it, but had to use Z3. Getting Z3 to work was a real pain, they really need to doco the rust crate better.

I'll try redo it at some point without Z3, maybe after I forgot what a pain this was.

spoiler


    struct Puzzle2 {
        target: Vec<u16>,
        buttons: Vec<Vec<u16>>,
    }
    fn solve_puzzle_z3(puzzle2: &Puzzle2) -> usize {
        let optimiser = Optimize::new();
        let num_presses: Vec<Int> = (0..puzzle2.buttons.len())
            .map(|i| Int::new_const(format!("n_{i}")))
            .collect();

        num_presses.iter().for_each(|p| optimiser.assert(&p.ge(0)));

        (0..puzzle2.target.len()).for_each(|i| {
            let r = puzzle2.target[i];

            let buttons = puzzle2
                .buttons
                .iter()
                .enumerate()
                .filter_map(|(j, b)| {
                    if b.contains(&(i as u16)) {
                        Some(&num_presses[j])
                    } else {
                        None
                    }
                })
                .collect::<Vec<&Int>>();

            let sum = buttons.into_iter().sum::<Int>();

            optimiser.assert(&sum.eq(r));
        });

        let all_presses = num_presses.iter().sum::<Int>();

        optimiser.minimize(&all_presses);
        if optimiser.check(&[]) != SatResult::Sat {panic!("Unsolvable")}
        let model = optimiser
                    .get_model()
                    .expect("Optimizer should have a model if sat");
        let t = model.eval(&all_presses, true).unwrap().as_i64().unwrap();
        t as usize
    }

    #[test]
    fn test_y2025_day10_part2() {
        let input = include_str!("../../input/2025/day_10.txt");
        let puzzles = input
            .lines()
            .map(|line| {
                let parts = line.split(" ").collect::<Vec<_>>();
                let display = parts.last().unwrap();
                let display = display[1..display.len() - 1]
                    .split(',')
                    .map(|c| c.parse::<u16>().unwrap())
                    .collect::<Vec<u16>>();

                let buttons = parts[1..parts.len() - 1]
                    .iter()
                    .map(|s| {
                        s[1..s.len() - 1]
                            .split(",")
                            .map(|s| s.parse::<u16>().unwrap())
                            .collect::<Vec<u16>>()
                    })
                    .collect::<Vec<Vec<u16>>>();

                Puzzle2 {
                    target: display,
                    buttons,
                }
            })
            .collect::<Vec<Puzzle2>>();

        let mut min_presses = 0;

        for puzzle in &puzzles {
            min_presses += solve_puzzle_z3(puzzle)
        }

        println!("PRESSED: {}", min_presses);
    }

[โ€“] CameronDev@programming.dev 2 points 1 week ago (2 children)

Rust

After the struggles of yesterday, nice to have an easy one. Still havent solved yesterdays pt2, struggling to understand z3 + rust.

Hope everyone else isnt too demoralised by the last 2 days!

spoiler

   fn count_paths2(
        paths: &HashMap<&str, Vec<&str>>,
        seen: &mut HashMap<String, usize>,
        node: &str,
        dest: &str,
    ) -> usize {
        if let Some(c) = seen.get(node) {
            return *c;
        }
        if node == dest {
            seen.insert(node.to_string(), 1);
            return 1;
        }

        let Some(next) = paths.get(node) else {
            return 0;
        };
        let mut total_paths = 0;
        for node in next {
            total_paths += count_paths2(paths, seen, node, dest)
        }
        seen.insert(node.to_string(), total_paths);
        total_paths
    }

    #[test]
    fn test_y2025_day11_part2() {
        let input = include_str!("../../input/2025/day_11.txt");
        let mut paths: HashMap<&str, Vec<&str>> = HashMap::new();
        input.lines().for_each(|line| {
            let (source, dests) = line.split_once(":").unwrap();
            let dests = dests.split(" ").collect::<Vec<&str>>();
            paths.insert(source, dests);
        });

        // srv -> fft -> dac -> out

        let mut total1 = 1;
        {
            let mut seen = HashMap::new();
            total1 *= count_paths2(&paths, &mut seen, "svr", "fft");
        }
        {
            let mut seen = HashMap::new();
            total1 *= count_paths2(&paths, &mut seen, "fft", "dac");
        }
        {
            let mut seen = HashMap::new();
            total1 *= count_paths2(&paths, &mut seen, "dac", "out");
        }

        // srv -> dac -> fft -> out

        let mut total2 = 1;
        {
            let mut seen = HashMap::new();
            total2 *= count_paths2(&paths, &mut seen, "svr", "dac");
        }
        {
            let mut seen = HashMap::new();
            total2 *= count_paths2(&paths, &mut seen, "dac", "fft");
        }
        {
            let mut seen = HashMap::new();
            total2 *= count_paths2(&paths, &mut seen, "fft", "out");
        }

        println!("total: {}", total1 + total2);
        assert_eq!(total1 + total2, 509312913844956);
    }

I dont think that is either tbh, no part of that is a change to drive shareholder value. Its weird, sure, but not enshittification.

[โ€“] CameronDev@programming.dev 8 points 1 week ago (2 children)

This isnt really enshittification, they aren't doing it for shareholder value, they are being forced to by various shitty governments.

Yeah, today is rough as well. I guess I jinxed it.

[โ€“] CameronDev@programming.dev 3 points 1 week ago (1 children)

Everyone has PTSD from yesterday.

[โ€“] CameronDev@programming.dev 2 points 1 week ago (2 children)

Based on the slow trickle of results pt2 was very hard. But, having now got a good result, its not that difficult, but getting to that solution/algorithm took a lot of brain power.

I hope todays is a little bit more relaxed.

[โ€“] CameronDev@programming.dev 1 points 1 week ago* (last edited 1 week ago)

Rust

pt2: 71ms.

Wow. What a step up in difficulty. Using the geo library got me the right answer, and quickly in terms of code, but run time was terrible (2m+). Switching back to simply checking if a wall is entirely outside the rectangle got me a much faster win, and the code isn't too bad either.

Code and algorithm description(A wall is outside if its entirely to the left OR entirely to the right of the rect) OR (entirely above OR entirely below).

   fn check_wall_outside(
        c: &(&Coord, &Coord),
        top: usize,
        bottom: usize,
        left: usize,
        right: usize,
    ) -> bool {
        if (c.0.x <= left && c.1.x <= left) || (c.0.x >= right && c.1.x >= right) {
            return true;
        }
        if (c.0.y <= top && c.1.y <= top) || (c.0.y >= bottom && c.1.y >= bottom) {
            return true;
        }
        false
    }

   #[test]
    fn test_y2025_day9_part2_mine1() {
        let input = include_str!("../../input/2025/day_9.txt");
        let coords = input
            .lines()
            .map(|l| {
                let halfs = l.split_once(',').unwrap();
                Coord {
                    x: halfs.0.parse::<usize>().unwrap(),
                    y: halfs.1.parse::<usize>().unwrap(),
                }
            })
            .collect::<Vec<Coord>>();

        let mut walls = vec![];

        for i in 0..coords.len() {
            let first = &coords[i];
            let second = coords.get(i + 1).unwrap_or(coords.first().unwrap());

            walls.push((first, second));
        }

        let mut max_area = 0;
        for i in 0..coords.len() {
            let first = &coords[i];
            'next_rect: for j in i..coords.len() {
                let second = &coords[j];
                if first == second {
                    continue 'next_rect;
                }
                let area = (first.x.abs_diff(second.x) + 1) * (first.y.abs_diff(second.y) + 1);
                if area < max_area {
                    continue 'next_rect;
                }

                let (top, bottom) = if first.y > second.y {
                    (second.y, first.y)
                } else {
                    (first.y, second.y)
                };

                let (left, right) = if first.x > second.x {
                    (second.x, first.x)
                } else {
                    (first.x, second.x)
                };

                for wall in &walls {
                    if !check_wall_outside(wall, top, bottom, left, right) {
                        continue 'next_rect;
                    }
                }

                max_area = area;
            }
        }
        assert_eq!(max_area, 1542119040);
        println!("Part 2: {}", max_area);
    }

[โ€“] CameronDev@programming.dev 4 points 1 week ago (2 children)

Even with using geo in rust, i am still struggling, so no shame in using the library. I did get the solve in 2m32s, but I dont feel like this is optimal.

Surely there is a better solution somewhere.

view more: โ€น prev next โ€บ