DEVELOPMENT ENVIRONMENT

~liljamo/aoc2024

aba8c4be8eec16124692175f981c9a3e9e68dc02 — Jonni Liljamo a month ago 65ada73
feat: day7
3 files changed, 201 insertions(+), 0 deletions(-)

A input/day7/example
A src/day7/mod.rs
M src/main.rs
A input/day7/example => input/day7/example +9 -0
@@ 0,0 1,9 @@
190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20

A src/day7/mod.rs => src/day7/mod.rs +184 -0
@@ 0,0 1,184 @@
use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
    str::FromStr,
};

pub fn solve(input: &Path) -> anyhow::Result<()> {
    println!("part one: {}", part_one(input)?);
    println!("part two: {}", part_two(input)?);

    Ok(())
}

#[derive(Debug)]
struct Equation {
    answer: u64,
    inputs: Vec<u64>,
}

impl FromStr for Equation {
    type Err = Box<dyn std::error::Error>;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split(":");

        Ok(Equation {
            answer: parts.next().unwrap().parse()?,
            inputs: parts
                .next()
                .unwrap()
                .split_whitespace()
                .map(|n| -> u64 { n.parse().unwrap() })
                .collect(),
        })
    }
}

fn part_one(input: &Path) -> anyhow::Result<u64> {
    let reader = BufReader::new(File::open(input)?);

    let mut equations = vec![];
    for line in reader.lines() {
        equations.push(Equation::from_str(&line?).unwrap());
    }

    Ok(equations
        .iter()
        .filter(|eq| check_equation_one(eq))
        .map(|eq| eq.answer)
        .collect::<Vec<u64>>()
        .iter()
        .sum())
}

fn check_equation_one(eq: &Equation) -> bool {
    let positions = eq.inputs.len() - 1;

    if positions == 1 {
        if eq.inputs[0] + eq.inputs[1] == eq.answer {
            return true;
        }
        if eq.inputs[0] * eq.inputs[1] == eq.answer {
            return true;
        }
        return false;
    }

    let operators = ["+", "*"];

    let combinations: Vec<String> = (operators.len()..positions).fold(
        operators
            .iter()
            .flat_map(|c| operators.iter().map(move |&d| d.to_owned() + *c))
            .collect(),
        |a, _| {
            a.into_iter()
                .flat_map(|c| operators.iter().map(move |&d| d.to_owned() + &*c))
                .collect()
        },
    );

    for combination in combinations {
        let combination: Vec<char> = combination.chars().collect();
        let mut current: Option<u64> = None;
        for (i, input) in eq.inputs.iter().enumerate() {
            if current.is_none() {
                current = Some(*input);
                continue;
            }

            match combination[i - 1] {
                '+' => current = Some(current.unwrap() + input),
                '*' => current = Some(current.unwrap() * input),
                _ => panic!(),
            }
        }
        if current.unwrap() == eq.answer {
            return true;
        }
    }

    false
}

fn part_two(input: &Path) -> anyhow::Result<u64> {
    let reader = BufReader::new(File::open(input)?);

    let mut equations = vec![];
    for line in reader.lines() {
        equations.push(Equation::from_str(&line?).unwrap());
    }

    Ok(equations
        .iter()
        .filter(|eq| check_equation_two(eq))
        .map(|eq| eq.answer)
        .collect::<Vec<u64>>()
        .iter()
        .sum())
}

fn check_equation_two(eq: &Equation) -> bool {
    let positions = eq.inputs.len() - 1;

    if positions == 1 {
        if eq.inputs[0] + eq.inputs[1] == eq.answer {
            return true;
        }
        if eq.inputs[0] * eq.inputs[1] == eq.answer {
            return true;
        }
        if (eq.inputs[0].to_string() + &eq.inputs[1].to_string())
            .parse::<u64>()
            .unwrap()
            == eq.answer
        {
            return true;
        }
        return false;
    }

    let operators = ["+", "*", "|"];

    let combinations: Vec<String> = (operators.len()..positions + 1).fold(
        operators
            .iter()
            .flat_map(|c| operators.iter().map(move |&d| d.to_owned() + *c))
            .collect(),
        |a, _| {
            a.into_iter()
                .flat_map(|c| operators.iter().map(move |&d| d.to_owned() + &*c))
                .collect()
        },
    );

    for combination in combinations {
        let combination: Vec<char> = combination.chars().collect();
        let mut current: Option<u64> = None;
        for (i, input) in eq.inputs.iter().enumerate() {
            if current.is_none() {
                current = Some(*input);
                continue;
            }

            match combination[i - 1] {
                '+' => current = Some(current.unwrap() + input),
                '*' => current = Some(current.unwrap() * input),
                '|' => {
                    current = Some(
                        (current.unwrap().to_string() + &input.to_string())
                            .parse()
                            .unwrap(),
                    )
                }
                _ => panic!(),
            }
        }
        if current.unwrap() == eq.answer {
            return true;
        }
    }

    false
}

M src/main.rs => src/main.rs +8 -0
@@ 12,6 12,7 @@ mod day3;
mod day4;
mod day5;
mod day6;
mod day7;

#[derive(Parser)]
struct Args {


@@ 45,6 46,10 @@ enum DayArgs {
        #[arg(short)]
        input: PathBuf,
    },
    Day7 {
        #[arg(short)]
        input: PathBuf,
    },
}

fn main() -> anyhow::Result<()> {


@@ 69,6 74,9 @@ fn main() -> anyhow::Result<()> {
        DayArgs::Day6 { input } => {
            day6::solve(&input)?;
        }
        DayArgs::Day7 { input } => {
            day7::solve(&input)?;
        }
    }

    Ok(())