diff --git a/day_04/README.md b/day_04/README.md new file mode 100644 index 0000000..8f682e9 --- /dev/null +++ b/day_04/README.md @@ -0,0 +1,85 @@ +# --- Day 4: Ceres Search --- + +"Looks like the Chief's not here. Next!" One of The Historians pulls out a device and pushes the only button on it. After a brief flash, you recognize the interior of the Ceres monitoring station! + +As the search for the Chief continues, a small Elf who lives on the station tugs on your shirt; she'd like to know if you could help her with her word search (your puzzle input). She only has to find one word: `XMAS`. + +This word search allows words to be horizontal, vertical, diagonal, written backwards, or even overlapping other words. It's a little unusual, though, as you don't merely need to find one instance of `XMAS` - you need to find all of them. Here are a few ways `XMAS` might appear, where irrelevant characters have been replaced with `.`: + +``` +..X... +.SAMX. +.A..A. +XMAS.S +.X.... +``` + +The actual word search will be full of letters instead. For example: + +``` +MMMSXXMASM +MSAMXMSMSA +AMXSXMAAMM +MSAMASMSMX +XMASAMXAMM +XXAMMXXAMA +SMSMSASXSS +SAXAMASAAA +MAMMMXMMMM +MXMXAXMASX +``` + +In this word search, XMAS occurs a total of 18 times; here's the same word search again, but where letters not involved in any XMAS have been replaced with .: + +``` +....XXMAS. +.SAMXMS... +...S..A... +..A.A.MS.X +XMASAMX.MM +X.....XA.A +S.S.S.S.SS +.A.A.A.A.A +..M.M.M.MM +.X.X.XMASX +``` + +Take a look at the little Elf's word search. How many times does XMAS appear? + +Your puzzle answer was 2524. +# --- Part Two --- + +The Elf looks quizzically at you. Did you misunderstand the assignment? + +Looking for the instructions, you flip over the word search to find that this isn't actually an XMAS puzzle; it's an X-MAS puzzle in which you're supposed to find two MAS in the shape of an X. One way to achieve that is like this: + +``` +M.S +.A. +M.S +``` + +Irrelevant characters have again been replaced with . in the above diagram. Within the X, each MAS can be written forwards or backwards. + +Here's the same example from before, but this time all of the X-MASes have been kept instead: + +``` +.M.S...... +..A..MSMS. +.M.S.MAA.. +..A.ASMSM. +.M.S.M.... +.......... +S.S.S.S.S. +.A.A.A.A.. +M.M.M.M.M. +.......... +``` + +In this example, an X-MAS appears 9 times. + +Flip the word search from the instructions back over to the word search side and try again. How many times does an X-MAS appear? + +Your puzzle answer was 1873. + +Both parts of this puzzle are complete! They provide two gold stars: ** \ No newline at end of file diff --git a/day_04/src/crossword.rs b/day_04/src/crossword.rs index a5b4d3e..4f609c2 100644 --- a/day_04/src/crossword.rs +++ b/day_04/src/crossword.rs @@ -28,18 +28,24 @@ impl<'a> CrosswordCell<'a> { self.value_by_index(self.x, self.y) } - fn take(&self, num_of_letters: usize, direction: (isize, isize)) -> String { + fn take(&self, num_of_letters: usize, direction: (isize, isize), start: isize) -> String { let mut word = String::new(); - for i in 0..num_of_letters { - let x = self.x as isize + (i as isize * direction.1); - let y = self.y as isize + (i as isize * direction.0); + let end = start + num_of_letters as isize; + + for i in start..end { + let x = self.x as isize + (i * direction.1); + let y = self.y as isize + (i * direction.0); if x < 0 || x >= self.crossword.width as isize || y < 0 || y >= self.crossword.height as isize { - break; + if i < 0 { + continue; + } else { + break; + } } word.push(self.value_by_index(x as usize, y as usize)); } @@ -47,36 +53,76 @@ impl<'a> CrosswordCell<'a> { word } + const DIRECTION_N: (isize, isize) = (-1, 0); pub fn n(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (-1, 0)) + self.take(num_of_letters, CrosswordCell::DIRECTION_N, 0) } + pub fn n2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_N, start) + } + + const DIRECTION_NE: (isize, isize) = (-1, 1); pub fn ne(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (-1, 1)) + self.take(num_of_letters, CrosswordCell::DIRECTION_NE, 0) } + pub fn ne2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_NE, start) + } + + const DIRECTION_E: (isize, isize) = (0, 1); pub fn e(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (0, 1)) + self.take(num_of_letters, CrosswordCell::DIRECTION_E, 0) } + pub fn e2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_E, start) + } + + const DIRECTION_SE: (isize, isize) = (1, 1); pub fn se(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (1, 1)) + self.take(num_of_letters, CrosswordCell::DIRECTION_SE, 0) } + pub fn se2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_SE, start) + } + + const DIRECTION_S: (isize, isize) = (1, 0); pub fn s(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (1, 0)) + self.take(num_of_letters, CrosswordCell::DIRECTION_S, 0) } + pub fn s2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_S, start) + } + + const DIRECTION_SW: (isize, isize) = (1, -1); pub fn sw(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (1, -1)) + self.take(num_of_letters, CrosswordCell::DIRECTION_SW, 0) } + pub fn sw2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_SW, start) + } + + const DIRECTION_W: (isize, isize) = (0, -1); pub fn w(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (0, -1)) + self.take(num_of_letters, CrosswordCell::DIRECTION_W, 0) } + pub fn w2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_W, start) + } + + const DIRECTION_NW: (isize, isize) = (-1, -1); pub fn nw(&self, num_of_letters: usize) -> String { - self.take(num_of_letters, (-1, -1)) + self.take(num_of_letters, CrosswordCell::DIRECTION_NW, 0) + } + + pub fn nw2(&self, num_of_letters: usize, start: isize) -> String { + self.take(num_of_letters, CrosswordCell::DIRECTION_NW, start) } } @@ -198,6 +244,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).n(1), "5"); assert_eq!(crossword.cell(1, 1).n(2), "52"); assert_eq!(crossword.cell(1, 1).n(3), "52"); + assert_eq!(crossword.cell(1, 1).n2(3, 1), "2"); + assert_eq!(crossword.cell(1, 1).n2(3, 0), "52"); + assert_eq!(crossword.cell(1, 1).n2(3, -1), "852"); + assert_eq!(crossword.cell(1, 1).n2(3, -2), "85"); } #[test] @@ -207,6 +257,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).ne(1), "5"); assert_eq!(crossword.cell(1, 1).ne(2), "53"); assert_eq!(crossword.cell(1, 1).ne(3), "53"); + assert_eq!(crossword.cell(1, 1).ne2(3, 1), "3"); + assert_eq!(crossword.cell(1, 1).ne2(3, 0), "53"); + assert_eq!(crossword.cell(1, 1).ne2(3, -1), "753"); + assert_eq!(crossword.cell(1, 1).ne2(3, -2), "75"); } #[test] @@ -216,6 +270,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).e(1), "5"); assert_eq!(crossword.cell(1, 1).e(2), "56"); assert_eq!(crossword.cell(1, 1).e(3), "56"); + assert_eq!(crossword.cell(1, 1).e2(3, 1), "6"); + assert_eq!(crossword.cell(1, 1).e2(3, 0), "56"); + assert_eq!(crossword.cell(1, 1).e2(3, -1), "456"); + assert_eq!(crossword.cell(1, 1).e2(3, -2), "45"); } #[test] @@ -225,6 +283,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).se(1), "5"); assert_eq!(crossword.cell(1, 1).se(2), "59"); assert_eq!(crossword.cell(1, 1).se(3), "59"); + assert_eq!(crossword.cell(1, 1).se2(3, 1), "9"); + assert_eq!(crossword.cell(1, 1).se2(3, 0), "59"); + assert_eq!(crossword.cell(1, 1).se2(3, -1), "159"); + assert_eq!(crossword.cell(1, 1).se2(3, -2), "15"); } #[test] @@ -234,6 +296,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).s(1), "5"); assert_eq!(crossword.cell(1, 1).s(2), "58"); assert_eq!(crossword.cell(1, 1).s(3), "58"); + assert_eq!(crossword.cell(1, 1).s2(3, 1), "8"); + assert_eq!(crossword.cell(1, 1).s2(3, 0), "58"); + assert_eq!(crossword.cell(1, 1).s2(3, -1), "258"); + assert_eq!(crossword.cell(1, 1).s2(3, -2), "25"); } #[test] @@ -243,6 +309,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).sw(1), "5"); assert_eq!(crossword.cell(1, 1).sw(2), "57"); assert_eq!(crossword.cell(1, 1).sw(3), "57"); + assert_eq!(crossword.cell(1, 1).sw2(3, 1), "7"); + assert_eq!(crossword.cell(1, 1).sw2(3, 0), "57"); + assert_eq!(crossword.cell(1, 1).sw2(3, -1), "357"); + assert_eq!(crossword.cell(1, 1).sw2(3, -2), "35"); } #[test] @@ -252,6 +322,10 @@ mod tests { assert_eq!(crossword.cell(1, 1).w(1), "5"); assert_eq!(crossword.cell(1, 1).w(2), "54"); assert_eq!(crossword.cell(1, 1).w(3), "54"); + assert_eq!(crossword.cell(1, 1).w2(3, 1), "4"); + assert_eq!(crossword.cell(1, 1).w2(3, 0), "54"); + assert_eq!(crossword.cell(1, 1).w2(3, -1), "654"); + assert_eq!(crossword.cell(1, 1).w2(3, -2), "65"); } #[test] @@ -261,5 +335,9 @@ mod tests { assert_eq!(crossword.cell(1, 1).nw(1), "5"); assert_eq!(crossword.cell(1, 1).nw(2), "51"); assert_eq!(crossword.cell(1, 1).nw(3), "51"); + assert_eq!(crossword.cell(1, 1).nw2(3, 1), "1"); + assert_eq!(crossword.cell(1, 1).nw2(3, 0), "51"); + assert_eq!(crossword.cell(1, 1).nw2(3, -1), "951"); + assert_eq!(crossword.cell(1, 1).nw2(3, -2), "95"); } } diff --git a/day_04/src/main.rs b/day_04/src/main.rs index ae7e4bd..7345c8e 100644 --- a/day_04/src/main.rs +++ b/day_04/src/main.rs @@ -2,6 +2,8 @@ // // Run command: cargo run ./input.txt +#![allow(dead_code)] + use std::env; use std::error::Error; use std::fs::File; @@ -64,9 +66,23 @@ fn main() -> Result<(), Box> { } println!( - "Count of the work '{}' in crossword: {}", + "Count of the word '{}' in crossword: {}", word_to_find, count ); + let mas = "MAS".to_owned(); + let mas_rev = mas.chars().rev().collect::(); + let mut count = 0; + for cell in crossword.iter_cells() { + let se_word = cell.se2(3, -1); + let sw_word = cell.sw2(3, -1); + + if (se_word == mas || se_word == mas_rev) && (sw_word == mas || sw_word == mas_rev) { + count += 1; + } + } + + println!("Count of the MAS Xes in crossword: {}", count); + Ok(()) }