day4
This commit is contained in:
@@ -4,3 +4,4 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
regex = "1.11.1"
|
||||
|
||||
80
day4/Readme.md
Normal file
80
day4/Readme.md
Normal file
@@ -0,0 +1,80 @@
|
||||
--- 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 2462.
|
||||
|
||||
The first half of this puzzle is complete! It provides one gold star: *
|
||||
|
||||
--- 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?
|
||||
@@ -7,4 +7,4 @@ XXAMMXXAMA
|
||||
SMSMSASXSS
|
||||
SAXAMASAAA
|
||||
MAMMMXMMMM
|
||||
MXMXAXMASX
|
||||
MXMXAXMASX
|
||||
131
day4/src/main.rs
131
day4/src/main.rs
@@ -1,3 +1,130 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use regex::Regex;
|
||||
|
||||
struct Direction(char, usize, i32, bool);
|
||||
|
||||
impl Direction {
|
||||
fn new(start: char, position: usize, length: usize) -> Vec<Self> {
|
||||
let (next, is_forward) = match start {
|
||||
'X' => ('M', true),
|
||||
'S' => ('A', false),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let mut directions = vec![Direction(next, position, 0, is_forward)];
|
||||
if position >= 3 {
|
||||
directions.push(Direction(next, position - 1, -1, is_forward));
|
||||
}
|
||||
if position + 3 < length {
|
||||
directions.push(Direction(next, position + 1, 1, is_forward));
|
||||
}
|
||||
directions
|
||||
}
|
||||
}
|
||||
|
||||
fn next_char(c: char, is_forward: bool) -> char {
|
||||
match (c, is_forward) {
|
||||
('X', true) => 'M',
|
||||
('M', true) => 'A',
|
||||
('A', true) => 'S',
|
||||
('S', true) => 'E',
|
||||
('S', false) => 'A',
|
||||
('A', false) => 'M',
|
||||
('M', false) => 'X',
|
||||
('X', false) => 'E',
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn prob1() {
|
||||
let input = std::fs::read_to_string("input.txt").unwrap();
|
||||
let lines = input.lines();
|
||||
|
||||
let mut count = 0;
|
||||
let re_xmas = Regex::new(r"XMAS").unwrap();
|
||||
let re_samx = Regex::new(r"SAMX").unwrap();
|
||||
let re_single = Regex::new(r"[XS]").unwrap();
|
||||
let mut candidates = vec![];
|
||||
for line in lines {
|
||||
let line = line.trim();
|
||||
let line_length = line.len();
|
||||
|
||||
let mut new_candidates = vec![];
|
||||
for direction in candidates.iter() {
|
||||
let Direction(char_should_be, position, step, is_forward) = direction;
|
||||
if line.chars().nth(*position).unwrap() == *char_should_be {
|
||||
let next = next_char(*char_should_be, *is_forward);
|
||||
if next == 'E' {
|
||||
count += 1;
|
||||
} else {
|
||||
new_candidates.push(Direction(
|
||||
next,
|
||||
(*position as i32 + step) as usize,
|
||||
*step,
|
||||
*is_forward,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count += re_xmas.find_iter(line).count();
|
||||
count += re_samx.find_iter(line).count();
|
||||
|
||||
for m in re_single.find_iter(line) {
|
||||
let position = m.start();
|
||||
new_candidates.append(&mut Direction::new(
|
||||
m.as_str().chars().next().unwrap(),
|
||||
position,
|
||||
line_length,
|
||||
));
|
||||
}
|
||||
candidates = new_candidates;
|
||||
}
|
||||
println!("{count}");
|
||||
}
|
||||
|
||||
fn opposite_char(c: Option<&char>) -> Result<char, ()> {
|
||||
match c {
|
||||
Some('S') => Ok('M'),
|
||||
Some('M') => Ok('S'),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn prob2() {
|
||||
let input = std::fs::read_to_string("input.txt").unwrap();
|
||||
let mut lines = input.lines();
|
||||
|
||||
let mut count = 0;
|
||||
let re_a = Regex::new(r"A").unwrap();
|
||||
let mut prev_line = lines.next().unwrap().trim().chars().collect::<Vec<char>>();
|
||||
let mut candidates = vec![];
|
||||
for line in lines {
|
||||
let line = line.trim();
|
||||
let last_index = line.len() - 1;
|
||||
let chars = line.chars().collect::<Vec<char>>();
|
||||
for ((c1, pos1), (c2, pos2)) in candidates {
|
||||
if chars[pos1] == c1 && chars[pos2] == c2 {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
candidates = vec![];
|
||||
for m in re_a.find_iter(line) {
|
||||
let position = m.start();
|
||||
if position == 0 || position == last_index {
|
||||
continue;
|
||||
} else if let Ok(c1) = opposite_char(prev_line.get(position - 1)) {
|
||||
if let Ok(c2) = opposite_char(prev_line.get(position + 1)) {
|
||||
candidates.push(((c1, position + 1), (c2, position - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_line = chars;
|
||||
}
|
||||
println!("{count}");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
prob1();
|
||||
prob2();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user