From f82191cd3ef392bb12b75f857a7b1e3782aba57c Mon Sep 17 00:00:00 2001 From: red Date: Thu, 29 Feb 2024 05:39:36 +0100 Subject: [PATCH] Improvement: Tests are faster --- CHANGELOG.md | 8 ++++ Cargo.toml | 2 +- NOTES_2015.md | 74 ++++++++++++++++--------------- README.md | 2 + inputs/year_2015_day_06_sample_v1 | 3 -- inputs/year_2015_day_06_sample_v2 | 2 - inputs/year_2015_day_07_sample_v1 | 8 ---- src/lib.rs | 22 ++++++--- src/year_2015.rs | 69 +++++++++++++++++++--------- src/year_2015/day_01.rs | 12 ++--- src/year_2015/day_02.rs | 12 ++--- src/year_2015/day_03.rs | 12 ++--- src/year_2015/day_04.rs | 18 +++++--- src/year_2015/day_05.rs | 34 +++++++++----- src/year_2015/day_06.rs | 15 ++++--- src/year_2015/day_07.rs | 30 ++++++++++--- src/year_2015/day_08.rs | 53 +++++++--------------- src/year_2015/day_09.rs | 17 ++++--- src/year_2015/day_10.rs | 18 ++++---- src/year_2015/day_12.rs | 59 ++++++++++++------------ 20 files changed, 262 insertions(+), 208 deletions(-) delete mode 100644 inputs/year_2015_day_06_sample_v1 delete mode 100644 inputs/year_2015_day_06_sample_v2 delete mode 100644 inputs/year_2015_day_07_sample_v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 41163fb..239c88c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ Of note: - The changelog 2015.5.2 has been rewritten from each commit content. - This file may be amended entirely in the future to adhere to the [GNU Changelog style](https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html#Style-of-Change-Logs) +## [2015.12.2] +### Changed +- All tests now take input from any `impl Into` (so `String`, `&str`,...). +- Some optimisations there and there. +### Removed +- File samples for 2015, days 6 and 7. +- Method and tests for `code_line_len` on 2015 day 8. + ## [2015.12.1] ### Added - Solved [exercice for 2015, day 12](src/year_2015/day_12.rs). diff --git a/Cargo.toml b/Cargo.toml index 4d32938..a583933 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "advent-rs" -version = "2015.12.1" +version = "2015.12.2" edition = "2021" authors = ["Arnaud 'red' Rouyer"] readme = "README.md" diff --git a/NOTES_2015.md b/NOTES_2015.md index 6c911a6..0377dab 100644 --- a/NOTES_2015.md +++ b/NOTES_2015.md @@ -10,14 +10,13 @@ test year_2015::day_01::tests::works_with_samples_v2 ... ok test year_2015_day_01 ... ok year_2015::day_01/year_2015::day_01_v1 - time: [5.1060 µs 5.1104 µs 5.1152 µs] + time: [6.2931 µs 6.8094 µs 7.3834 µs] year_2015::day_01/year_2015::day_01_v2 - time: [1.4617 µs 1.4620 µs 1.4623 µs] - + time: [1.9841 µs 1.9896 µs 1.9955 µs] year_2015::day_01_v1/Slow/7000 - time: [59.965 µs 60.418 µs 60.893 µs] + time: [63.548 µs 64.204 µs 64.821 µs] year_2015::day_01_v1/Fast/7000 - time: [5.6145 µs 5.9122 µs 6.2267 µs] + time: [5.6477 µs 5.8044 µs 6.0121 µs] ``` @@ -44,9 +43,9 @@ test year_2015::day_02::tests::works_with_samples_v2 ... ok test year_2015_day_02 ... ok year_2015::day_02/year_2015::day_02_v1 - time: [74.716 µs 74.839 µs 74.945 µs] + time: [74.835 µs 74.904 µs 74.977 µs] year_2015::day_02/year_2015::day_02_v2 - time: [74.636 µs 74.685 µs 74.727 µs] + time: [74.878 µs 74.969 µs 75.067 µs] ``` @@ -74,18 +73,17 @@ test year_2015::day_03::tests::works_with_samples_v2 ... ok test year_2015_day_03 ... ok year_2015::day_03/year_2015::day_03_v1 - time: [415.91 µs 416.24 µs 416.60 µs] + time: [232.27 µs 232.77 µs 233.35 µs] year_2015::day_03/year_2015::day_03_v2 - time: [440.35 µs 441.72 µs 442.91 µs] - + time: [250.97 µs 251.71 µs 252.48 µs] year_2015::day_03_v1/BTreeSet/8192 - time: [410.11 µs 411.30 µs 413.11 µs] + time: [401.94 µs 402.21 µs 402.50 µs] year_2015::day_03_v1/HashSet/8192 - time: [169.64 µs 169.95 µs 170.28 µs] + time: [234.20 µs 234.41 µs 234.64 µs] year_2015::day_03_v2/BTreeSet/8192 - time: [440.56 µs 441.85 µs 443.34 µs] + time: [432.48 µs 432.72 µs 432.98 µs] year_2015::day_03_v2/HashSet/8192 - time: [179.96 µs 180.06 µs 180.15 µs] + time: [252.37 µs 252.70 µs 253.00 µs] ``` @@ -107,15 +105,15 @@ This time, [the benchmark](benches/year_2015_day_03.rs) checks which of [`BTreeS 📊Tests and benchmarks ``` -test year_2015::day_04::tests::works_with_samples_v1 ... ignored -test year_2015::day_04::tests::works_with_samples_v2 ... ignored +test year_2015::day_04::tests::works_with_samples_v1 ... ok +test year_2015::day_04::tests::works_with_samples_v2 ... ok test year_2015_day_04 ... ok year_2015::day_04/year_2015::day_04_v1 - time: [65.402 ms 65.534 ms 65.640 ms] -Warning: Unable to complete 10 samples in 5.0s. You may wish to increase target time to 18.9s. + time: [36.404 ms 36.439 ms 36.457 ms] +Warning: Unable to complete 10 samples in 5.0s. You may wish to increase target time to 10.6s. year_2015::day_04/year_2015::day_04_v2 - time: [1.8911 s 1.8941 s 1.8969 s] + time: [1.0535 s 1.0541 s 1.0545 s] ``` @@ -140,9 +138,15 @@ test year_2015::day_05::tests::works_with_samples_v2 ... ok test year_2015_day_05 ... ok year_2015::day_05/year_2015::day_05_v1 - time: [142.32 µs 142.58 µs 142.91 µs] + time: [51.142 µs 51.447 µs 51.928 µs] + year_2015::day_05/year_2015::day_05_v2 - time: [299.92 µs 300.33 µs 300.68 µs] + time: [181.19 µs 181.42 µs 181.68 µs] + +year_2015::day_05_v1/contains/17000 + time: [95.128 µs 95.245 µs 95.361 µs] +year_2015::day_05_v1/chars/17000 + time: [50.388 µs 50.474 µs 50.563 µs] ``` @@ -165,9 +169,9 @@ test year_2015::day_06::tests::works_with_samples_v2 ... ok test year_2015_day_06 ... ok year_2015::day_06/year_2015::day_06_v1 - time: [13.269 ms 13.341 ms 13.423 ms] + time: [13.186 ms 13.320 ms 13.522 ms] year_2015::day_06/year_2015::day_06_v2 - time: [13.481 ms 13.585 ms 13.720 ms] + time: [13.437 ms 13.466 ms 13.499 ms] ``` @@ -198,9 +202,9 @@ test year_2015::day_07::tests::works_with_samples_v2 ... ok test year_2015_day_07 ... ok year_2015::day_07/year_2015::day_07_v1 - time: [63.406 µs 63.509 µs 63.606 µs] + time: [62.800 µs 62.873 µs 62.940 µs] year_2015::day_07/year_2015::day_07_v2 - time: [129.92 µs 130.54 µs 131.09 µs] + time: [127.35 µs 127.56 µs 127.82 µs] ``` @@ -229,9 +233,9 @@ test year_2015::day_08::tests::works_with_samples_v1 ... ok test year_2015::day_08::tests::works_with_samples_v2 ... ok year_2015::day_08/year_2015::day_08_v1 - time: [11.833 µs 11.907 µs 11.995 µs] + time: [13.389 µs 13.434 µs 13.486 µs] year_2015::day_08/year_2015::day_08_v2 - time: [8.3510 µs 8.6640 µs 9.1839 µs] + time: [8.7562 µs 8.8298 µs 8.9084 µs] ``` @@ -256,9 +260,9 @@ test year_2015::day_09::tests::works_with_samples_v2 ... ok test year_2015_day_09 ... ok year_2015::day_09/year_2015::day_09_v1 - time: [4.1046 ms 4.1171 ms 4.1298 ms] + time: [1.2927 ms 1.2995 ms 1.3064 ms] year_2015::day_09/year_2015::day_09_v2 - time: [4.1209 ms 4.1370 ms 4.1531 ms] + time: [4.0988 ms 4.1071 ms 4.1157 ms] ``` @@ -288,9 +292,9 @@ test year_2015::day_10::tests::looks_and_says_over_strings ... ok test year_2015_day_10 ... ok year_2015::day_10/year_2015::day_10_v1 - time: [2.7216 ms 2.7336 ms 2.7457 ms] + time: [870.36 µs 872.61 µs 875.35 µs] year_2015::day_10/year_2015::day_10_v2 - time: [37.291 ms 37.419 ms 37.551 ms] + time: [12.131 ms 12.153 ms 12.177 ms] ``` @@ -315,9 +319,9 @@ test year_2015::day_11::tests::works_with_samples_v1 ... ok test year_2015_day_11 ... ok year_2015::day_11/year_2015::day_11_v1 - time: [5.6672 ms 5.6736 ms 5.6797 ms] + time: [4.8713 ms 4.8800 ms 4.8927 ms] year_2015::day_11/year_2015::day_11_v2 - time: [29.014 ms 29.036 ms 29.057 ms] + time: [24.898 ms 24.958 ms 25.035 ms] ``` @@ -342,9 +346,9 @@ test year_2015::day_12::tests::works_with_samples_v2 ... ok test year_2015_day_12 ... ok year_2015::day_12/year_2015::day_12_v1 - time: [24.003 µs 24.055 µs 24.112 µs] + time: [17.760 µs 17.955 µs 18.183 µs] year_2015::day_12/year_2015::day_12_v2 - time: [39.613 µs 39.848 µs 40.091 µs] + time: [30.888 µs 31.305 µs 31.736 µs] ``` diff --git a/README.md b/README.md index 7d77f5f..0d3c54c 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,5 @@ Strangely, testing feels more natural in Rust than in Ruby. Since I've [already # Benchmarking I use [criterion.rs](https://github.com/bheisler/criterion.rs) for benchmarking, as it feels like the best option. I try to strive for the most effective solutions, without cutting corners. I could probably gain a lot more time in some spaces, but I'm going at my own speed for now. + +The speeds I'm reporting are what my Mac M2 reports, depending on how many Chrome tabs I got opened. It's just to give myself a pat on the back. diff --git a/inputs/year_2015_day_06_sample_v1 b/inputs/year_2015_day_06_sample_v1 deleted file mode 100644 index c2353b9..0000000 --- a/inputs/year_2015_day_06_sample_v1 +++ /dev/null @@ -1,3 +0,0 @@ -turn on 0,0 through 999,999 -toggle 0,0 through 999,0 -turn off 499,499 through 500,500 \ No newline at end of file diff --git a/inputs/year_2015_day_06_sample_v2 b/inputs/year_2015_day_06_sample_v2 deleted file mode 100644 index 1fd149a..0000000 --- a/inputs/year_2015_day_06_sample_v2 +++ /dev/null @@ -1,2 +0,0 @@ -turn on 0,0 through 0,0 -toggle 0,0 through 999,999 diff --git a/inputs/year_2015_day_07_sample_v1 b/inputs/year_2015_day_07_sample_v1 deleted file mode 100644 index 82b0bf0..0000000 --- a/inputs/year_2015_day_07_sample_v1 +++ /dev/null @@ -1,8 +0,0 @@ -123 -> x -456 -> b -x AND g -> a -x OR b -> e -x LSHIFT 2 -> f -b RSHIFT 2 -> g -NOT x -> h -NOT b -> i diff --git a/src/lib.rs b/src/lib.rs index 2287e3e..19f7ad0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,19 +35,27 @@ pub fn fetch_input(file_path: Option) -> Result /// Returns the solution for a specified exercise and input. /// /// # Arguments -/// /// * `year` - The year of the exercise, from 2015. /// * `day` - The day of the exercise, from 1 to 25. /// * `version` - The version of the exercise, 1 or 2. -/// * `input` - The input to the problem. +/// * `input` - The input to the exercise. +/// +/// # Examples +/// Non-existing year/day/version +/// ``` +/// use advent_rs::solve; +/// assert_eq!(solve(2014, 1, 1, ""), None); +/// assert_eq!(solve(2015, 1, 3, ""), None); +/// assert_eq!(solve(2015, 26, 1, ""), None); +/// ``` /// -/// # Example +/// Existing year/day/version returns a String /// ``` -/// use advent_of_code::solve; -/// let solution = solve(2019, 1, 1, "14"); -/// assert_eq!(solution, "2")); +/// use advent_rs::solve; +/// let solution = solve(2015, 1, 1, "(())"); +/// assert_eq!(solution, Some("0".to_string())); /// ``` -pub fn solve(year: u16, day: u8, version: u8, input: String) -> Option { +pub fn solve(year: u16, day: u8, version: u8, input: impl Into) -> Option { match year { 2015 => return year_2015::solve(day, version, input), _ => return None, diff --git a/src/year_2015.rs b/src/year_2015.rs index 093fc33..a7f985a 100644 --- a/src/year_2015.rs +++ b/src/year_2015.rs @@ -8,29 +8,56 @@ pub mod day_07; pub mod day_08; pub mod day_09; pub mod day_10; +pub mod day_11; +pub mod day_12; -pub fn solve(day: u8, version: u8, input: String) -> Option { +/// Returns the solution for a specified exercise and input. +/// +/// # Arguments +/// * `day` - The day of the exercise, from 1 to 25. +/// * `version` - The version of the exercise, 1 or 2. +/// * `input` - The input to the exercise. +/// +/// # Examples +/// Non-existing day/version +/// ``` +/// use advent_rs::year_2015::solve; +/// assert_eq!(solve(1, 3, ""), None); +/// assert_eq!(solve(26, 1, ""), None); +/// ``` +/// +/// Existing day/version returns a String +/// ``` +/// use advent_rs::year_2015::solve; +/// let solution = solve(1, 1, "(())"); +/// assert_eq!(solution, Some("0".to_string())); +/// ``` +pub fn solve(day: u8, version: u8, input: impl Into) -> Option { match (day, version) { - (1, 1) => return Some(format!("{}", day_01::day_01_v1(&input))), - (1, 2) => return Some(format!("{}", day_01::day_01_v2(&input))), - (2, 1) => return Some(format!("{}", day_02::day_02_v2(&input))), - (2, 2) => return Some(format!("{}", day_02::day_02_v2(&input))), - (3, 1) => return Some(format!("{}", day_03::day_03_v2(&input))), - (3, 2) => return Some(format!("{}", day_03::day_03_v2(&input))), - (4, 1) => return Some(format!("{}", day_04::day_04_v2(&input))), - (4, 2) => return Some(format!("{}", day_04::day_04_v2(&input))), - (5, 1) => return Some(format!("{}", day_05::day_05_v2(&input))), - (5, 2) => return Some(format!("{}", day_05::day_05_v2(&input))), - (6, 1) => return Some(format!("{}", day_06::day_06_v2(&input))), - (6, 2) => return Some(format!("{}", day_06::day_06_v2(&input))), - (7, 1) => return Some(format!("{}", day_07::day_07_v2(&input))), - (7, 2) => return Some(format!("{}", day_07::day_07_v2(&input))), - (8, 1) => return Some(format!("{}", day_08::day_08_v1(&input))), - (8, 2) => return Some(format!("{}", day_08::day_08_v2(&input))), - (9, 1) => return Some(format!("{}", day_09::day_09_v1(&input))), - (9, 2) => return Some(format!("{}", day_09::day_09_v2(&input))), - (10, 1) => return Some(format!("{}", day_10::day_10_v1(&input))), - (10, 2) => return Some(format!("{}", day_10::day_10_v2(&input))), + (1, 1) => return Some(format!("{}", day_01::day_01_v1(input))), + (1, 2) => return Some(format!("{}", day_01::day_01_v2(input))), + (2, 1) => return Some(format!("{}", day_02::day_02_v2(input))), + (2, 2) => return Some(format!("{}", day_02::day_02_v2(input))), + (3, 1) => return Some(format!("{}", day_03::day_03_v2(input))), + (3, 2) => return Some(format!("{}", day_03::day_03_v2(input))), + (4, 1) => return Some(format!("{}", day_04::day_04_v2(input))), + (4, 2) => return Some(format!("{}", day_04::day_04_v2(input))), + (5, 1) => return Some(format!("{}", day_05::day_05_v2(input))), + (5, 2) => return Some(format!("{}", day_05::day_05_v2(input))), + (6, 1) => return Some(format!("{}", day_06::day_06_v2(input))), + (6, 2) => return Some(format!("{}", day_06::day_06_v2(input))), + (7, 1) => return Some(format!("{}", day_07::day_07_v2(input))), + (7, 2) => return Some(format!("{}", day_07::day_07_v2(input))), + (8, 1) => return Some(format!("{}", day_08::day_08_v1(input))), + (8, 2) => return Some(format!("{}", day_08::day_08_v2(input))), + (9, 1) => return Some(format!("{}", day_09::day_09_v1(input))), + (9, 2) => return Some(format!("{}", day_09::day_09_v2(input))), + (10, 1) => return Some(format!("{}", day_10::day_10_v1(input))), + (10, 2) => return Some(format!("{}", day_10::day_10_v2(input))), + (11, 1) => return Some(format!("{}", day_11::day_11_v1(input))), + (11, 2) => return Some(format!("{}", day_11::day_11_v2(input))), + (12, 1) => return Some(format!("{}", day_12::day_12_v1(input))), + (12, 2) => return Some(format!("{}", day_12::day_12_v2(input))), _ => return None, } } diff --git a/src/year_2015/day_01.rs b/src/year_2015/day_01.rs index 80c9e44..66f6119 100644 --- a/src/year_2015/day_01.rs +++ b/src/year_2015/day_01.rs @@ -1,7 +1,7 @@ -pub fn day_01_v1(input: &str) -> i16 { +pub fn day_01_v1(input: impl Into) -> i16 { let mut lvl: i16 = 0; - for chr in input.chars() { + for chr in input.into().chars() { match chr { '(' => lvl += 1, ')' => lvl -= 1, @@ -11,10 +11,10 @@ pub fn day_01_v1(input: &str) -> i16 { lvl } -pub fn day_01_v2(input: &str) -> i16 { +pub fn day_01_v2(input: impl Into) -> i16 { let mut lvl: i16 = 0; - for (idx, chr) in input.chars().enumerate() { + for (idx, chr) in input.into().chars().enumerate() { match chr { '(' => lvl += 1, ')' => lvl -= 1, @@ -45,7 +45,7 @@ mod tests { (")())())", -3), ]; for (sample, result) in sample_one.iter() { - assert_eq!(day_01_v1(sample), *result); + assert_eq!(day_01_v1(*sample), *result); } } @@ -56,7 +56,7 @@ mod tests { ("()())", 5), ]; for (sample, result) in sample_two.iter() { - assert_eq!(day_01_v2(sample), *result); + assert_eq!(day_01_v2(*sample), *result); } } } diff --git a/src/year_2015/day_02.rs b/src/year_2015/day_02.rs index 239f88c..8efd40d 100644 --- a/src/year_2015/day_02.rs +++ b/src/year_2015/day_02.rs @@ -49,9 +49,9 @@ impl FromStr for PresentBox { } } -pub fn day_02_v1(input: &str) -> u32 { +pub fn day_02_v1(input: impl Into) -> u32 { let mut total: u32 = 0; - for line in input.lines() { + for line in input.into().lines() { match PresentBox::from_str(line) { Ok(present) => total += present.wrapper() as u32, Err(_) => {} @@ -60,9 +60,9 @@ pub fn day_02_v1(input: &str) -> u32 { total } -pub fn day_02_v2(input: &str) -> u32 { +pub fn day_02_v2(input: impl Into) -> u32 { let mut total: u32 = 0; - for line in input.lines() { + for line in input.into().lines() { match PresentBox::from_str(line) { Ok(present) => total += present.ribbon() as u32, Err(_) => {} @@ -82,7 +82,7 @@ mod tests { ("1x1x10", 43), ]; for (sample, result) in sample_one.iter() { - assert_eq!(day_02_v1(sample), *result); + assert_eq!(day_02_v1(*sample), *result); } } @@ -94,7 +94,7 @@ mod tests { ]; for (sample, result) in sample_two.iter() { - assert_eq!(day_02_v2(sample), *result); + assert_eq!(day_02_v2(*sample), *result); } } } diff --git a/src/year_2015/day_03.rs b/src/year_2015/day_03.rs index bd54a96..3428504 100644 --- a/src/year_2015/day_03.rs +++ b/src/year_2015/day_03.rs @@ -13,22 +13,22 @@ fn move_character(pos: (i8, i8), direction: char) -> (i8, i8) { newpos } -pub fn day_03_v1(input: &str) -> usize { +pub fn day_03_v1(input: impl Into) -> usize { let mut santa: (i8, i8) = (0, 0); let mut houses = HashSet::from([santa]); - for (_idx, chr) in input.chars().enumerate() { + for (_idx, chr) in input.into().chars().enumerate() { santa = move_character(santa, chr); houses.insert(santa); } return houses.len() as usize; } -pub fn day_03_v2(input: &str) -> usize { +pub fn day_03_v2(input: impl Into) -> usize { let mut santa: (i8, i8) = (0, 0); let mut robot: (i8, i8) = (0, 0); let mut houses = HashSet::from([santa]); - let moves: Vec = input.chars().collect(); + let moves: Vec = input.into().chars().collect(); for chars in moves.chunks(2) { santa = move_character(santa, chars[0]); @@ -66,7 +66,7 @@ mod tests { ]; for (sample, result) in sample_one.iter() { - assert_eq!(day_03_v1(sample), *result); + assert_eq!(day_03_v1(*sample), *result); } } @@ -79,7 +79,7 @@ mod tests { ]; for (sample, result) in sample_two.iter() { - assert_eq!(day_03_v2(sample), *result); + assert_eq!(day_03_v2(*sample), *result); } } } diff --git a/src/year_2015/day_04.rs b/src/year_2015/day_04.rs index 4041aee..4a00501 100644 --- a/src/year_2015/day_04.rs +++ b/src/year_2015/day_04.rs @@ -3,8 +3,12 @@ use md5::{Digest, Md5}; #[mutants::skip] // Don't even try this hahaha pub fn loop_until_hash(input: &str, stop_value: u8) -> u32 { let mut starter: u32 = 0; + let mut hasher = Md5::new(); + hasher.update(input); loop { - let hash = Md5::digest(format!("{input}{starter}")); + let mut hasher_num = hasher.clone(); + hasher_num.update(starter.to_string()); + let hash = hasher_num.finalize(); if hash[..2] == [0, 0] && hash[2] <= stop_value { return starter; } @@ -13,13 +17,15 @@ pub fn loop_until_hash(input: &str, stop_value: u8) -> u32 { } } -pub fn day_04_v1(input: &str) -> u32 { - let clean_str = input.lines().next().expect("OK"); +pub fn day_04_v1(input: impl Into) -> u32 { + let input_str = input.into(); + let clean_str = input_str.lines().next().expect("OK"); return loop_until_hash(clean_str, 15); } -pub fn day_04_v2(input: &str) -> u32 { - let clean_str = input.lines().next().expect("OK"); +pub fn day_04_v2(input: impl Into) -> u32 { + let input_str = input.into(); + let clean_str = input_str.lines().next().expect("OK"); return loop_until_hash(clean_str, 0); } @@ -34,7 +40,7 @@ mod tests { ("pqrstuv", 1048970), ]; for (sample, result) in sample_one.iter() { - assert_eq!(day_04_v1(sample), *result); + assert_eq!(day_04_v1(*sample), *result); } } diff --git a/src/year_2015/day_05.rs b/src/year_2015/day_05.rs index 614efef..dc22086 100644 --- a/src/year_2015/day_05.rs +++ b/src/year_2015/day_05.rs @@ -1,5 +1,5 @@ fn string_is_nice_v1(input: &str) -> bool { - let mut vowels = 0; + let mut vowels: u8 = 0; let mut repeated = false; let no_naughty_sequences = input.chars().try_fold(' ', |acc, elt| { if acc == 'a' && elt == 'b' { @@ -22,7 +22,6 @@ fn string_is_nice_v1(input: &str) -> bool { } return Ok(elt); }); - return no_naughty_sequences != Err('-') && repeated && vowels >= 3; } @@ -34,21 +33,32 @@ fn string_is_nice_v2(input: &str) -> bool { if letters[i] == letters[i + 2] { repeated = true; } - let pattern = &input[i..(i + 2)]; - let ending = &input[i + 2..input.len()]; - if ending.contains(pattern) { - twice_pair = true; + if twice_pair { + continue; + } + for j in i + 2..input.len() - 1 { + if letters[i] == letters[j] && letters[i + 1] == letters[j + 1] { + twice_pair = true; + } } } return twice_pair && repeated; } -pub fn day_05_v1(input: &str) -> u32 { - return input.lines().filter(|line| string_is_nice_v1(line)).count() as u32; +pub fn day_05_v1(input: impl Into) -> u32 { + let input_str = input.into(); + return input_str + .lines() + .filter(|line| string_is_nice_v1(line)) + .count() as u32; } -pub fn day_05_v2(input: &str) -> u32 { - return input.lines().filter(|line| string_is_nice_v2(line)).count() as u32; +pub fn day_05_v2(input: impl Into) -> u32 { + let input_str = input.into(); + return input_str + .lines() + .filter(|line| string_is_nice_v2(line)) + .count() as u32; } #[cfg(test)] @@ -65,7 +75,7 @@ mod tests { ("dvszwmarrgswjxmb", false), ]; for (sample, result) in sample_one.iter() { - assert_eq!(string_is_nice_v1(sample), *result); + assert_eq!(string_is_nice_v1(*sample), *result); } } @@ -78,7 +88,7 @@ mod tests { ("ieodomkazucvgmuy", false), ]; for (sample, result) in sample_two.iter() { - assert_eq!(string_is_nice_v2(sample), *result); + assert_eq!(string_is_nice_v2(*sample), *result); } } diff --git a/src/year_2015/day_06.rs b/src/year_2015/day_06.rs index 96016f7..4abf7d6 100644 --- a/src/year_2015/day_06.rs +++ b/src/year_2015/day_06.rs @@ -31,10 +31,10 @@ where } } -pub fn day_06_v1(input: &str) -> u32 { +pub fn day_06_v1(input: impl Into) -> u32 { let re = Regex::new(r"(?on|off|toggle) (?\d+,\d+) through (?\d+,\d+)").unwrap(); let mut light_grid: Vec = vec![0_u8; 1_000_000]; - for line in input.lines() { + for line in input.into().lines() { let Some(caps) = re.captures(line) else { panic!("Invalid instruction: {}", line) }; @@ -70,10 +70,10 @@ pub fn day_06_v1(input: &str) -> u32 { return light_grid.iter().map(|&i| i as u32).sum(); } -pub fn day_06_v2(input: &str) -> u32 { +pub fn day_06_v2(input: impl Into) -> u32 { let re = Regex::new(r"(?on|off|toggle) (?\d+,\d+) through (?\d+,\d+)").unwrap(); let mut light_grid: Vec = vec![0_u8; 1_000_000]; - for line in input.lines() { + for line in input.into().lines() { let Some(caps) = re.captures(line) else { panic!("Invalid instruction: {}", line) }; @@ -121,13 +121,16 @@ mod tests { #[test] fn works_with_samples_v1() { - let sample_one = include_str!("../../inputs/year_2015_day_06_sample_v1"); + let sample_one = r#"turn on 0,0 through 999,999 + toggle 0,0 through 999,0 + turn off 499,499 through 500,500"#; assert_eq!(day_06_v1(sample_one), 998_996); } #[test] fn works_with_samples_v2() { - let sample_two = include_str!("../../inputs/year_2015_day_06_sample_v2"); + let sample_two = r#"turn on 0,0 through 0,0 + toggle 0,0 through 999,999"#; assert_eq!(day_06_v2(sample_two), 2_000_001); } } diff --git a/src/year_2015/day_07.rs b/src/year_2015/day_07.rs index f7e5e5e..82a48c8 100644 --- a/src/year_2015/day_07.rs +++ b/src/year_2015/day_07.rs @@ -67,9 +67,10 @@ fn create_gate<'a>(gates: &mut HashMap<&'a str, LogicalGate<'a>>, line: &'a str) gates.insert(wire, gate); } -pub fn day_07_v1(input: &str) -> u32 { +pub fn day_07_v1(input: impl Into) -> u32 { + let input_str = input.into(); let mut gates: HashMap<&str, LogicalGate> = HashMap::new(); - for line in input.lines() { + for line in input_str.lines() { create_gate(&mut gates, line); } let Some(result) = value_of(&mut gates, "a") else { @@ -78,12 +79,13 @@ pub fn day_07_v1(input: &str) -> u32 { return result; } -pub fn day_07_v2(input: &str) -> u32 { +pub fn day_07_v2(input: impl Into) -> u32 { + let input_str = input.into(); let mut gates: HashMap<&str, LogicalGate> = HashMap::new(); - for line in input.lines() { + for line in input_str.lines() { create_gate(&mut gates, line); } - let value_of_a = day_07_v1(input); + let value_of_a = day_07_v1(&input_str); let value_a = format!("{}", value_of_a); let gate = LogicalGate { operation: Operation::Assign(value_a.as_str()), @@ -103,13 +105,27 @@ mod tests { #[test] fn works_with_samples_v1() { - let sample_one = include_str!("../../inputs/year_2015_day_07_sample_v1"); + let sample_one = "123 -> x\n\ + 456 -> b\n\ + x AND g -> a\n\ + x OR b -> e\n\ + x LSHIFT 2 -> f\n\ + b RSHIFT 2 -> g\n\ + NOT x -> h\n\ + NOT b -> i"; assert_eq!(day_07_v1(sample_one), 114); } #[test] fn works_with_samples_v2() { - let sample_one = include_str!("../../inputs/year_2015_day_07_sample_v1"); + let sample_one = "123 -> x\n\ + 456 -> b\n\ + x AND g -> a\n\ + x OR b -> e\n\ + x LSHIFT 2 -> f\n\ + b RSHIFT 2 -> g\n\ + NOT x -> h\n\ + NOT b -> i"; assert_eq!(day_07_v2(sample_one), 24); } } diff --git a/src/year_2015/day_08.rs b/src/year_2015/day_08.rs index 48b1ed4..5badc3f 100644 --- a/src/year_2015/day_08.rs +++ b/src/year_2015/day_08.rs @@ -1,7 +1,3 @@ -fn code_line_len(line: &str) -> u16 { - line.len() as u16 -} - fn memory_line_len(line: &str) -> u16 { let mut line_len = line.len() as u16 - 2; let mut idx: usize = 1; @@ -13,11 +9,11 @@ fn memory_line_len(line: &str) -> u16 { idx += 2; } r#"\x"# => { - let num_tokens = &line[idx + 2..=idx + 3]; - if u32::from_str_radix(num_tokens, 16).ok().is_some() { - line_len -= 3; - idx += 4; - } + // let num_tokens = &line[idx + 2..=idx + 3]; + // if u32::from_str_radix(num_tokens, 16).ok().is_some() { + line_len -= 3; + idx += 4; + // } } _ => idx += 1, } @@ -28,28 +24,26 @@ fn memory_line_len(line: &str) -> u16 { fn dumped_line_len(line: &str) -> u16 { let mut line_len = line.len() as u16 + 2 as u16; - for char in line.chars() { - match char { - '"' => line_len += 1, - '\\' => line_len += 1, - _ => {} + for chr in line.chars() { + if chr == '"' || chr == '\\' { + line_len += 1; } } line_len } -pub fn day_08_v1(input: &str) -> u16 { +pub fn day_08_v1(input: impl Into) -> u16 { let mut total: u16 = 0; - for line in input.lines() { - total += code_line_len(line) - memory_line_len(line); + for line in input.into().lines() { + total += line.len() as u16 - memory_line_len(line); } total } -pub fn day_08_v2(input: &str) -> u16 { +pub fn day_08_v2(input: impl Into) -> u16 { let mut total: u16 = 0; - for line in input.lines() { - total += dumped_line_len(line) - code_line_len(line); + for line in input.into().lines() { + total += dumped_line_len(line) - line.len() as u16; } total } @@ -58,19 +52,6 @@ pub fn day_08_v2(input: &str) -> u16 { mod tests { use super::*; - #[test] - fn calculates_length_of_code_strings() { - let sample_one: [(&str, u16); 4] = [ - (r#""""#, 2), - (r#""abc""#, 5), - (r#""aaa\"aaa""#, 10), - (r#""\x27""#, 6), - ]; - for (sample, result) in sample_one.iter() { - assert_eq!(code_line_len(sample), *result); - } - } - #[test] fn calculates_length_of_memory_strings() { let sample_one: [(&str, u16); 4] = [ @@ -93,7 +74,7 @@ mod tests { (r#""\x27""#, 11), ]; for (sample, result) in sample_one.iter() { - assert_eq!(dumped_line_len(sample), *result); + assert_eq!(dumped_line_len(*sample), *result); } } @@ -106,7 +87,7 @@ mod tests { (r#""\x27""#, 5), ]; for (sample, result) in sample_one.iter() { - assert_eq!(day_08_v1(sample), *result); + assert_eq!(day_08_v1(*sample), *result); } } @@ -119,7 +100,7 @@ mod tests { (r#""\x27""#, 5), ]; for (sample, result) in sample_one.iter() { - assert_eq!(day_08_v2(sample), *result); + assert_eq!(day_08_v2(*sample), *result); } } diff --git a/src/year_2015/day_09.rs b/src/year_2015/day_09.rs index dd14bbe..0b1c766 100644 --- a/src/year_2015/day_09.rs +++ b/src/year_2015/day_09.rs @@ -38,18 +38,20 @@ fn next_cities_ids<'a>(input: &Vec, needle: &u8) -> Vec { return new_vec; } -fn try_best_path<'a, CMP>( +fn try_best_path<'a, STP, CMP>( paths: &HashMap<(u8, u8), u16>, current_city: &u8, cities: Vec, + stopper_func: &STP, path_is_better: &CMP, current_path: &'a u16, current_best: &'a u16, ) -> u16 where + STP: Fn(u16, u16, usize) -> bool, CMP: Fn(u16, u16) -> bool, { - if cities.len() == 0 { + if stopper_func(*current_best, *current_path, cities.len()) { return *current_path; } let mut best_path = *current_best; @@ -63,6 +65,7 @@ where &paths, city_id, next_cities_ids(&cities, city_id), + stopper_func, path_is_better, &next_path, current_best, @@ -74,14 +77,15 @@ where best_path } -pub fn day_09_v1<'a>(input: &str) -> u16 { - let (cities_ids, paths) = parse_input(input); +pub fn day_09_v1<'a>(input: impl Into) -> u16 { + let (cities_ids, paths) = parse_input(&input.into()); let mut best_path = u16::MAX; for city_id in cities_ids.iter() { let new_best = try_best_path( &paths, city_id, next_cities_ids(&cities_ids, city_id), + &|best, cur, cities_len| best < cur || cities_len == 0, &|best, cur| cur < best, &0, &best_path, @@ -93,14 +97,15 @@ pub fn day_09_v1<'a>(input: &str) -> u16 { best_path } -pub fn day_09_v2<'a>(input: &str) -> u16 { - let (cities_ids, paths) = parse_input(input); +pub fn day_09_v2<'a>(input: impl Into) -> u16 { + let (cities_ids, paths) = parse_input(&input.into()); let mut best_path = 0; for city_id in cities_ids.iter() { let new_best = try_best_path( &paths, city_id, next_cities_ids(&cities_ids, city_id), + &|_best, _cur, cities_len| cities_len == 0, &|best, cur| cur > best, &0, &best_path, diff --git a/src/year_2015/day_10.rs b/src/year_2015/day_10.rs index 4baf143..daf613c 100644 --- a/src/year_2015/day_10.rs +++ b/src/year_2015/day_10.rs @@ -3,17 +3,17 @@ use itertools::Itertools; fn look_and_say(input: Vec) -> Vec { let mut current_cnt: u8 = 0; let mut current_chr: u8 = input[0]; - let mut new_seq = input.iter().fold(vec![], |mut acc, chr| { + let mut new_seq: Vec = Vec::new(); + for chr in input.iter() { if *chr == current_chr { current_cnt += 1; } else { - acc.push(current_cnt); - acc.push(current_chr); + new_seq.push(current_cnt); + new_seq.push(current_chr); current_cnt = 1; current_chr = *chr; } - acc - }); + } new_seq.push(current_cnt); new_seq.push(current_chr); @@ -31,16 +31,16 @@ fn string_to_chr(input: &str) -> Vec { .collect_vec() } -pub fn day_10_v1(input: &str) -> u32 { - let mut next_input: Vec = string_to_chr(input); +pub fn day_10_v1(input: impl Into) -> u32 { + let mut next_input: Vec = string_to_chr(&input.into()); for _n in 1..=40 { next_input = look_and_say(next_input); } next_input.len() as u32 } -pub fn day_10_v2(input: &str) -> u32 { - let mut next_input: Vec = string_to_chr(input); +pub fn day_10_v2(input: impl Into) -> u32 { + let mut next_input: Vec = string_to_chr(&input.into()); for _n in 1..=50 { next_input = look_and_say(next_input); } diff --git a/src/year_2015/day_12.rs b/src/year_2015/day_12.rs index cdf10d9..3c91303 100644 --- a/src/year_2015/day_12.rs +++ b/src/year_2015/day_12.rs @@ -13,6 +13,9 @@ fn traverse_node_value(input: &Vec, idx: usize) -> (i32, usize) { total += input[idx + length] as i32 - 48; } _ => { + if length == 0 { + return (0, 1); + } return (total * min, length - 1); } }; @@ -24,11 +27,11 @@ fn traverse_node_array(input: &Vec, idx: usize) -> (i32, usize) { let mut total: i32 = 0; let mut length: usize = 1; loop { - if idx + length >= input.len() || input[idx + length] == b']' { - return (total, length); - } match input[idx + length] { - b'-' | b'0'..=b'9' => { + b']' => { + return (total, length); + } + b'-'..=b'9' => { let (add_total, add_length) = traverse_node_value(input, idx + length); total += add_total; length += add_length; @@ -54,14 +57,14 @@ fn traverse_node_hash(input: &Vec, idx: usize) -> (i32, usize) { let mut length: usize = 1; let mut no_red = true; loop { - if idx + length >= input.len() || input[idx + length] == b'}' { - if no_red == false { - total = 0; - } - return (total, length); - } match input[idx + length] { - b'-' | b'0'..=b'9' => { + b'}' => { + if no_red == false { + total = 0; + } + return (total, length); + } + b'-'..=b'9' => { let (add_total, add_length) = traverse_node_value(input, idx + length); total += add_total; length += add_length; @@ -77,8 +80,8 @@ fn traverse_node_hash(input: &Vec, idx: usize) -> (i32, usize) { length += add_length; } b'r' => { - if input[idx + length - 1..=idx + length + 3] == *r#""red""#.as_bytes() { - length += 2; + if no_red && input[idx + length - 1..=idx + length + 3] == *r#""red""#.as_bytes() { + length += 3; no_red = false; } } @@ -90,25 +93,19 @@ fn traverse_node_hash(input: &Vec, idx: usize) -> (i32, usize) { pub fn day_12_v1(input: impl Into) -> i32 { let mut total: i32 = 0; - let mut cur: i32 = 0; - let mut min: i32 = 1; - for chr in input.into().as_bytes().iter() { - match chr { - b'-' => { - min = -1; - } - b'0'..=b'9' => { - cur *= 10; - cur += *chr as i32 - 48; - } - _ => { - if cur > 0 { - total += cur * min; - } - cur = 0; - min = 1; + let mut idx = 0; + + let letters: Vec = input.into().into_bytes(); + while idx < letters.len() - 1 { + match letters[idx] { + b'-'..=b'9' => { + let (add_total, add_length) = traverse_node_value(&letters, idx); + total += add_total; + idx += add_length; } - } + _ => {} + }; + idx += 1; } total