From a0ca5cb73704749436ae06323dd95d1fe801dc01 Mon Sep 17 00:00:00 2001 From: Benjamin Chandler Date: Fri, 13 Dec 2024 12:27:07 +0100 Subject: [PATCH 1/2] day 13 --- data/test/test_13.txt | 15 +++++ src/implementation/thirteen.rs | 115 +++++++++++++++++++++++++++++++-- 2 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 data/test/test_13.txt diff --git a/data/test/test_13.txt b/data/test/test_13.txt new file mode 100644 index 0000000..444a287 --- /dev/null +++ b/data/test/test_13.txt @@ -0,0 +1,15 @@ +Button A: X+94, Y+34 +Button B: X+22, Y+67 +Prize: X=8400, Y=5400 + +Button A: X+26, Y+66 +Button B: X+67, Y+21 +Prize: X=12748, Y=12176 + +Button A: X+17, Y+86 +Button B: X+84, Y+37 +Prize: X=7870, Y=6450 + +Button A: X+69, Y+23 +Button B: X+27, Y+71 +Prize: X=18641, Y=10279 \ No newline at end of file diff --git a/src/implementation/thirteen.rs b/src/implementation/thirteen.rs index 44d8a04..c08f522 100644 --- a/src/implementation/thirteen.rs +++ b/src/implementation/thirteen.rs @@ -1,21 +1,124 @@ use crate::Solution; pub struct DayThirteenSolution { - data: Vec, + button_configs: Vec<(ButtonA, ButtonB)>, + prizes: Vec +} + +#[derive(Debug)] +struct ButtonA { + x: u32, + y: u32, +} + +#[derive(Debug)] +struct ButtonB { + x: u32, + y: u32, +} + +struct Prize { + x: u32, + y: u32, } impl Solution for DayThirteenSolution { const DAY: u8 = 13; fn new() -> Self { - todo!("Implement new function for DayThirteenSolution") + let input = parse_input(Self::read_data_to_vec().unwrap()); + DayThirteenSolution { button_configs: input.0, prizes: input.1 } } - fn part_one(&self) -> ! { - todo!("Implement part_one function for DayThirteenSolution") + fn part_one(&self) -> u32 { + let mut count: u32 = 0; + for (button_config, prize) in self.button_configs.iter().zip(self.prizes.iter()) { + let mut tokens = Vec::new(); + find_prize_recurse(&button_config.0, &button_config.1, prize.x, prize.y, 0, 0, &mut tokens); + if tokens.len() > 0 { + count += *tokens.iter().min().unwrap(); + } + break; + } + count } - fn part_two(&self) -> ! { - todo!("Implement part_two function for DayThirteenSolution") + fn part_two(&self) -> u32 { + 42 } } + +fn find_prize_recurse( + button_a: &ButtonA, + button_b: &ButtonB, + x: u32, + y: u32, + a_press: u32, + b_press: u32, + tokens: &mut Vec, +) { + println!("button A: {:?}, button B: {:?}, x: {:?}, y: {:?}, a_press: {:?}, b_press: {:?}", button_a, button_b, x, y, a_press, b_press); + if a_press > 100 && b_press > 100 { + return; + } + if x == 0 && y == 0 { + tokens.push((3*a_press) + b_press); + println!("Tokens updated: {:?}", tokens); + return; + } + // Check if we can push button A. + if x >= button_a.x && y >= button_a.y && a_press < 100 { + return find_prize_recurse(button_a, button_b, x - button_a.x, y - button_a.y, a_press + 1, b_press, tokens); + } + // Check if we can push button B. + if x >= button_b.x && y >= button_b.y && b_press < 100 { + return find_prize_recurse(button_a, button_b, x - button_b.x, y - button_b.y, a_press, b_press + 1, tokens); + } + + return; +} +fn parse_input(input: Vec) -> (Vec<(ButtonA, ButtonB)>, Vec) { + let mut button_configs = Vec::new(); + let mut prizes = Vec::new(); + let filtered_input = input.iter().filter(|x| x.len() > 0).collect::>(); + for combo in filtered_input.chunks(3) { + button_configs.push(( + ButtonA { + x: combo[0].split("+").collect::>()[1].split(",").collect::>()[0].parse::().unwrap(), + y: combo[0].split("+").collect::>()[2].parse::().unwrap(), + }, + ButtonB { + x: combo[1].split("+").collect::>()[1].split(",").collect::>()[0].parse::().unwrap(), + y: combo[1].split("+").collect::>()[2].parse::().unwrap(), + }, + )); + prizes.push(Prize { + x: combo[2].split("=").collect::>()[1].split(",").collect::>()[0].parse::().unwrap(), + y: combo[2].split("=").collect::>()[2].parse::().unwrap(), + }); + } + (button_configs, prizes) +} + +#[cfg(test)] +mod tests { + use std::fs; + + use super::*; + fn get_day_thirteen() -> DayThirteenSolution { + let data = parse_input( + fs::read_to_string("data/test/test_13.txt") + .unwrap() + .lines() + .map(|x| x.to_string()) + .collect(), + ); + DayThirteenSolution { button_configs: data.0, prizes: data.1 } + } + #[test] + fn test_part_one() { + let day_thirteen = get_day_thirteen(); + let output = day_thirteen.part_one(); + assert_eq!(output, 480); + } +} \ No newline at end of file From ab82cbf3cbd3cda8c18fd137dcd03ee54353661d Mon Sep 17 00:00:00 2001 From: Benjamin Chandler Date: Fri, 13 Dec 2024 14:03:17 +0100 Subject: [PATCH 2/2] update part 1 --- benches/benchmark_aoc.rs | 16 ++++- src/implementation/thirteen.rs | 127 +++++++++++++++++++-------------- 2 files changed, 86 insertions(+), 57 deletions(-) diff --git a/benches/benchmark_aoc.rs b/benches/benchmark_aoc.rs index 95f131e..c48b490 100644 --- a/benches/benchmark_aoc.rs +++ b/benches/benchmark_aoc.rs @@ -2,8 +2,8 @@ use advent_of_code_2024::{ implementation::{ eight::DayEightSolution, eleven::DayElevenSolution, five::DayFiveSolution, four::DayFourSolution, nine::DayNineSolution, one::DayOneSolution, seven::DaySevenSolution, - six::DaySixSolution, ten::DayTenSolution, three::DayThreeSolution, - twelve::DayTwelveSolution, two::DayTwoSolution, + six::DaySixSolution, ten::DayTenSolution, thirteen::DayThirteenSolution, + three::DayThreeSolution, twelve::DayTwelveSolution, two::DayTwoSolution, }, Solution, }; @@ -118,6 +118,15 @@ fn benchmark_aoc_day_twelve(c: &mut Criterion) { group.finish(); } +fn benchmark_aoc_day_thirteen(c: &mut Criterion) { + let day_thirteen = DayThirteenSolution::new(); + let mut group = c.benchmark_group("AOC day 13"); + + group.bench_function("Solution one", |b| b.iter(|| day_thirteen.part_one())); + //group.bench_function("Solution two", |b| b.iter(|| day_thirteen.part_two())); + group.finish(); +} + criterion_group!( benches, benchmark_aoc_day_one, @@ -131,6 +140,7 @@ criterion_group!( benchmark_aoc_day_nine, benchmark_aoc_day_ten, benchmark_aoc_day_eleven, - benchmark_aoc_day_twelve + benchmark_aoc_day_twelve, + benchmark_aoc_day_thirteen ); criterion_main!(benches); diff --git a/src/implementation/thirteen.rs b/src/implementation/thirteen.rs index c08f522..d3eab7b 100644 --- a/src/implementation/thirteen.rs +++ b/src/implementation/thirteen.rs @@ -1,18 +1,12 @@ use crate::Solution; pub struct DayThirteenSolution { - button_configs: Vec<(ButtonA, ButtonB)>, - prizes: Vec + button_configs: Vec<(Button, Button)>, + prizes: Vec, } #[derive(Debug)] -struct ButtonA { - x: u32, - y: u32, -} - -#[derive(Debug)] -struct ButtonB { +struct Button { x: u32, y: u32, } @@ -27,74 +21,96 @@ impl Solution for DayThirteenSolution { fn new() -> Self { let input = parse_input(Self::read_data_to_vec().unwrap()); - DayThirteenSolution { button_configs: input.0, prizes: input.1 } + DayThirteenSolution { + button_configs: input.0, + prizes: input.1, + } } fn part_one(&self) -> u32 { let mut count: u32 = 0; for (button_config, prize) in self.button_configs.iter().zip(self.prizes.iter()) { - let mut tokens = Vec::new(); - find_prize_recurse(&button_config.0, &button_config.1, prize.x, prize.y, 0, 0, &mut tokens); - if tokens.len() > 0 { - count += *tokens.iter().min().unwrap(); + if let Some(v) = find_minimum_tokens( + button_config.0.x, + button_config.0.y, + button_config.1.x, + button_config.1.y, + prize.x, + prize.y, + ) { + count += v; } - break; } count } - fn part_two(&self) -> u32 { + fn part_two(&self) -> u64 { + const CORRECTION: u64 = 10000000000000; 42 } } -fn find_prize_recurse( - button_a: &ButtonA, - button_b: &ButtonB, - x: u32, - y: u32, - a_press: u32, - b_press: u32, - tokens: &mut Vec, -) { - println!("button A: {:?}, button B: {:?}, x: {:?}, y: {:?}, a_press: {:?}, b_press: {:?}", button_a, button_b, x, y, a_press, b_press); - if a_press > 100 && b_press > 100 { - return; - } - if x == 0 && y == 0 { - tokens.push((3*a_press) + b_press); - println!("Tokens updated: {:?}", tokens); - return; - } - // Check if we can push button A. - if x >= button_a.x && y >= button_a.y && a_press < 100 { - return find_prize_recurse(button_a, button_b, x - button_a.x, y - button_a.y, a_press + 1, b_press, tokens); - } - // Check if we can push button B. - if x >= button_b.x && y >= button_b.y && b_press < 100 { - return find_prize_recurse(button_a, button_b, x - button_b.x, y - button_b.y, a_press, b_press + 1, tokens); +fn find_minimum_tokens(xa: u32, ya: u32, xb: u32, yb: u32, x: u32, y: u32) -> Option { + let mut min_tokens = None; + + for a_press in 1..100 { + for b_press in 1..100 { + let current_x = xa * a_press + xb * b_press; + let current_y = ya * a_press + yb * b_press; + + if current_x == x && current_y == y { + let tokens = 3 * a_press + b_press; + min_tokens = Some(match min_tokens { + Some(current_min) if tokens < current_min => tokens, + Some(current_min) => current_min, + None => tokens, + }); + } + } } - return; + min_tokens } -fn parse_input(input: Vec) -> (Vec<(ButtonA, ButtonB)>, Vec) { + +fn parse_input(input: Vec) -> (Vec<(Button, Button)>, Vec) { let mut button_configs = Vec::new(); let mut prizes = Vec::new(); - let filtered_input = input.iter().filter(|x| x.len() > 0).collect::>(); + let filtered_input = input + .iter() + .filter(|x| x.len() > 0) + .collect::>(); for combo in filtered_input.chunks(3) { button_configs.push(( - ButtonA { - x: combo[0].split("+").collect::>()[1].split(",").collect::>()[0].parse::().unwrap(), - y: combo[0].split("+").collect::>()[2].parse::().unwrap(), + Button { + x: combo[0].split("+").collect::>()[1] + .split(",") + .collect::>()[0] + .parse::() + .unwrap(), + y: combo[0].split("+").collect::>()[2] + .parse::() + .unwrap(), }, - ButtonB { - x: combo[1].split("+").collect::>()[1].split(",").collect::>()[0].parse::().unwrap(), - y: combo[1].split("+").collect::>()[2].parse::().unwrap(), + Button { + x: combo[1].split("+").collect::>()[1] + .split(",") + .collect::>()[0] + .parse::() + .unwrap(), + y: combo[1].split("+").collect::>()[2] + .parse::() + .unwrap(), }, )); prizes.push(Prize { - x: combo[2].split("=").collect::>()[1].split(",").collect::>()[0].parse::().unwrap(), - y: combo[2].split("=").collect::>()[2].parse::().unwrap(), + x: combo[2].split("=").collect::>()[1] + .split(",") + .collect::>()[0] + .parse::() + .unwrap(), + y: combo[2].split("=").collect::>()[2] + .parse::() + .unwrap(), }); } (button_configs, prizes) @@ -113,7 +129,10 @@ mod tests { .map(|x| x.to_string()) .collect(), ); - DayThirteenSolution { button_configs: data.0, prizes: data.1 } + DayThirteenSolution { + button_configs: data.0, + prizes: data.1, + } } #[test] fn test_part_one() { @@ -121,4 +140,4 @@ mod tests { let output = day_thirteen.part_one(); assert_eq!(output, 480); } -} \ No newline at end of file +}