Finish day 4

This commit is contained in:
2025-05-29 22:02:50 -05:00
parent bd64b51683
commit 6730dd1a80
3 changed files with 193 additions and 14 deletions

85
day_04/README.md Normal file
View File

@@ -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: **

View File

@@ -28,55 +28,101 @@ impl<'a> CrosswordCell<'a> {
self.value_by_index(self.x, self.y) 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(); let mut word = String::new();
for i in 0..num_of_letters { let end = start + num_of_letters as isize;
let x = self.x as isize + (i as isize * direction.1);
let y = self.y as isize + (i as isize * direction.0); 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 if x < 0
|| x >= self.crossword.width as isize || x >= self.crossword.width as isize
|| y < 0 || y < 0
|| y >= self.crossword.height as isize || y >= self.crossword.height as isize
{ {
if i < 0 {
continue;
} else {
break; break;
} }
}
word.push(self.value_by_index(x as usize, y as usize)); word.push(self.value_by_index(x as usize, y as usize));
} }
word word
} }
const DIRECTION_N: (isize, isize) = (-1, 0);
pub fn n(&self, num_of_letters: usize) -> String { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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(1), "5");
assert_eq!(crossword.cell(1, 1).n(2), "52"); assert_eq!(crossword.cell(1, 1).n(2), "52");
assert_eq!(crossword.cell(1, 1).n(3), "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] #[test]
@@ -207,6 +257,10 @@ mod tests {
assert_eq!(crossword.cell(1, 1).ne(1), "5"); 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(2), "53");
assert_eq!(crossword.cell(1, 1).ne(3), "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] #[test]
@@ -216,6 +270,10 @@ mod tests {
assert_eq!(crossword.cell(1, 1).e(1), "5"); 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(2), "56");
assert_eq!(crossword.cell(1, 1).e(3), "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] #[test]
@@ -225,6 +283,10 @@ mod tests {
assert_eq!(crossword.cell(1, 1).se(1), "5"); 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(2), "59");
assert_eq!(crossword.cell(1, 1).se(3), "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] #[test]
@@ -234,6 +296,10 @@ mod tests {
assert_eq!(crossword.cell(1, 1).s(1), "5"); 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(2), "58");
assert_eq!(crossword.cell(1, 1).s(3), "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] #[test]
@@ -243,6 +309,10 @@ mod tests {
assert_eq!(crossword.cell(1, 1).sw(1), "5"); 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(2), "57");
assert_eq!(crossword.cell(1, 1).sw(3), "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] #[test]
@@ -252,6 +322,10 @@ mod tests {
assert_eq!(crossword.cell(1, 1).w(1), "5"); 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(2), "54");
assert_eq!(crossword.cell(1, 1).w(3), "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] #[test]
@@ -261,5 +335,9 @@ mod tests {
assert_eq!(crossword.cell(1, 1).nw(1), "5"); 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(2), "51");
assert_eq!(crossword.cell(1, 1).nw(3), "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");
} }
} }

View File

@@ -2,6 +2,8 @@
// //
// Run command: cargo run ./input.txt // Run command: cargo run ./input.txt
#![allow(dead_code)]
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
@@ -64,9 +66,23 @@ fn main() -> Result<(), Box<dyn Error>> {
} }
println!( println!(
"Count of the work '{}' in crossword: {}", "Count of the word '{}' in crossword: {}",
word_to_find, count word_to_find, count
); );
let mas = "MAS".to_owned();
let mas_rev = mas.chars().rev().collect::<String>();
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(()) Ok(())
} }