• 12 Posts
  • 15 Comments
Joined 6 months ago
cake
Cake day: June 4th, 2025

help-circle



  • Rust

    pub fn solve_part_1(input: &str) -> String {
        let numbers: Vec<i32> = input.split(",").map(|x| x.parse().unwrap()).collect();
        let mut count = 0;
        for i in 1..numbers.len() {
            if numbers[i].abs_diff(numbers[i - 1]) == 16 {
                count += 1;
            }
        }
        count.to_string()
    }
    
    pub fn solve_part_2(input: &str) -> String {
        let numbers: Vec<i32> = input.split(",").map(|x| x.parse().unwrap()).collect();
        let mut lines: Vec<(i32, i32)> = vec![];
        for i in 1..numbers.len() {
            let (a, b) = (numbers[i - 1], numbers[i]);
            if a > b {
                lines.push((b, a));
            } else {
                lines.push((a, b));
            }
        }
        let mut knots = 0;
        for i in 0..lines.len() {
            for j in 0..i {
                let (a, b) = lines[i];
                let (c, d) = lines[j];
                if a == c || a == d || b == c || b == d {
                    continue;
                }
                let c_inside = c > a && c < b;
                let d_inside = d > a && d < b;
                if c_inside != d_inside {
                    knots += 1;
                }
            }
        }
        knots.to_string()
    }
    
    pub fn solve_part_3(input: &str) -> String {
        let numbers: Vec<i32> = input.split(",").map(|x| x.parse().unwrap()).collect();
        let mut lines: Vec<(i32, i32)> = vec![];
        for i in 1..numbers.len() {
            let (a, b) = (numbers[i - 1], numbers[i]);
            if a > b {
                lines.push((b, a));
            } else {
                lines.push((a, b));
            }
        }
        let mut best_cut_threads = i64::MIN;
        for d in 1..=256 {
            for c in 1..d {
                let mut cut_threads = 0;
                for (a, b) in lines.iter().copied() {
                    if a == c || a == d || b == c || b == d {
                        if a == c && b == d {
                            cut_threads += 1;
                        }
                        continue;
                    }
                    let c_inside = c > a && c < b;
                    let d_inside = d > a && d < b;
                    if c_inside != d_inside {
                        cut_threads += 1;
                    }
                }
                if cut_threads > best_cut_threads {
                    best_cut_threads = cut_threads;
                }
            }
        }
        best_cut_threads.to_string()
    }
    

  • Rust

    Technically you don’t need to store the names in part 3, but I was too lazy.

    use std::collections::{HashMap, HashSet};
    
    pub fn solve_part_1(input: &str) -> String {
        let (names, rules) = input.split_once("\n\n").unwrap();
        let names: Vec<&str> = names.split(",").collect();
        let rules: HashMap<char, HashSet<char>> = rules
            .lines()
            .map(|line| {
                let (from, to) = line.split_once(" > ").unwrap();
                let to = to.split(",");
                (
                    from.chars().next().unwrap(),
                    to.map(|s| s.chars().next().unwrap()).collect(),
                )
            })
            .collect();
        for name in names {
            let mut allowed_chars = rules.get(&name.chars().next().unwrap());
            let mut acceptable = true;
            for ch in name.chars().skip(1) {
                match allowed_chars {
                    Some(allowed) => {
                        if !allowed.contains(&ch) {
                            acceptable = false;
                            break;
                        }
                        allowed_chars = rules.get(&ch);
                    }
                    None => {
                        panic!("no rules for letter {ch} in name {name}");
                    }
                }
            }
            if acceptable {
                return name.to_string();
            }
        }
        panic!("all names bad");
    }
    
    pub fn solve_part_2(input: &str) -> String {
        let (names, rules) = input.split_once("\n\n").unwrap();
        let names: Vec<&str> = names.split(",").collect();
        let rules: HashMap<char, HashSet<char>> = rules
            .lines()
            .map(|line| {
                let (from, to) = line.split_once(" > ").unwrap();
                let to = to.split(",");
                (
                    from.chars().next().unwrap(),
                    to.map(|s| s.chars().next().unwrap()).collect(),
                )
            })
            .collect();
        let mut sum_of_indices = 0;
        for (i, name) in names.into_iter().enumerate() {
            let mut allowed_chars = rules.get(&name.chars().next().unwrap());
            let mut acceptable = true;
            for ch in name.chars().skip(1) {
                match allowed_chars {
                    Some(allowed) => {
                        if !allowed.contains(&ch) {
                            acceptable = false;
                            break;
                        }
                        allowed_chars = rules.get(&ch);
                    }
                    None => {
                        panic!("no rules for letter {ch} in name {name}");
                    }
                }
            }
            if acceptable {
                sum_of_indices += 1 + i;
            }
        }
        sum_of_indices.to_string()
    }
    
    fn gen_names_with_prefix(
        prefix: &str,
        rules: &HashMap<char, HashSet<char>>,
        result: &mut HashSet<String>,
    ) {
        if prefix.len() >= 7 {
            result.insert(prefix.to_string());
        }
        if prefix.len() == 11 {
            return;
        }
        let last_char = prefix.chars().last().unwrap();
        if let Some(next_chars) = rules.get(&last_char) {
            for next_char in next_chars {
                let new_prefix = format!("{prefix}{next_char}");
                gen_names_with_prefix(new_prefix.as_str(), rules, result);
            }
        }
    }
    
    pub fn solve_part_3(input: &str) -> String {
        let (prefix, rules) = input.split_once("\n\n").unwrap();
        let prefixes: Vec<_> = prefix.split(",").collect();
        let rules: HashMap<char, HashSet<char>> = rules
            .lines()
            .map(|line| {
                let (from, to) = line.split_once(" > ").unwrap();
                let to = to.split(",");
                (
                    from.chars().next().unwrap(),
                    to.map(|s| s.chars().next().unwrap()).collect(),
                )
            })
            .collect();
        let mut results: HashSet<String> = HashSet::new();
        prefixes
            .into_iter()
            .filter(|&name| {
                let mut allowed_chars = rules.get(&name.chars().next().unwrap());
                let mut acceptable = true;
                for ch in name.chars().skip(1) {
                    match allowed_chars {
                        Some(allowed) => {
                            if !allowed.contains(&ch) {
                                acceptable = false;
                                break;
                            }
                            allowed_chars = rules.get(&ch);
                        }
                        None => {
                            panic!("no rules for letter {ch} in name {name}");
                        }
                    }
                }
                acceptable
            })
            .for_each(|prefix| gen_names_with_prefix(prefix, &rules, &mut results));
        results.len().to_string()
    }
    

  • Rust

    use std::collections::HashMap;
    use itertools::Itertools;
    
    pub fn solve_part_1(input: &str) -> String {
        let mut mentors = 0;
        let mut pairs = 0;
        for ch in input.chars() {
            match ch {
                'A' => mentors += 1,
                'a' => pairs += mentors,
                _ => {}
            }
        }
        pairs.to_string()
    }
    
    pub fn solve_part_2(input: &str) -> String {
        let mut mentors: HashMap<char, i64> = HashMap::new();
        let mut pairs = 0;
        for ch in input.chars() {
            match ch {
                'A'..='Z' => *mentors.entry(ch).or_default() += 1,
                'a'..='z' => pairs += *mentors.entry(ch.to_ascii_uppercase()).or_default(),
                _ => panic!("unexpected character {ch}"),
            }
        }
        pairs.to_string()
    }
    
    pub fn solve_part_3(input: &str) -> String {
        let data: Vec<_> = input.chars().collect();
        let len = data.len();
        let mentors: HashMap<char, Vec<usize>> = data
            .iter()
            .enumerate()
            .map(|(i, ch)| (*ch, i))
            .into_group_map();
        let mut pairs: i64 = 0;
        for (squire_position, ch) in data.into_iter().enumerate() {
            if ch.is_ascii_lowercase() {
                for mentor_position in mentors.get(&ch.to_ascii_uppercase()).unwrap() {
                    if squire_position.abs_diff(*mentor_position) <= 1000 {
                        pairs += 1000;
                    } else if (squire_position as isize)
                        .wrapping_sub_unsigned(len)
                        .abs_diff(*mentor_position as isize)
                        <= 1000
                        || (*mentor_position as isize)
                            .wrapping_sub_unsigned(len)
                            .abs_diff(squire_position as isize)
                            <= 1000
                    {
                        pairs += 999;
                    }
                }
            }
        }
        pairs.to_string()
    }
    




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

  • Rust

    use num::{BigInt, Integer};
    
    pub fn solve_part_1(input: &str) -> String {
        let gears: Vec<i64> = input.trim().lines().map(|g| g.parse().unwrap()).collect();
        (2025 * gears[0] / gears.last().unwrap()).to_string()
    }
    
    pub fn solve_part_2(input: &str) -> String {
        let gears: Vec<i64> = input.trim().lines().map(|g| g.parse().unwrap()).collect();
        let res = (BigInt::parse_bytes(b"10000000000000", 10).unwrap() * gears.last().unwrap())
            .div_ceil(&(BigInt::ZERO + gears[0]));
        res.to_string()
    }
    
    pub fn solve_part_3(input: &str) -> String {
        let mut lines = input.trim().lines();
        let first_gear = BigInt::parse_bytes(lines.next().unwrap().as_bytes(), 10).unwrap();
        let mut nominator: BigInt = first_gear * 100;
        let mut denominator: BigInt = BigInt::ZERO + 1;
        for line in lines {
            let mut split = line.split("|");
            denominator *= BigInt::parse_bytes(split.next().unwrap().as_bytes(), 10).unwrap();
            match split.next() {
                Some(size) => {
                    nominator *= BigInt::parse_bytes(size.as_bytes(), 10).unwrap();
                }
                None => {
                    break;
                }
            }
        }
        (nominator / denominator).to_string()
    }
    

  • Rust

    pub fn solve_part_1(input: &str) -> String {
        let mut crates: Vec<i64> = input.split(",").map(|s| s.parse().unwrap()).collect();
        crates.sort();
        let mut monotonic_subsequence = vec![crates[0]];
        for size in crates.into_iter().skip(1) {
            if size == *monotonic_subsequence.last().unwrap() {
                continue;
            }
            monotonic_subsequence.push(size);
        }
        monotonic_subsequence.iter().sum::<i64>().to_string()
    }
    
    pub fn solve_part_2(input: &str) -> String {
        let mut crates: Vec<i64> = input.split(",").map(|s| s.parse().unwrap()).collect();
        crates.sort();
        let mut monotonic_subsequence = vec![crates[0]];
        for size in crates.into_iter().skip(1) {
            if size == *monotonic_subsequence.last().unwrap() {
                continue;
            }
            monotonic_subsequence.push(size);
            if monotonic_subsequence.len() >= 20 {
                break;
            }
        }
        monotonic_subsequence.iter().sum::<i64>().to_string()
    }
    
    pub fn solve_part_3(input: &str) -> String {
        let mut crates: Vec<i64> = input.split(",").map(|s| s.parse().unwrap()).collect();
        crates.sort();
        let mut monotonic_subsequences = vec![vec![crates[0]]];
        for size in crates.into_iter().skip(1) {
            let updateable_sequence = monotonic_subsequences
                .iter_mut()
                .find(|v| *v.last().unwrap() < size);
            match updateable_sequence {
                Some(v) => {
                    v.push(size);
                }
                None => {
                    monotonic_subsequences.push(vec![size]);
                }
            }
        }
        monotonic_subsequences.len().to_string()
    }
    




  • Rust

    use log::debug;
    use std::collections::HashSet;
    
    use regex::Regex;
    
    #[derive(PartialEq, Eq, Hash, Clone)]
    struct Number(isize, isize);
    
    impl Number {
    
      fn add(self: &Number, b: &Number) -> Number {
        Number(self.0 + b.0, self.1 + b.1)
      }
    
      fn mul(self: &Number, b: &Number) -> Number {
        Number(self.0 * b.0 - self.1 * b.1, self.0 * b.1 + self.1 * b.0)
      }
    
      fn div(self: &Number, b: &Number) -> Number {
        Number(self.0 / b.0, self.1 / b.1)
      }
    }
    
    pub fn solve_part_1(input: &str) -> String {
      let re = Regex::new(r"A=\[(\d+),(\d+)\]").unwrap();
      let (_, [x, y]) = re.captures(input).unwrap().extract();
      let a = Number(x.parse().unwrap(), y.parse().unwrap());
      let mut res = Number(0, 0);
      for _ in 0..3 {
        res = res.mul(&res);
        res = res.div(&Number(10, 10));
        res = res.add(&a);
      }
      format!("[{},{}]", res.0, res.1)
    }
    
    pub fn solve_part_2(input: &str) -> String {
      let re = Regex::new(r"A=\[([-0-9]+),([-0-9]+)\]").unwrap();
      let (_, [x, y]) = re.captures(input).unwrap().extract();
      let a = Number(x.parse().unwrap(), y.parse().unwrap());
      let mut engraved_points = 0;
      let mut pts: HashSet<_> = HashSet::new();
      for i in 0..=100 {
        for j in 0..=100 {
          let pt = Number(a.0 + 10 * i, a.1 + 10 * j);
          let mut res = Number(0, 0);
          engraved_points += 1;
          pts.insert(pt.clone());
          for _ in 0..100 {
            res = res.mul(&res);
            res = res.div(&Number(100_000, 100_000));
            res = res.add(&pt);
            if res.0.abs() > 1_000_000 || res.1.abs() > 1_000_000 {
              engraved_points -= 1;
              pts.remove(&pt);
              break;
            }
          }
        }
      }
      for i in 0..=100 {
        debug!("{}", (0..=100).map(|j| if pts.contains(&Number(a.0 + 10*i, a.1 + 10*j)) { 'X' } else {'.'}).collect::<String>());
      }
      engraved_points.to_string()
    }
    
    pub fn solve_part_3(input: &str) -> String {
      let re = Regex::new(r"A=\[([-0-9]+),([-0-9]+)\]").unwrap();
      let (_, [x, y]) = re.captures(input).unwrap().extract();
      let a = Number(x.parse().unwrap(), y.parse().unwrap());
      let mut engraved_points = 0;
      for i in 0..=1000 {
        for j in 0..=1000 {
          let pt = Number(a.0 + i, a.1 + j);
          let mut res = Number(0, 0);
          engraved_points += 1;
          for _ in 0..100 {
            res = res.mul(&res);
            res = res.div(&Number(100_000, 100_000));
            res = res.add(&pt);
            if res.0.abs() > 1_000_000 || res.1.abs() > 1_000_000 {
              engraved_points -= 1;
              break;
            }
          }
        }
      }
      engraved_points.to_string()
    }