Skip to content

Commit

Permalink
AoC 2024 Day 4 - rust
Browse files Browse the repository at this point in the history
  • Loading branch information
pareronia committed Dec 4, 2024
1 parent 34d721e commit 26cbc2f
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
| ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| python3 | [](src/main/python/AoC2024_01.py) | [](src/main/python/AoC2024_02.py) | [](src/main/python/AoC2024_03.py) | [](src/main/python/AoC2024_04.py) | | | | | | | | | | | | | | | | | | | | | |
| java | [](src/main/java/AoC2024_01.java) | [](src/main/java/AoC2024_02.java) | [](src/main/java/AoC2024_03.java) | [](src/main/java/AoC2024_04.java) | | | | | | | | | | | | | | | | | | | | | |
| rust | [](src/main/rust/AoC2024_01/src/main.rs) | [](src/main/rust/AoC2024_02/src/main.rs) | [](src/main/rust/AoC2024_03/src/main.rs) | | | | | | | | | | | | | | | | | | | | | | |
| rust | [](src/main/rust/AoC2024_01/src/main.rs) | [](src/main/rust/AoC2024_02/src/main.rs) | [](src/main/rust/AoC2024_03/src/main.rs) | [](src/main/rust/AoC2024_04/src/main.rs) | | | | | | | | | | | | | | | | | | | | | |
<!-- @END:ImplementationsTable:2024@ -->

## 2023
Expand Down
7 changes: 7 additions & 0 deletions src/main/rust/AoC2024_04/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "AoC2024_04"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../aoc" }
100 changes: 100 additions & 0 deletions src/main/rust/AoC2024_04/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#![allow(non_snake_case)]

use aoc::geometry::Direction;
use aoc::grid::{CharGrid, Grid};
use aoc::Puzzle;
use std::collections::HashSet;

struct AoC2024_04;

impl AoC2024_04 {}

impl aoc::Puzzle for AoC2024_04 {
type Input = CharGrid;
type Output1 = usize;
type Output2 = usize;

aoc::puzzle_year_day!(2024, 4);

fn parse_input(&self, lines: Vec<String>) -> Self::Input {
CharGrid::from(&lines.iter().map(AsRef::as_ref).collect::<Vec<_>>())
}

fn part_1(&self, grid: &Self::Input) -> Self::Output1 {
grid.cells()
.filter(|cell| grid.get(cell) == 'X')
.map(|cell| {
Direction::octants()
.iter()
.filter(|dir| {
let mut it = grid.cells_direction(&cell, **dir);
['M', 'A', 'S'].iter().all(|ch| match it.next() {
Some(n) => grid.get(&n) == *ch,
None => false,
})
})
.count()
})
.sum()
}

fn part_2(&self, grid: &Self::Input) -> Self::Output2 {
let directions = [
Direction::LeftAndUp,
Direction::RightAndDown,
Direction::RightAndUp,
Direction::LeftAndDown,
];
let matches = HashSet::from(["MSMS", "SMSM", "MSSM", "SMMS"]);
grid.cells()
.filter(|cell| {
0 < cell.row
&& cell.row < grid.height() - 1
&& 0 < cell.col
&& cell.col < grid.width() - 1
})
.filter(|cell| grid.get(cell) == 'A')
.filter(|cell| {
let s = directions
.iter()
.map(|d| grid.get(&cell.try_at(*d).unwrap()))
.collect::<String>();
matches.contains(&s as &str)
})
.count()
}

fn samples(&self) {
aoc::puzzle_samples! {
self, part_1, TEST, 18,
self, part_2, TEST, 9
};
}
}

fn main() {
AoC2024_04 {}.run(std::env::args());
}

const TEST: &str = "\
MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
";

#[cfg(test)]
mod tests {
use super::*;

#[test]
pub fn samples() {
AoC2024_04 {}.samples();
}
}
7 changes: 7 additions & 0 deletions src/main/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions src/main/rust/aoc/src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ impl XY {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Direction {
Up,
RightAndUp,
Right,
RightAndDown,
Down,
LeftAndDown,
Left,
LeftAndUp,
}

impl Direction {
Expand All @@ -47,6 +51,21 @@ impl Direction {
.collect()
}

pub fn octants() -> HashSet<Direction> {
vec![
Direction::Up,
Direction::RightAndUp,
Direction::Right,
Direction::RightAndDown,
Direction::Down,
Direction::LeftAndDown,
Direction::Left,
Direction::LeftAndUp,
]
.into_iter()
.collect()
}

pub fn is_horizontal(&self) -> bool {
*self == Direction::Right || *self == Direction::Left
}
Expand All @@ -73,6 +92,7 @@ impl Direction {
Turn::Left => Direction::Down,
Turn::Right => Direction::Up,
},
_ => panic!("Invalid Direction for turn: {}", self),
}
}
}
Expand Down Expand Up @@ -109,9 +129,13 @@ impl TryFrom<Direction> for XY {
fn try_from(value: Direction) -> Result<Self, Self::Error> {
match value {
Direction::Up => Ok(XY::of(0, 1)),
Direction::RightAndUp => Ok(XY::of(1, 1)),
Direction::Right => Ok(XY::of(1, 0)),
Direction::RightAndDown => Ok(XY::of(1, -1)),
Direction::Down => Ok(XY::of(0, -1)),
Direction::LeftAndDown => Ok(XY::of(-1, -1)),
Direction::Left => Ok(XY::of(-1, 0)),
Direction::LeftAndUp => Ok(XY::of(-1, 1)),
}
}
}
Expand Down
95 changes: 95 additions & 0 deletions src/main/rust/aoc/src/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,13 @@ pub struct CellRange {
pub enum Direction {
Forward,
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest,
}

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -125,27 +129,57 @@ impl Iterator for GridIterator {
};
self.next
}
Direction::NorthEast => {
self.next = match val.row > 0 && val.col < self.width - 1 {
true => Some(Cell::at(val.row - 1, val.col + 1)),
false => None,
};
self.next
}
Direction::East => {
self.next = match val.col < self.width - 1 {
true => Some(Cell::at(val.row, val.col + 1)),
false => None,
};
self.next
}
Direction::SouthEast => {
self.next = match val.row < self.height - 1
&& val.col < self.width - 1
{
true => Some(Cell::at(val.row + 1, val.col + 1)),
false => None,
};
self.next
}
Direction::South => {
self.next = match val.row < self.height - 1 {
true => Some(Cell::at(val.row + 1, val.col)),
false => None,
};
self.next
}
Direction::SouthWest => {
self.next = match val.row < self.height - 1 && val.col > 0 {
true => Some(Cell::at(val.row + 1, val.col - 1)),
false => None,
};
self.next
}
Direction::West => {
self.next = match val.col > 0 {
true => Some(Cell::at(val.row, val.col - 1)),
false => None,
};
self.next
}
Direction::NorthWest => {
self.next = match val.row > 0 && val.col > 0 {
true => Some(Cell::at(val.row - 1, val.col - 1)),
false => None,
};
self.next
}
},
}
}
Expand Down Expand Up @@ -249,6 +283,31 @@ pub trait Grid {
}
}

fn cells_direction(
&self,
cell: &Cell,
direction: crate::geometry::Direction,
) -> GridIterator {
match direction {
crate::geometry::Direction::Up => self.cells_north(cell),
crate::geometry::Direction::RightAndUp => {
self.cells_north_east(cell)
}
crate::geometry::Direction::Right => self.cells_east(cell),
crate::geometry::Direction::RightAndDown => {
self.cells_south_east(cell)
}
crate::geometry::Direction::Down => self.cells_south(cell),
crate::geometry::Direction::LeftAndDown => {
self.cells_south_west(cell)
}
crate::geometry::Direction::Left => self.cells_west(cell),
crate::geometry::Direction::LeftAndUp => {
self.cells_north_west(cell)
}
}
}

fn cells_north(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
Expand All @@ -258,6 +317,15 @@ pub trait Grid {
}
}

fn cells_north_east(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
height: self.height(),
direction: Direction::NorthEast,
next: Some(Cell::at(cell.row, cell.col)),
}
}

fn cells_east(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
Expand All @@ -267,6 +335,15 @@ pub trait Grid {
}
}

fn cells_south_east(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
height: self.height(),
direction: Direction::SouthEast,
next: Some(Cell::at(cell.row, cell.col)),
}
}

fn cells_south(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
Expand All @@ -276,6 +353,15 @@ pub trait Grid {
}
}

fn cells_south_west(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
height: self.height(),
direction: Direction::SouthWest,
next: Some(Cell::at(cell.row, cell.col)),
}
}

fn cells_west(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
Expand All @@ -285,6 +371,15 @@ pub trait Grid {
}
}

fn cells_north_west(&self, cell: &Cell) -> GridIterator {
GridIterator {
width: self.width(),
height: self.height(),
direction: Direction::NorthWest,
next: Some(Cell::at(cell.row, cell.col)),
}
}

// TODO return iterator
fn cells_capital_directions(&self, cell: &Cell) -> Vec<GridIterator> {
vec![
Expand Down
1 change: 1 addition & 0 deletions src/main/rust/aoc/src/navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl From<Direction> for Heading {
Direction::Right => Heading::East,
Direction::Down => Heading::South,
Direction::Left => Heading::West,
_ => panic!("Direction not supported: {}", direction),
}
}
}
Expand Down

0 comments on commit 26cbc2f

Please sign in to comment.