madmo

joined 2 years ago
[โ€“] [email protected] 1 points 2 weeks ago

Rust

Used a sorted/unsorted comparison to solve the first part, the second part was just filling out the else branch.

use std::{
    cmp::Ordering,
    collections::HashMap,
    io::{BufRead, BufReader},
};

fn main() {
    let mut lines = BufReader::new(std::fs::File::open("input.txt").unwrap()).lines();

    let mut rules: HashMap<u64, Vec<u64>> = HashMap::default();

    for line in lines.by_ref() {
        let line = line.unwrap();

        if line.is_empty() {
            break;
        }

        let lr = line
            .split('|')
            .map(|el| el.parse::<u64>())
            .collect::<Result<Vec<u64>, _>>()
            .unwrap();

        let left = lr[0];
        let right = lr[1];

        if let Some(values) = rules.get_mut(&left) {
            values.push(right);
            values.sort();
        } else {
            rules.insert(left, vec![right]);
        }
    }

    let mut updates: Vec<Vec<u64>> = Vec::default();

    for line in lines {
        let line = line.unwrap();

        let update = line
            .split(',')
            .map(|el| el.parse::<u64>())
            .collect::<Result<Vec<u64>, _>>()
            .unwrap();

        updates.push(update);
    }

    let mut middle_sum = 0;
    let mut fixed_middle_sum = 0;

    for update in updates {
        let mut update_sorted = update.clone();
        update_sorted.sort_by(|a, b| {
            if let Some(rules) = rules.get(a) {
                if rules.contains(b) {
                    Ordering::Less
                } else {
                    Ordering::Equal
                }
            } else {
                Ordering::Equal
            }
        });

        if update.eq(&update_sorted) {
            let middle = update[(update.len() - 1) / 2];
            middle_sum += middle;
        } else {
            let middle = update_sorted[(update_sorted.len() - 1) / 2];
            fixed_middle_sum += middle;
        }
    }

    println!("part1: {} part2: {}", middle_sum, fixed_middle_sum);
}
[โ€“] [email protected] 3 points 3 weeks ago (1 children)

Rust with nom parser

Decided to give it a go with the nom parser (first time using this crate). Turned out quite nicely. Had some issues with the alt combinator: All alternatives have to return the same type, using a enum to wrap all options did the trick.

use memmap2::Mmap;
use nom::{
    branch::alt, bytes::complete::*, character::complete::*, combinator::map, multi::many_till,
    sequence::tuple, AsBytes, IResult,
};

#[derive(Debug)]
enum Token {
    Do,
    Dont,
    Mul(u64, u64),
}

fn main() -> anyhow::Result<()> {
    let file = std::fs::File::open("input.txt")?;
    let mmap = unsafe { Mmap::map(&file)? };

    let mut sum_part1 = 0;
    let mut sum_part2 = 0;
    let mut enabled = true;

    let mut cursor = mmap.as_bytes();
    while let Ok(token) = parse(cursor) {
        match token.1 .1 {
            Token::Do => enabled = true,
            Token::Dont => enabled = false,
            Token::Mul(left, right) => {
                let prod = left * right;
                sum_part1 += prod;
                if enabled {
                    sum_part2 += prod;
                }
            }
        }

        cursor = token.0;
    }

    println!("part1: {} part2: {}", sum_part1, sum_part2);

    Ok(())
}

type ParseResult<'a> =
    Result<(&'a [u8], (Vec<char>, Token)), nom::Err<nom::error::Error<&'a [u8]>>>;

fn parse(input: &[u8]) -> ParseResult {
    many_till(
        anychar,
        alt((
            map(doit, |_| Token::Do),
            map(dont, |_| Token::Dont),
            map(mul, |el| Token::Mul(el.2, el.4)),
        )),
    )(input)
}

fn doit(input: &[u8]) -> IResult<&[u8], &[u8]> {
    tag("do()")(input)
}

fn dont(input: &[u8]) -> IResult<&[u8], &[u8]> {
    tag("don't()")(input)
}

type ParsedMulResult<'a> = (&'a [u8], &'a [u8], u64, &'a [u8], u64, &'a [u8]);

fn mul(input: &[u8]) -> IResult<&[u8], ParsedMulResult> {
    tuple((tag("mul"), tag("("), u64, tag(","), u64, tag(")")))(input)
}
[โ€“] [email protected] 2 points 8 months ago

Thanks for creating and sharing this tool! Will definitely add it to my toolbelt!