From dbb5a4e5711fba371fbb011356bcd8a28cc963e4 Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Tue, 8 Jul 2025 17:10:53 +0200 Subject: Day 22 2022 --- 2022/22/b.rs | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 2022/22/b.rs (limited to '2022/22/b.rs') diff --git a/2022/22/b.rs b/2022/22/b.rs new file mode 100644 index 0000000..1d292ee --- /dev/null +++ b/2022/22/b.rs @@ -0,0 +1,314 @@ +use std::mem::swap; +mod common; +use common::*; + +// Use 4 for the test input, 50 for the real one +//const CUBE_SIZE: usize = 4; +const CUBE_SIZE: usize = 50; + +// Connections between faces to make the cube 3D. +// This is hard coded to work for my specific input. +// To make it work for a different input you have to change this. +// The faces are in top-to-bottom, left-to-right order of input. +// For each face, the 4 connections are in order right, down, left, up. + +// Test case. Configuration: +// 0 U = 0, D = 4 +// 123 R = 5, L = 2 +// 45 F = 3, B = 1 +/* +const CONNECTIONS: [[Connection; 4]; 6] = [ + // Face 0 = U + [ + Connection { face: 5, side: Direction::Right }, + Connection { face: 3, side: Direction::Up }, + Connection { face: 2, side: Direction::Up }, + Connection { face: 1, side: Direction::Up }, + ], + + // Face 1 + [ + Connection { face: 2, side: Direction::Left }, + Connection { face: 4, side: Direction::Down }, + Connection { face: 5, side: Direction::Down }, + Connection { face: 0, side: Direction::Up }, + ], + + // Face 2 + [ + Connection { face: 3, side: Direction::Left }, + Connection { face: 4, side: Direction::Left }, + Connection { face: 1, side: Direction::Right }, + Connection { face: 0, side: Direction::Left }, + ], + + // Face 3 + [ + Connection { face: 5, side: Direction::Up }, + Connection { face: 4, side: Direction::Up }, + Connection { face: 2, side: Direction::Right }, + Connection { face: 0, side: Direction::Down }, + ], + + // Face 4 + [ + Connection { face: 5, side: Direction::Left }, + Connection { face: 1, side: Direction::Down }, + Connection { face: 2, side: Direction::Down }, + Connection { face: 3, side: Direction::Down }, + ], + + // Face 5 + [ + Connection { face: 0, side: Direction::Right }, + Connection { face: 1, side: Direction::Left }, + Connection { face: 4, side: Direction::Right }, + Connection { face: 3, side: Direction::Right }, + ], +]; +*/ + +// Input. Configuration: +// 01 +// 2 +// 34 +// 5 +const CONNECTIONS: [[Connection; 4]; 6] = [ + // Face 0 = U + [ + Connection { face: 1, side: Direction::Left }, + Connection { face: 2, side: Direction::Up }, + Connection { face: 3, side: Direction::Left }, + Connection { face: 5, side: Direction::Left }, + ], + + // Face 1 + [ + Connection { face: 4, side: Direction::Right }, + Connection { face: 2, side: Direction::Right }, + Connection { face: 0, side: Direction::Right }, + Connection { face: 5, side: Direction::Down }, + ], + + // Face 2 + [ + Connection { face: 1, side: Direction::Down }, + Connection { face: 4, side: Direction::Up }, + Connection { face: 3, side: Direction::Up }, + Connection { face: 0, side: Direction::Down }, + ], + + // Face 3 + [ + Connection { face: 4, side: Direction::Left }, + Connection { face: 5, side: Direction::Up }, + Connection { face: 0, side: Direction::Left }, + Connection { face: 2, side: Direction::Left }, + ], + + // Face 4 + [ + Connection { face: 1, side: Direction::Right }, + Connection { face: 5, side: Direction::Right }, + Connection { face: 3, side: Direction::Right }, + Connection { face: 2, side: Direction::Down }, + ], + + // Face 5 + [ + Connection { face: 4, side: Direction::Down }, + Connection { face: 1, side: Direction::Up }, + Connection { face: 0, side: Direction::Up }, + Connection { face: 3, side: Direction::Down }, + ], +]; + + +#[derive(Copy, Clone, Debug)] +struct Connection { + pub face: usize, + pub side: Direction +} + +struct Face { + pub tiles: [[Tile; CUBE_SIZE]; CUBE_SIZE], + offset_i: usize, + offset_j: usize +} + +#[derive(PartialEq, Debug, Copy, Clone)] +struct Position { + f: usize, + i: usize, + j: usize, + d: Direction +} + +#[allow(dead_code)] +impl Face { + pub fn empty() -> Face { + Face { + tiles: [[Tile::Skip; CUBE_SIZE]; CUBE_SIZE], + offset_i: 0, + offset_j: 0 + } + } + + pub fn is_empty(&self) -> bool { + self.tiles[0][0] == Tile::Skip + } + + pub fn print(&self) { + for i in 0..CUBE_SIZE { + for j in 0..CUBE_SIZE { + print!("{}", self.tiles[i][j].to_char()); + } + println!(); + } + } +} + +struct Cube { + pub faces: Vec +} + +type StepFn = fn(&Cube, Position) -> Position; + +impl Cube { + pub fn from_stdin() -> Cube { + let mut faces = vec![]; + let mut line = String::new(); + let mut offset_i = 0; + while faces.len() < 6 { + let mut row = [Face::empty(), Face::empty(), Face::empty(), + Face::empty(), Face::empty(), Face::empty()]; + for k in 0..CUBE_SIZE { + let _ = std::io::stdin().read_line(&mut line); + let bytes = &line.as_bytes(); + for l in 0..line.len()-1 { + row[l / CUBE_SIZE].tiles[k][l % CUBE_SIZE] = + Tile::from_byte(bytes[l]); + } + line.clear(); + } + let mut offset_j = 0; + for mut r in row { + r.offset_i = offset_i; + r.offset_j = offset_j; + if !r.is_empty() { + faces.push(r); + } + offset_j += CUBE_SIZE; + } + offset_i += CUBE_SIZE; + } + let _ = std::io::stdin().read_line(&mut line); // Read empty line + assert!(faces.len() == 6, "Cube has {} faces", faces.len()); + Cube { faces } + } + + fn start_position(&self) -> Position { + let j = self.faces[0].tiles[0].iter() + .position(|t| *t == Tile::Walk).unwrap(); + Position { f: 0, i: 0, j, d: Direction::Right } + } + + pub fn walk(&self, pos: Position, n: usize, step: StepFn) -> Position { + let mut p = pos; + for _ in 0..n { p = step(self, p); } + p + } +} + +fn flips(d1: Direction, d2: Direction) -> bool { + match d1 { + Direction::Right | Direction::Up => + d2 == Direction::Right || d2 == Direction::Up, + Direction::Down | Direction::Left => + d2 == Direction::Down || d2 == Direction::Left + } +} + +fn swaps(d1: Direction, d2: Direction) -> bool { + match d1 { + Direction::Right | Direction::Left => + d2 == Direction::Up || d2 == Direction::Down, + Direction::Up | Direction::Down => + d2 == Direction::Right || d2 == Direction::Left + } +} + +fn validate_connections(conn: &[[Connection; 4]; 6]) { + for i in 0..6 { + for j in 0..4 { + let c = conn[i][j]; + let d = conn[c.face][c.side.value()]; + assert!(d.face == i, "Bad connection: face {}-{}", i, j); + assert!(d.side.value() == j, "Bad connection: side {}-{}", i, j); + } + } +} + +fn overflow(i: i64, j: i64) -> Option { + if i == -1 { return Some(Direction::Up) } + if j == -1 { return Some(Direction::Left) } + if i as usize == CUBE_SIZE { return Some(Direction::Down) } + if j as usize == CUBE_SIZE { return Some(Direction::Right) } + None +} + +fn on_other_side(i: i64, flip: bool, positive: bool) -> usize { + const CUBE_SIZE_I64: i64 = CUBE_SIZE as i64; + (if i >= 0 && i < CUBE_SIZE_I64 { + if flip { CUBE_SIZE_I64 - i - 1 } else { i } + } else { + if positive { 0 } else { CUBE_SIZE_I64 - 1 } + }) as usize +} + +fn step(cube: &Cube, p: Position) -> Position { + let s = p.d.step(); + let mut inext = s.0 + p.i as i64; + let mut jnext = s.1 + p.j as i64; + + let ret = if let Some(d) = overflow(inext, jnext) { + let conn = CONNECTIONS[p.f][d.value()]; + let flip = flips(p.d, conn.side); + let new_direction = conn.side.opposite(); + let positive = new_direction.is_positive(); + if swaps(p.d, conn.side) { swap(&mut inext, &mut jnext) } + Position { + f: conn.face, + i: on_other_side(inext, flip, positive), + j: on_other_side(jnext, flip, positive), + d: conn.side.opposite() + } + } else { + Position { + f: p.f, + i: inext as usize, + j: jnext as usize, + d: p.d + } + }; + + if cube.faces[ret.f].tiles[ret.i][ret.j] == Tile::Wall { p } else { ret } +} + +fn password(cube: &Cube, p: Position) -> usize { + let f = &cube.faces[p.f]; + 1000 * (p.i + f.offset_i + 1) + 4 * (p.j + f.offset_j + 1) + p.d.value() +} + +fn main() { + validate_connections(&CONNECTIONS); + let cube = Cube::from_stdin(); + let mut position = cube.start_position(); + let (turns, steps) = read_instruction_line_from_stdin(); + for i in 0..turns.len() { + position = cube.walk(position, steps[i], step); + position.d = position.d.turn(turns[i]); + } + position = cube.walk(position, steps[steps.len()-1], step); + println!("{}", password(&cube, position)); +} -- cgit v1.3