From beb3f012e306509110cd4e97aeb569a8266bd967 Mon Sep 17 00:00:00 2001 From: mirsella Date: Sun, 17 Dec 2023 18:24:59 +0100 Subject: [PATCH] gamp --- 2023/Cargo.toml | 2 +- 2023/day17/.gitignore | 19 +++++++++ 2023/day17/Cargo.toml | 10 +++++ 2023/day17/build.rs | 28 +++++++++++++ 2023/day17/src/main.rs | 94 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 2023/day17/.gitignore create mode 100644 2023/day17/Cargo.toml create mode 100644 2023/day17/build.rs create mode 100644 2023/day17/src/main.rs diff --git a/2023/Cargo.toml b/2023/Cargo.toml index ad1a414..39f0aeb 100644 --- a/2023/Cargo.toml +++ b/2023/Cargo.toml @@ -18,7 +18,7 @@ members = [ "day14", "day15", "day16", - # "day17", + "day17", # "day18", # "day19", # "day20", diff --git a/2023/day17/.gitignore b/2023/day17/.gitignore new file mode 100644 index 0000000..e983cca --- /dev/null +++ b/2023/day17/.gitignore @@ -0,0 +1,19 @@ +input.txt +flamegraph.svg +perf.data* +### Rust +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + diff --git a/2023/day17/Cargo.toml b/2023/day17/Cargo.toml new file mode 100644 index 0000000..818b736 --- /dev/null +++ b/2023/day17/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day17" +authors = ["mirsella "] +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pathfinding = "4.6.0" diff --git a/2023/day17/build.rs b/2023/day17/build.rs new file mode 100644 index 0000000..b6a19a0 --- /dev/null +++ b/2023/day17/build.rs @@ -0,0 +1,28 @@ +use std::fs::File; +use std::io::{self, Read}; +use std::path::PathBuf; +use std::{env, fs}; + +fn replace_in_file(file_path: &PathBuf, old: &str, new: &str) -> io::Result<()> { + let mut contents = String::new(); + File::open(file_path)?.read_to_string(&mut contents)?; + let new_contents = contents.replace(old, new); + if contents != new_contents { + println!("Updating {}", file_path.display()); + fs::write(file_path, new_contents)?; + } + Ok(()) +} + +fn main() -> io::Result<()> { + let pkg_name = env::var("CARGO_PKG_NAME").unwrap(); + replace_in_file( + &"../Cargo.toml".into(), + &format!("# \"{pkg_name}\""), + &format!("\"{pkg_name}\""), + )?; + + replace_in_file(&"./Cargo.toml".into(), "\n[workspace]", "")?; + + Ok(()) +} diff --git a/2023/day17/src/main.rs b/2023/day17/src/main.rs new file mode 100644 index 0000000..db11aa5 --- /dev/null +++ b/2023/day17/src/main.rs @@ -0,0 +1,94 @@ +use pathfinding::{directed::dijkstra::dijkstra, matrix::Matrix}; + +fn pathfind(input: &str, min: usize, max: usize) -> usize { + let grid = Matrix::from_rows( + input + .lines() + .map(|l| l.chars().map(|c| c.to_digit(10).unwrap())), + ) + .unwrap(); + + let result = dijkstra( + &((0, 0), (0, 0), 0), + |&(pos, (direction_x, direction_y), consecutive_count)| { + let mut moves = Vec::new(); + let mut add_moves = |direction, consecutive_count| { + if let Some(new_pos) = grid.move_in_direction(pos, direction) { + moves.push(((new_pos, direction, consecutive_count), grid[new_pos])); + }; + }; + if consecutive_count < max { + add_moves((direction_x, direction_y), consecutive_count + 1); + } + if consecutive_count >= min { + add_moves((-direction_y, -direction_x), 1); + add_moves((direction_y, direction_x), 1); + } else if consecutive_count == 0 { + add_moves((1, 0), 1); + add_moves((0, 1), 1); + } + moves + }, + |pos| pos.0 == (grid.rows - 1, grid.columns - 1) && pos.2 >= min, + ) + .unwrap(); + for (x, row) in grid.iter().enumerate() { + for (y, digit) in row.iter().enumerate() { + if result.0.iter().any(|p| p.0 == (x, y)) { + print!("#"); + } else { + print!("{}", digit); + } + } + println!(); + } + result.1 as usize +} + +fn part1(input: &str) -> usize { + pathfind(input, 1, 3) +} + +fn part2(input: &str) -> usize { + pathfind(input, 4, 10) +} + +fn main() { + let input = include_str!("../input.txt"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); +} + +#[cfg(test)] +mod tests { + const INPUT: &str = "2413432311323 +3215453535623 +3255245654254 +3446585845452 +4546657867536 +1438598798454 +4457876987766 +3637877979653 +4654967986887 +4564679986453 +1224686865563 +2546548887735 +4322674655533"; + const INPUT2: &str = "111111111111 +999999999991 +999999999991 +999999999991 +999999999991"; + #[test] + fn part1() { + assert_eq!(super::part1(INPUT), 102); + } + #[test] + fn part2() { + assert_eq!(super::part2(INPUT), 94); + } + #[test] + fn part2_2() { + assert_eq!(super::part2(INPUT2), 71); + } +}