this post was submitted on 18 Dec 2023
0 points (NaN% liked)

Advent Of Code

761 readers
1 users here now

An unofficial home for the advent of code community on programming.dev!

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.

AoC 2023

Solution Threads

M T W T F S S
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25

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 1 year ago
MODERATORS
 

Day 18: Lavaduct Lagoon

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

you are viewing a single comment's thread
view the rest of the comments
[โ€“] Gobbel2000@feddit.de 0 points 10 months ago

Rust

I originally went with a flooding solution similar to Day 10 with the pipe ring. But that was highly unlikely to work in part 2. So I added length * horizontal_pos when going down, and subtracted the same when going up. After fiddling with a bunch of off-by-one-errors, that gave me the result I was looking for.

use std::str::FromStr;

enum Dir {
    N,
    E,
    S,
    W,
}

impl FromStr for Dir {
    type Err = String;
    // Part 1
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "U" => Ok(Dir::N),
            "R" => Ok(Dir::E),
            "D" => Ok(Dir::S),
            "L" => Ok(Dir::W),
            _ => Err(format!("Invalid direction char {s}")),
        }
    }
}

impl TryFrom<u32> for Dir {
    type Error = String;
    // Part 2
    fn try_from(n: u32) -> Result<Self, Self::Error> {
        match n {
            0 => Ok(Dir::E),
            1 => Ok(Dir::S),
            2 => Ok(Dir::W),
            3 => Ok(Dir::N),
            _ => Err(format!("Invalid direction number {n}"))
        }
    }
}

struct Edge {
    dir: Dir,
    length: u32,
}

impl Edge {
    fn from_str_part1(s: &str) -> Option<Self> {
        let mut parts = s.split_whitespace();
        let dir = parts.next()?.to_string().parse().ok()?;
        let length = parts.next()?.parse::<u32>().ok()?;
        Some(Edge {
            dir,
            length,
        })
    }

    fn from_str_part2(s: &str) -> Option<Self> {
        let mut parts = s.split_whitespace();
        let not_color = parts.nth(2)?;
        let hex = not_color.trim_start_matches("(#").trim_end_matches(')');
        let num = u32::from_str_radix(hex, 16).ok()?;
        Some(Edge {
            dir: Dir::try_from(num & 0xf).ok()?,
            length: num >> 4,
        })
    }
}

fn area(edges: &[Edge]) -> u64 {
    // Initialize with 1 for starting point
    let mut area: i64 = 1;
    // Horizontal position
    let mut pos = 0;
    for edge in edges {
        let l = edge.length as i64;
        match edge.dir {
            Dir::S => area += l * (pos + 1),
            Dir::N => area -= l * pos,
            Dir::E => { area += l; pos += l },
            Dir::W => pos -= l,
        }
    }
    // If the path went counter-clockwise, area would end up negative
    area.unsigned_abs()
}

fn part1(input: String) {
    let inputs: Vec<Edge> = input.lines()
        .map(|l| Edge::from_str_part1(l).unwrap())
        .collect(); 
    println!("{}", area(&inputs));
}

fn part2(input: String) {
    let inputs: Vec<Edge> = input.lines()
        .map(|l| Edge::from_str_part2(l).unwrap())
        .collect();
    println!("{}", area(&inputs));
}

util::aoc_main!("day18.txt");