diff --git a/.aoc_tiles/tiles/2025/12.png b/.aoc_tiles/tiles/2025/12.png
new file mode 100644
index 0000000..efc17e5
Binary files /dev/null and b/.aoc_tiles/tiles/2025/12.png differ
diff --git a/README.md b/README.md
index 923f7eb..e6d0a16 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
- 2025 - 20 ⭐ - Rust
+ 2025 - 21 ⭐ - Rust
@@ -35,4 +35,7 @@
+
+
+
diff --git a/utils/grid/lib.rs b/utils/grid/lib.rs
index 6e60bc5..69205ad 100644
--- a/utils/grid/lib.rs
+++ b/utils/grid/lib.rs
@@ -22,6 +22,11 @@ pub const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
/// NESW
pub const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)];
+pub enum MirrorAxis {
+ X,
+ Y,
+}
+
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Coord2d {
pub x: i64,
@@ -281,7 +286,7 @@ impl<'a, T: Clone + Eq + PartialEq + Debug> Iterator for OffsetsIter<'a, T> {
}
}
-#[derive(Clone, Eq, PartialEq, Debug)]
+#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct Grid {
pub data: Vec,
width: i64,
@@ -486,6 +491,79 @@ impl Grid {
}
}
+ pub fn rotated(&self, mut rot: u8) -> Self {
+ rot %= 4;
+ match rot {
+ 0 => self.clone(),
+ 1 => {
+ let mut n = Grid::with_shape(self.height(), self.width(), self.data[0].clone()); // fill will be overwritten anyway
+ for y in 0..self.height() {
+ for x in 0..self.width() {
+ n.set(
+ &(self.height() - y - 1, x),
+ self.get(&(x as u64, y as u64)).unwrap().clone(),
+ );
+ }
+ }
+ n
+ }
+ 2 => {
+ let mut n = Grid::with_shape(self.height(), self.width(), self.data[0].clone()); // fill will be overwritten anyway
+ for y in 0..self.height() {
+ for x in 0..self.width() {
+ n.set(
+ &(self.width() - x - 1, self.height() - y - 1),
+ self.get(&(x as u64, y as u64)).unwrap().clone(),
+ );
+ }
+ }
+ n
+ }
+ 3 => {
+ let mut n = Grid::with_shape(self.height(), self.width(), self.data[0].clone()); // fill will be overwritten anyway
+ for y in 0..self.height() {
+ for x in 0..self.width() {
+ n.set(
+ &(self.height() - y - 1, self.width() - x - 1),
+ self.get(&(x as u64, y as u64)).unwrap().clone(),
+ );
+ }
+ }
+ n
+ }
+ _ => unreachable!("invalid rotation"),
+ }
+ }
+
+ pub fn mirrored(&self, axis: MirrorAxis) -> Self {
+ match axis {
+ MirrorAxis::X => {
+ let mut n = Grid::with_shape(self.height(), self.width(), self.data[0].clone()); // fill will be overwritten anyway
+ for y in 0..self.height() {
+ for x in 0..self.width() {
+ n.set(
+ &(self.width() - x - 1, y),
+ self.get(&(x as u64, y as u64)).unwrap().clone(),
+ );
+ }
+ }
+ n
+ }
+ MirrorAxis::Y => {
+ let mut n = Grid::with_shape(self.height(), self.width(), self.data[0].clone()); // fill will be overwritten anyway
+ for y in 0..self.height() {
+ for x in 0..self.width() {
+ n.set(
+ &(x, &self.height() - y - 1),
+ self.get(&(x as u64, y as u64)).unwrap().clone(),
+ );
+ }
+ }
+ n
+ }
+ }
+ }
+
// fn window_compare_impl(&self, needle: &[T]) -> Vec<(i64, i64)> {
// if (self.width as usize) < needle.len() {
// return Vec::new();