Quest 5: Fishbone Order

  • 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

Link to participate: https://everybody.codes/

  • hades@programming.devOPM
    link
    fedilink
    arrow-up
    3
    ·
    1 day ago

    Rust

    use itertools::Itertools;
    
    type Fishbone = Vec<(i64, Option<i64>, Option<i64>)>;
    
    fn parse_fishbone(quality_str: &str) -> Fishbone {
        let mut fishbone: Fishbone = vec![];
        'outer: for num in quality_str.split(",").map(|x| x.parse().unwrap()) {
            for e in fishbone.iter_mut() {
                if num < e.0 && e.1.is_none() {
                    e.1 = Some(num);
                    continue 'outer;
                }
                if num > e.0 && e.2.is_none() {
                    e.2 = Some(num);
                    continue 'outer;
                }
            }
            fishbone.push((num, None, None));
        }
        fishbone
    }
    
    fn compute_quality(fishbone: &Fishbone) -> i64 {
        fishbone
            .iter()
            .map(|(c, _, _)| c.to_string())
            .join("")
            .parse()
            .unwrap()
    }
    
    pub fn solve_part_1(input: &str) -> String {
        let (_, data) = input.split_once(":").unwrap();
        compute_quality(&parse_fishbone(data)).to_string()
    }
    
    pub fn solve_part_2(input: &str) -> String {
        let mut worst_quality = i64::MAX;
        let mut best_quality = i64::MIN;
        for sword in input.lines() {
            let (_, data) = sword.split_once(":").unwrap();
            let quality = compute_quality(&parse_fishbone(data));
            worst_quality = worst_quality.min(quality);
            best_quality = best_quality.max(quality);
        }
        (best_quality - worst_quality).to_string()
    }
    
    pub fn solve_part_3(input: &str) -> String {
        let mut swords: Vec<_> = input
            .lines()
            .map(|def| {
                let (id, data) = def.split_once(":").unwrap();
                let fishbone = parse_fishbone(data);
                (id.parse::<i64>().unwrap(), fishbone)
            })
            .collect();
        swords.sort_by(|a, b| {
            let cmp = compute_quality(&a.1).cmp(&compute_quality(&b.1));
            if !matches!(cmp, std::cmp::Ordering::Equal) {
                return cmp;
            }
            for (a_seg, b_seg) in a.1.iter().zip(b.1.iter()) {
                let a_val = match a_seg {
                    (a, Some(b), Some(c)) => format!("{b}{a}{c}"),
                    (a, Some(b), None) => format!("{b}{a}"),
                    (a, None, Some(c)) => format!("{a}{c}"),
                    (a, None, None) => format!("{a}"),
                };
                let b_val = match b_seg {
                    (a, Some(b), Some(c)) => format!("{b}{a}{c}"),
                    (a, Some(b), None) => format!("{b}{a}"),
                    (a, None, Some(c)) => format!("{a}{c}"),
                    (a, None, None) => format!("{a}"),
                };
                let cmp = a_val.parse::<i64>().unwrap().cmp(&b_val.parse().unwrap());
                if !matches!(cmp, std::cmp::Ordering::Equal) {
                    return cmp;
                }
            }
            a.0.cmp(&b.0)
        });
        swords.reverse();
        swords
            .into_iter()
            .enumerate()
            .map(|(pos, (id, _))| id * (pos as i64 + 1))
            .sum::<i64>()
            .to_string()
    }