summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-12-25 00:29:43 -0500
committerJesse Luehrs <doy@tozt.net>2021-12-25 00:29:43 -0500
commit3dfa5bd6227ce8654f75371bd7de06b0cbe92f87 (patch)
treea81539784e9c1d8e93e9b93ff3fcd32aa9d80ae1 /src
parentefd2635dd73b7806d75d23e21f37bd82288820c1 (diff)
downloadadvent-of-code-3dfa5bd6227ce8654f75371bd7de06b0cbe92f87.tar.gz
advent-of-code-3dfa5bd6227ce8654f75371bd7de06b0cbe92f87.zip
day 25
Diffstat (limited to 'src')
-rw-r--r--src/2021/25/mod.rs99
-rw-r--r--src/2021/mod.rs4
-rw-r--r--src/grid.rs47
-rw-r--r--src/parse.rs18
4 files changed, 151 insertions, 17 deletions
diff --git a/src/2021/25/mod.rs b/src/2021/25/mod.rs
new file mode 100644
index 0000000..67d589e
--- /dev/null
+++ b/src/2021/25/mod.rs
@@ -0,0 +1,99 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+use crate::prelude::*;
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum Cell {
+ Down,
+ Right,
+ None,
+}
+
+impl Default for Cell {
+ fn default() -> Self {
+ Self::None
+ }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Map {
+ grid: Grid<Cell>,
+}
+
+impl Map {
+ fn step(&self) -> Self {
+ self.step_east().step_south()
+ }
+
+ fn step_east(&self) -> Self {
+ let mut step = self.clone();
+ for ((Row(row), Col(col)), cell) in self.grid.indexed_cells() {
+ if *cell == Cell::Right {
+ let mut next = col + 1;
+ if next >= self.grid.cols().0 {
+ next = 0;
+ }
+ if self.grid[Row(row)][Col(next)] == Cell::None {
+ step.grid[Row(row)][Col(next)] = Cell::Right;
+ step.grid[Row(row)][Col(col)] = Cell::None;
+ }
+ }
+ }
+ step
+ }
+
+ fn step_south(&self) -> Self {
+ let mut step = self.clone();
+ for ((Row(row), Col(col)), cell) in self.grid.indexed_cells() {
+ if *cell == Cell::Down {
+ let mut next = row + 1;
+ if next >= self.grid.rows().0 {
+ next = 0;
+ }
+ if self.grid[Row(next)][Col(col)] == Cell::None {
+ step.grid[Row(next)][Col(col)] = Cell::Down;
+ step.grid[Row(row)][Col(col)] = Cell::None;
+ }
+ }
+ }
+ step
+ }
+}
+
+pub fn parse(fh: File) -> Result<Map> {
+ Ok(Map {
+ grid: parse::grid(parse::lines(fh), |b| match b {
+ b'v' => Cell::Down,
+ b'>' => Cell::Right,
+ b'.' => Cell::None,
+ _ => panic!("unknown cell {}", b),
+ }),
+ })
+}
+
+pub fn part1(map: Map) -> Result<i64> {
+ let mut prev = map;
+ let mut i = 0;
+ loop {
+ i += 1;
+ let next = prev.step();
+ if next == prev {
+ break;
+ }
+ prev = next;
+ }
+ Ok(i)
+}
+
+pub fn part2(_: Map) -> Result<i64> {
+ todo!()
+}
+
+#[test]
+fn test() {
+ assert_eq!(
+ part1(parse(parse::data(2021, 25).unwrap()).unwrap()).unwrap(),
+ 482
+ );
+}
diff --git a/src/2021/mod.rs b/src/2021/mod.rs
index e5cdeb2..e7a838b 100644
--- a/src/2021/mod.rs
+++ b/src/2021/mod.rs
@@ -48,6 +48,8 @@ mod day22;
mod day23;
#[path = "24/mod.rs"]
mod day24;
+#[path = "25/mod.rs"]
+mod day25;
// NEXT MOD
pub fn run(day: u8, puzzle: u8) -> Result<i64> {
@@ -100,6 +102,8 @@ pub fn run(day: u8, puzzle: u8) -> Result<i64> {
(23, 2) => day23::part2(day23::parse(parse::data(2021, 23)?)?),
(24, 1) => day24::part1(day24::parse(parse::data(2021, 24)?)?),
(24, 2) => day24::part2(day24::parse(parse::data(2021, 24)?)?),
+ (25, 1) => day25::part1(day25::parse(parse::data(2021, 25)?)?),
+ (25, 2) => day25::part2(day25::parse(parse::data(2021, 25)?)?),
// NEXT PART
_ => Err(anyhow!("unknown puzzle {}-{}", day, puzzle)),
}
diff --git a/src/grid.rs b/src/grid.rs
index 46f6263..b84e1b7 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -59,12 +59,12 @@ impl std::ops::Sub<Col> for usize {
}
}
-#[derive(Default, Clone, Debug)]
-pub struct GridRow<T: Default + Clone> {
+#[derive(Default, Clone, Debug, Eq, PartialEq)]
+pub struct GridRow<T: Default + Clone + Eq + PartialEq> {
cells: Vec<T>,
}
-impl<T: Default + Clone> GridRow<T> {
+impl<T: Default + Clone + Eq + PartialEq> GridRow<T> {
pub fn iter(&self) -> impl Iterator<Item = &T> + Clone {
self.cells.iter()
}
@@ -74,25 +74,29 @@ impl<T: Default + Clone> GridRow<T> {
}
}
-impl<T: Default + Clone> std::ops::Index<Col> for GridRow<T> {
+impl<T: Default + Clone + Eq + PartialEq> std::ops::Index<Col>
+ for GridRow<T>
+{
type Output = T;
fn index(&self, col: Col) -> &Self::Output {
&self.cells[col.0]
}
}
-impl<T: Default + Clone> std::ops::IndexMut<Col> for GridRow<T> {
+impl<T: Default + Clone + Eq + PartialEq> std::ops::IndexMut<Col>
+ for GridRow<T>
+{
fn index_mut(&mut self, col: Col) -> &mut Self::Output {
&mut self.cells[col.0]
}
}
-#[derive(Default, Clone, Debug)]
-pub struct Grid<T: Default + Clone> {
+#[derive(Default, Clone, Debug, Eq, PartialEq)]
+pub struct Grid<T: Default + Clone + Eq + PartialEq> {
rows: Vec<GridRow<T>>,
}
-impl<T: Default + Clone> Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq> Grid<T> {
pub fn grow(&mut self, rows: Row, cols: Col) {
self.rows
.resize_with(rows.0.max(self.rows.len()), GridRow::default);
@@ -154,7 +158,7 @@ impl<T: Default + Clone> Grid<T> {
}
}
-impl<T: Default + Clone + std::fmt::Display> Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq + std::fmt::Display> Grid<T> {
pub fn display_packed<F: Fn(&T) -> char>(
&self,
f: F,
@@ -163,7 +167,9 @@ impl<T: Default + Clone + std::fmt::Display> Grid<T> {
}
}
-impl<T: Default + Clone + std::fmt::Display> std::fmt::Display for Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq + std::fmt::Display>
+ std::fmt::Display for Grid<T>
+{
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
@@ -178,20 +184,22 @@ impl<T: Default + Clone + std::fmt::Display> std::fmt::Display for Grid<T> {
}
}
-impl<T: Default + Clone> std::ops::Index<Row> for Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq> std::ops::Index<Row> for Grid<T> {
type Output = GridRow<T>;
fn index(&self, row: Row) -> &Self::Output {
&self.rows[row.0]
}
}
-impl<T: Default + Clone> std::ops::IndexMut<Row> for Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq> std::ops::IndexMut<Row>
+ for Grid<T>
+{
fn index_mut(&mut self, row: Row) -> &mut Self::Output {
&mut self.rows[row.0]
}
}
-impl<T: Default + Clone> FromIterator<Vec<T>> for Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq> FromIterator<Vec<T>> for Grid<T> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = Vec<T>>,
@@ -202,7 +210,9 @@ impl<T: Default + Clone> FromIterator<Vec<T>> for Grid<T> {
}
}
-impl<T: Default + Clone> FromIterator<((Row, Col), T)> for Grid<T> {
+impl<T: Default + Clone + Eq + PartialEq> FromIterator<((Row, Col), T)>
+ for Grid<T>
+{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = ((Row, Col), T)>,
@@ -218,12 +228,15 @@ impl<T: Default + Clone> FromIterator<((Row, Col), T)> for Grid<T> {
pub struct DisplayPacked<
'a,
- T: Default + Clone + std::fmt::Display,
+ T: Default + Clone + Eq + PartialEq + std::fmt::Display,
F: Fn(&'a T) -> char,
>(&'a Grid<T>, F);
-impl<'a, T: Default + Clone + std::fmt::Display, F: Fn(&'a T) -> char>
- std::fmt::Display for DisplayPacked<'a, T, F>
+impl<
+ 'a,
+ T: Default + Clone + Eq + PartialEq + std::fmt::Display,
+ F: Fn(&'a T) -> char,
+ > std::fmt::Display for DisplayPacked<'a, T, F>
{
fn fmt(
&self,
diff --git a/src/parse.rs b/src/parse.rs
index 903ad2f..3674a25 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -63,3 +63,21 @@ pub fn digit_grid(lines: impl Iterator<Item = String>) -> Grid<u8> {
})
.collect()
}
+
+// false positive, doing its suggestion gives borrow checker errors
+#[allow(clippy::redundant_closure)]
+pub fn grid<F, T>(lines: impl Iterator<Item = String>, f: F) -> Grid<T>
+where
+ F: Fn(u8) -> T,
+ T: Clone + Default + Eq + PartialEq,
+{
+ lines
+ .map(|s| {
+ s.as_bytes()
+ .iter()
+ .copied()
+ .map(|b| f(b))
+ .collect::<Vec<_>>()
+ })
+ .collect()
+}