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

  • Deebster
    link
    fedilink
    arrow-up
    1
    ·
    14 days ago

    Rust

    I don’t love this code, but I didn’t initially use a hashmap and it runs so fast it wasn’t worth the time to refactor.

    use std::{cmp::Ordering, fs, str::FromStr};
    
    use color_eyre::eyre::{Report, Result};
    use itertools::Itertools;
    
    struct Updates(Vec<Vec<isize>>);
    
    impl FromStr for Updates {
        type Err = Report;
    
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let pages = s
                .lines()
                .map(|l| l.split(",").map(|n| n.parse::<isize>()).collect())
                .collect::<Result<_, _>>()?;
            Ok(Self(pages))
        }
    }
    
    impl Updates {
        fn get_valid(&self, rules: &OrderingRules) -> Self {
            let pages = self
                .0
                .clone()
                .into_iter()
                .filter(|p| rules.validate(p))
                .collect();
            Self(pages)
        }
    
        fn get_invalid(&self, rules: &OrderingRules) -> Self {
            let pages = self
                .0
                .clone()
                .into_iter()
                .filter(|p| !rules.validate(p))
                .collect();
            Self(pages)
        }
    }
    
    struct OrderingRules(Vec<(isize, isize)>);
    
    impl OrderingRules {
        fn validate(&self, pnums: &Vec<isize>) -> bool {
            self.0.iter().all(|(a, b)| {
                let Some(a_pos) = pnums.iter().position(|&x| x == *a) else {
                    return true;
                };
                let Some(b_pos) = pnums.iter().position(|&x| x == *b) else {
                    return true;
                };
                a_pos < b_pos
            })
        }
    
        fn fix(&self, pnums: &Vec<isize>) -> Vec<isize> {
            let mut v = pnums.clone();
    
            v.sort_by(|a, b| {
                let mut fr = self
                    .0
                    .iter()
                    .filter(|(ra, rb)| (ra == a || ra == b) && (rb == a || rb == b));
                if let Some((ra, _rb)) = fr.next() {
                    if ra == a {
                        Ordering::Less
                    } else {
                        Ordering::Greater
                    }
                } else {
                    Ordering::Equal
                }
            });
            v
        }
    }
    
    impl FromStr for OrderingRules {
        type Err = Report;
    
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let v = s
                .lines()
                .map(|l| {
                    l.splitn(2, "|")
                        .map(|n| n.parse::<isize>().unwrap())
                        .collect_tuple()
                        .ok_or_else(|| Report::msg("Rules need two items"))
                })
                .collect::<Result<_, _>>()?;
            Ok(Self(v))
        }
    }
    
    fn parse(s: &str) -> Result<(OrderingRules, Updates)> {
        let parts: Vec<_> = s.splitn(2, "\n\n").collect();
        let rules = OrderingRules::from_str(parts[0])?;
        let updates = Updates::from_str(parts[1])?;
        Ok((rules, updates))
    }
    
    fn part1(filepath: &str) -> Result<isize> {
        let input = fs::read_to_string(filepath)?;
        let (rules, updates) = parse(&input)?;
        let res = updates
            .get_valid(&rules)
            .0
            .iter()
            .map(|v| v[v.len() / 2])
            .sum();
        Ok(res)
    }
    
    fn part2(filepath: &str) -> Result<isize> {
        let input = fs::read_to_string(filepath)?;
        let (rules, updates) = parse(&input)?;
        let res = updates
            .get_invalid(&rules)
            .0
            .iter()
            .map(|v| rules.fix(&v))
            .map(|v| v[v.len() / 2])
            .sum();
        Ok(res)
    }
    
    fn main() -> Result<()> {
        color_eyre::install()?;
    
        println!("Part 1: {}", part1("d05/input.txt")?);
        println!("Part 2: {}", part2("d05/input.txt")?);
        Ok(())
    }