• 0 Posts
  • 2 Comments
Joined 1 year ago
cake
Cake day: July 1st, 2023

help-circle
  • 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);
    }
    

  • 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)
    }