diff --git a/.gitignore b/.gitignore index 8572b09..dd00645 100644 --- a/.gitignore +++ b/.gitignore @@ -159,4 +159,42 @@ cython_debug/ # Others .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db + +# Added by cargo + +/target + +## Rust + +# Compiled files +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information: https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# If you use Visual Studio Code, you might want to include the following: +.vscode/ + +# If you're using vim or emacs, you might want to include the following: +*.swp +*~ +/project_name + +# If you use IntelliJ IDEA-based editors (like CLion), you might want to include: +.idea/ +*.iml + +# The directory `.rustup` and `.cargo` are used to store user-specific Rust versions and cargo metadata +.rustup/ +.cargo/ + +# You should also ignore any local configuration files that might contain user-specific or sensitive data +**/config/local_* + +# MacOS-specific +.DS_Store \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0bfce98 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "advent-of-code-2023" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "day1" +path = "src/day1/rust/mod.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/day1/rust/mod.rs b/src/day1/rust/mod.rs new file mode 100644 index 0000000..c114bb7 --- /dev/null +++ b/src/day1/rust/mod.rs @@ -0,0 +1,78 @@ +pub fn part_a(input: &str) -> i32 { + let mut sum = 0; + for line in input.lines() { + let mut digits = line.chars().filter(|c| c.is_ascii_digit()).map(|c| c.to_digit(10).unwrap()); + let first_digit = digits.next().unwrap(); + let last_digit = digits.last().unwrap_or(first_digit); + let combined = first_digit * 10 + last_digit; + sum += combined as i32; + } + sum +} + +pub fn part_b(input: &str) -> i32 { + let mut sum = 0; + let digit_strings = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]; + for line in input.lines() { + let mut digit_array = Vec::new(); + for (current_index, c) in line.chars().enumerate() { + if c.is_ascii_digit() { + digit_array.push(c.to_digit(10).unwrap()); + } else if "otfsen".contains(c) { + let foresight = &line[current_index..]; + for (index, digit_string) in digit_strings.iter().enumerate() { + if foresight.starts_with(digit_string) { + digit_array.push(index as u32 + 1); + break; + } + } + } + } + let first_digit = digit_array[0]; + let last_digit = *digit_array.last().unwrap_or(&first_digit); + let combined = first_digit * 10 + last_digit; + sum += combined as i32; + } + sum +} + +pub fn main() { + let input = include_str!("../input.txt"); + let example_input = include_str!("../input_example.txt"); + let example_input_b = include_str!("../input_example_b.txt"); + println!("Day 1 Example Part A: {}", part_a(example_input)); + println!("Day 1 Part A: {}", part_a(input)); + println!("Day 1 Example Part B: {}", part_b(example_input_b)); + println!("Day 1 Part B: {}", part_b(input)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_a_example() { + let example_input = include_str!("../input_example.txt"); + let example_answer_a = 142; + assert_eq!(part_a(example_input), example_answer_a); + } + #[test] + fn test_part_a() { + let input = include_str!("../input.txt"); + let answer_a = 55029; + assert_eq!(part_a(input), answer_a); + } + #[test] + fn test_part_b_example() { + let example_input_b = include_str!("../input_example_b.txt"); + let example_answer_b = 281; + assert_eq!(part_b(example_input_b), example_answer_b); + } + + #[test] + fn test_part_b() { + let input = include_str!("../input.txt"); + let answer_b = 55686; + assert_eq!(part_b(input), answer_b); + } +}