diff options
| -rw-r--r-- | .idea/aoc2024.iml | 1 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | day4/Cargo.toml | 8 | ||||
| -rw-r--r-- | day4/src/main.rs | 215 |
4 files changed, 225 insertions, 1 deletions
diff --git a/.idea/aoc2024.iml b/.idea/aoc2024.iml index 779b5d8..5a17898 100644 --- a/.idea/aoc2024.iml +++ b/.idea/aoc2024.iml | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> | 7 | <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> |
| 8 | <sourceFolder url="file://$MODULE_DIR$/day2/src" isTestSource="false" /> | 8 | <sourceFolder url="file://$MODULE_DIR$/day2/src" isTestSource="false" /> |
| 9 | <sourceFolder url="file://$MODULE_DIR$/day3/src" isTestSource="false" /> | 9 | <sourceFolder url="file://$MODULE_DIR$/day3/src" isTestSource="false" /> |
| 10 | <sourceFolder url="file://$MODULE_DIR$/day4/src" isTestSource="false" /> | ||
| 10 | <excludeFolder url="file://$MODULE_DIR$/aoc/target" /> | 11 | <excludeFolder url="file://$MODULE_DIR$/aoc/target" /> |
| 11 | <excludeFolder url="file://$MODULE_DIR$/target" /> | 12 | <excludeFolder url="file://$MODULE_DIR$/target" /> |
| 12 | </content> | 13 | </content> |
| @@ -1,3 +1,3 @@ | |||
| 1 | [workspace] | 1 | [workspace] |
| 2 | members = ["aoc", "day1", "day2", "day3"] | 2 | members = ["aoc", "day1", "day2", "day3", "day4"] |
| 3 | resolver = "2" | 3 | resolver = "2" |
diff --git a/day4/Cargo.toml b/day4/Cargo.toml new file mode 100644 index 0000000..3161844 --- /dev/null +++ b/day4/Cargo.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [package] | ||
| 2 | name = "day4" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | aoc = { path = "../aoc" } | ||
| 8 | regex = "1.11.1" | ||
diff --git a/day4/src/main.rs b/day4/src/main.rs new file mode 100644 index 0000000..c788292 --- /dev/null +++ b/day4/src/main.rs | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | use aoc; | ||
| 2 | use std::io::{BufRead, BufReader, Read}; | ||
| 3 | use aoc::Day; | ||
| 4 | use regex::Regex; | ||
| 5 | |||
| 6 | struct Day4 {} | ||
| 7 | |||
| 8 | enum Direction { | ||
| 9 | Horizontal, | ||
| 10 | Vertical, | ||
| 11 | DiagonalDown, | ||
| 12 | DiagonalUp, | ||
| 13 | } | ||
| 14 | |||
| 15 | impl Day4 { | ||
| 16 | fn parse_input(&self, input: BufReader<Box<dyn Read>>) -> Vec<String> { | ||
| 17 | input | ||
| 18 | .lines() | ||
| 19 | .map(|l| { | ||
| 20 | l | ||
| 21 | .unwrap() | ||
| 22 | .trim() | ||
| 23 | .to_string() | ||
| 24 | }) | ||
| 25 | .collect::<Vec<String>>() | ||
| 26 | } | ||
| 27 | |||
| 28 | fn _diagonal_half_loop(&self, input: &Vec<String>) -> Vec<String> { | ||
| 29 | let mut out: Vec<String> = vec![]; | ||
| 30 | for y in 0..input.len() { | ||
| 31 | let mut out_row = String::new(); | ||
| 32 | |||
| 33 | for (x, row) in input[0..y + 1].iter().rev().enumerate() { | ||
| 34 | out_row.push(row.chars().nth(x).unwrap()); | ||
| 35 | } | ||
| 36 | |||
| 37 | out.push(out_row) | ||
| 38 | } | ||
| 39 | |||
| 40 | out | ||
| 41 | } | ||
| 42 | |||
| 43 | fn _rotate(&self, input: &Vec<String>) -> Vec<String> { | ||
| 44 | let mut output: Vec<String> = vec![]; | ||
| 45 | |||
| 46 | for (i, _) in input[0].char_indices() { | ||
| 47 | let mut line_out = String::new(); | ||
| 48 | for line in input { | ||
| 49 | let a = line.chars().nth(i).unwrap(); | ||
| 50 | line_out.push(a) | ||
| 51 | } | ||
| 52 | |||
| 53 | output.push(line_out.chars().rev().collect::<String>()); | ||
| 54 | } | ||
| 55 | |||
| 56 | output | ||
| 57 | } | ||
| 58 | |||
| 59 | fn _mirror(&self, input: &Vec<String>) -> Vec<String> { | ||
| 60 | input | ||
| 61 | .iter() | ||
| 62 | .map(|l| { | ||
| 63 | l | ||
| 64 | .chars() | ||
| 65 | .rev() | ||
| 66 | .collect::<String>() | ||
| 67 | }) | ||
| 68 | .collect::<Vec<String>>() | ||
| 69 | } | ||
| 70 | |||
| 71 | fn diagonal_loop(&self, input: &Vec<String>) -> Vec<String> { | ||
| 72 | let mut first_half: Vec<String> = self._diagonal_half_loop(input); | ||
| 73 | |||
| 74 | let rev_input = input | ||
| 75 | .iter() | ||
| 76 | .rev() | ||
| 77 | .map(|row| { | ||
| 78 | row | ||
| 79 | .chars() | ||
| 80 | .rev() | ||
| 81 | .collect::<String>() | ||
| 82 | }) | ||
| 83 | .collect::<Vec<String>>(); | ||
| 84 | |||
| 85 | |||
| 86 | let mut second_half = self | ||
| 87 | ._diagonal_half_loop(&rev_input) | ||
| 88 | .iter() | ||
| 89 | .rev() | ||
| 90 | .collect::<Vec<_>>()[1..] | ||
| 91 | .iter() | ||
| 92 | .map(|row| { | ||
| 93 | row | ||
| 94 | .chars() | ||
| 95 | .rev() | ||
| 96 | .collect::<String>() | ||
| 97 | }) | ||
| 98 | .collect::<Vec<String>>(); | ||
| 99 | |||
| 100 | |||
| 101 | first_half.append(&mut second_half); | ||
| 102 | first_half | ||
| 103 | } | ||
| 104 | |||
| 105 | fn loop_over_puzzle(&self, input: &Vec<String>, direction: Direction, rev: bool) -> Vec<String> { | ||
| 106 | let _input = if rev { | ||
| 107 | self._rotate(&self._rotate(&input)) | ||
| 108 | } else { | ||
| 109 | input.clone() | ||
| 110 | }; | ||
| 111 | |||
| 112 | |||
| 113 | match direction { | ||
| 114 | Direction::Horizontal => _input, | ||
| 115 | Direction::Vertical => self._mirror(&self._rotate(&_input)), | ||
| 116 | Direction::DiagonalUp => self.diagonal_loop(&_input), | ||
| 117 | Direction::DiagonalDown => self.diagonal_loop(&self._rotate(&_input)), | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | impl Day for Day4 { | ||
| 123 | fn example_input(&self) -> &'static str { | ||
| 124 | r#" | ||
| 125 | MMMSXXMASM | ||
| 126 | MSAMXMSMSA | ||
| 127 | AMXSXMAAMM | ||
| 128 | MSAMASMSMX | ||
| 129 | XMASAMXAMM | ||
| 130 | XXAMMXXAMA | ||
| 131 | SMSMSASXSS | ||
| 132 | SAXAMASAAA | ||
| 133 | MAMMMXMMMM | ||
| 134 | MXMXAXMASX | ||
| 135 | "#.trim() | ||
| 136 | // r#" | ||
| 137 | // 123 | ||
| 138 | // 456 | ||
| 139 | // 789 | ||
| 140 | // "#.trim() | ||
| 141 | } | ||
| 142 | |||
| 143 | fn example_result_part_1(&self) -> &'static str { | ||
| 144 | "18" | ||
| 145 | } | ||
| 146 | |||
| 147 | fn example_result_part_2(&self) -> &'static str { | ||
| 148 | "9" | ||
| 149 | } | ||
| 150 | |||
| 151 | fn part_1(&self, input: BufReader<Box<dyn Read>>) -> String { | ||
| 152 | let puzzle = self.parse_input(input); | ||
| 153 | |||
| 154 | let mut all_possibilities: Vec<String> = vec![]; | ||
| 155 | |||
| 156 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::Horizontal, false)); | ||
| 157 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::Horizontal, true)); | ||
| 158 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::Vertical, false)); | ||
| 159 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::Vertical, true)); | ||
| 160 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::DiagonalUp, false)); | ||
| 161 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::DiagonalUp, true)); | ||
| 162 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::DiagonalDown, false)); | ||
| 163 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::DiagonalDown, true)); | ||
| 164 | |||
| 165 | let re = Regex::new("XMAS"); | ||
| 166 | all_possibilities | ||
| 167 | .into_iter() | ||
| 168 | .map(|l| { | ||
| 169 | re | ||
| 170 | .clone() | ||
| 171 | .unwrap() | ||
| 172 | .find_iter(&l) | ||
| 173 | .count() | ||
| 174 | }) | ||
| 175 | .sum::<usize>() | ||
| 176 | .to_string() | ||
| 177 | } | ||
| 178 | |||
| 179 | fn part_2(&self, input: BufReader<Box<dyn Read>>) -> String { | ||
| 180 | let puzzle = self.parse_input(input); | ||
| 181 | |||
| 182 | let mut all_possibilities: Vec<String> = vec![]; | ||
| 183 | |||
| 184 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::DiagonalUp, false)); | ||
| 185 | all_possibilities.append(&mut self.loop_over_puzzle(&puzzle, Direction::DiagonalDown, false)); | ||
| 186 | |||
| 187 | let re = Regex::new("MAS|SAM"); | ||
| 188 | all_possibilities | ||
| 189 | .into_iter() | ||
| 190 | .map(|l| { | ||
| 191 | re | ||
| 192 | .clone() | ||
| 193 | .unwrap() | ||
| 194 | .find_iter(&l) | ||
| 195 | .map(|m| println!("{:#?}", m)) | ||
| 196 | .count() | ||
| 197 | }) | ||
| 198 | .sum::<usize>() | ||
| 199 | .to_string() | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | |||
| 204 | fn main() { | ||
| 205 | aoc::main(&Day4 {}); | ||
| 206 | } | ||
| 207 | |||
| 208 | #[cfg(test)] | ||
| 209 | mod tests { | ||
| 210 | use super::*; | ||
| 211 | #[test] | ||
| 212 | fn test_day4() { | ||
| 213 | aoc::test_day(&Day4 {}); | ||
