mirror of
https://github.com/mx42/aoc2024.rs.git
synced 2026-01-14 13:59:52 +01:00
feat: add day 4
This commit is contained in:
@@ -22,8 +22,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
|
|||||||
| [Day 1](./src/bin/01.rs) | `72.0µs` | `76.8µs` |
|
| [Day 1](./src/bin/01.rs) | `72.0µs` | `76.8µs` |
|
||||||
| [Day 2](./src/bin/02.rs) | `215.6µs` | `371.6µs` |
|
| [Day 2](./src/bin/02.rs) | `215.6µs` | `371.6µs` |
|
||||||
| [Day 3](./src/bin/03.rs) | `652.5µs` | `736.7µs` |
|
| [Day 3](./src/bin/03.rs) | `652.5µs` | `736.7µs` |
|
||||||
|
| [Day 4](./src/bin/04.rs) | `5.6ms` | `2.4ms` |
|
||||||
|
|
||||||
**Total: 2.13ms**
|
**Total: 10.13ms**
|
||||||
<!--- benchmarking table --->
|
<!--- benchmarking table --->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
10
data/examples/04.txt
Normal file
10
data/examples/04.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
MMMSXXMASM
|
||||||
|
MSAMXMSMSA
|
||||||
|
AMXSXMAAMM
|
||||||
|
MSAMASMSMX
|
||||||
|
XMASAMXAMM
|
||||||
|
XXAMMXXAMA
|
||||||
|
SMSMSASXSS
|
||||||
|
SAXAMASAAA
|
||||||
|
MAMMMXMMMM
|
||||||
|
MXMXAXMASX
|
||||||
181
src/bin/04.rs
Normal file
181
src/bin/04.rs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
advent_of_code::solution!(4);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Pos {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pos {
|
||||||
|
fn init(x: usize, y: usize) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
fn get_pos_from_origin(&self) -> Vec<Pos> {
|
||||||
|
(0..self.y)
|
||||||
|
.flat_map(|y| (0..self.x).map(|x| Pos::init(x, y)).collect::<Vec<Pos>>())
|
||||||
|
.collect::<Vec<Pos>>()
|
||||||
|
}
|
||||||
|
fn diag_pos(&self, max: &Pos) -> Option<Vec<Pos>> {
|
||||||
|
if self.y == 0 || self.y >= max.y - 1 || self.x == 0 || self.x >= max.x - 1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(vec![
|
||||||
|
// Northwest
|
||||||
|
Pos::init(self.x - 1, self.y - 1),
|
||||||
|
// Northeast
|
||||||
|
Pos::init(self.x + 1, self.y - 1),
|
||||||
|
// Southwest
|
||||||
|
Pos::init(self.x - 1, self.y + 1),
|
||||||
|
// Southeast
|
||||||
|
Pos::init(self.x + 1, self.y + 1),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xmas_pos(&self, max: &Pos) -> Vec<Vec<Pos>> {
|
||||||
|
let mut res: Vec<Vec<Pos>> = Vec::new();
|
||||||
|
if self.y >= 3 {
|
||||||
|
if self.x >= 3 {
|
||||||
|
// Northwest
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|z| Pos::init(self.x - z as usize, self.y - z as usize))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// North
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|y| Pos::init(self.x, self.y - y as usize))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
if self.x < max.x - 3 {
|
||||||
|
// Northeast
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|z| Pos::init(self.x + z as usize, self.y - z as usize))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.x >= 3 {
|
||||||
|
// West
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|x| Pos::init(self.x - x as usize, self.y))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if self.x < max.x - 3 {
|
||||||
|
// East
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|x| Pos::init(self.x + x as usize, self.y))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if self.y < max.y - 3 {
|
||||||
|
if self.x >= 3 {
|
||||||
|
// Southwest
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|z| Pos::init(self.x - z as usize, self.y + z as usize))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// South
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|y| Pos::init(self.x, self.y + y as usize))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
if self.x < max.x - 3 {
|
||||||
|
// Southeast
|
||||||
|
res.push(
|
||||||
|
(1..4)
|
||||||
|
.map(|z| Pos::init(self.x + z as usize, self.y + z as usize))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// println!("Surrounding pos for {:?}", self);
|
||||||
|
// println!("{:#?}", res);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
fn get_char_in_input(&self, input: &[&str]) -> char {
|
||||||
|
input[self.y].chars().nth(self.x).unwrap_or('0')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mas_at_pos(input: &[&str], ps: &[Pos]) -> bool {
|
||||||
|
for (p, l) in ps.iter().zip("MAS".chars()) {
|
||||||
|
let c = p.get_char_in_input(input);
|
||||||
|
if c != l {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cross_mas_at_pos(input: &[&str], ps: &[Pos]) -> bool {
|
||||||
|
let letters = ps
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.get_char_in_input(input))
|
||||||
|
.collect::<Vec<char>>();
|
||||||
|
letters.iter().all(|&c| c == 'M' || c == 'S')
|
||||||
|
&& letters[0] != letters[3]
|
||||||
|
&& letters[1] != letters[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_one(input: &str) -> Option<usize> {
|
||||||
|
let input = input
|
||||||
|
.strip_suffix("\n")
|
||||||
|
.unwrap_or(input)
|
||||||
|
.lines()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let input = input.as_slice();
|
||||||
|
let max = Pos::init(input[0].len(), input.len());
|
||||||
|
max.get_pos_from_origin()
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.get_char_in_input(input) == 'X')
|
||||||
|
.flat_map(|p| p.xmas_pos(&max))
|
||||||
|
.filter(|ps| mas_at_pos(input, ps))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.len()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_two(input: &str) -> Option<usize> {
|
||||||
|
let input = input
|
||||||
|
.strip_suffix("\n")
|
||||||
|
.unwrap_or(input)
|
||||||
|
.lines()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let input = input.as_slice();
|
||||||
|
let max = Pos::init(input[0].len(), input.len());
|
||||||
|
max.get_pos_from_origin()
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.get_char_in_input(input) == 'A')
|
||||||
|
.flat_map(|p| p.diag_pos(&max))
|
||||||
|
.filter(|ps| cross_mas_at_pos(input, ps))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.len()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_one() {
|
||||||
|
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||||
|
assert_eq!(result, Some(18));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_two() {
|
||||||
|
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||||
|
assert_eq!(result, Some(9));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user