b.rs (9136B)
1 use std::mem::swap; 2 mod common; 3 use common::*; 4 5 // Use 4 for the test input, 50 for the real one 6 //const CUBE_SIZE: usize = 4; 7 const CUBE_SIZE: usize = 50; 8 9 // Connections between faces to make the cube 3D. 10 // This is hard coded to work for my specific input. 11 // To make it work for a different input you have to change this. 12 // The faces are in top-to-bottom, left-to-right order of input. 13 // For each face, the 4 connections are in order right, down, left, up. 14 15 // Test case. Configuration: 16 // 0 U = 0, D = 4 17 // 123 R = 5, L = 2 18 // 45 F = 3, B = 1 19 /* 20 const CONNECTIONS: [[Connection; 4]; 6] = [ 21 // Face 0 = U 22 [ 23 Connection { face: 5, side: Direction::Right }, 24 Connection { face: 3, side: Direction::Up }, 25 Connection { face: 2, side: Direction::Up }, 26 Connection { face: 1, side: Direction::Up }, 27 ], 28 29 // Face 1 30 [ 31 Connection { face: 2, side: Direction::Left }, 32 Connection { face: 4, side: Direction::Down }, 33 Connection { face: 5, side: Direction::Down }, 34 Connection { face: 0, side: Direction::Up }, 35 ], 36 37 // Face 2 38 [ 39 Connection { face: 3, side: Direction::Left }, 40 Connection { face: 4, side: Direction::Left }, 41 Connection { face: 1, side: Direction::Right }, 42 Connection { face: 0, side: Direction::Left }, 43 ], 44 45 // Face 3 46 [ 47 Connection { face: 5, side: Direction::Up }, 48 Connection { face: 4, side: Direction::Up }, 49 Connection { face: 2, side: Direction::Right }, 50 Connection { face: 0, side: Direction::Down }, 51 ], 52 53 // Face 4 54 [ 55 Connection { face: 5, side: Direction::Left }, 56 Connection { face: 1, side: Direction::Down }, 57 Connection { face: 2, side: Direction::Down }, 58 Connection { face: 3, side: Direction::Down }, 59 ], 60 61 // Face 5 62 [ 63 Connection { face: 0, side: Direction::Right }, 64 Connection { face: 1, side: Direction::Left }, 65 Connection { face: 4, side: Direction::Right }, 66 Connection { face: 3, side: Direction::Right }, 67 ], 68 ]; 69 */ 70 71 // Input. Configuration: 72 // 01 73 // 2 74 // 34 75 // 5 76 const CONNECTIONS: [[Connection; 4]; 6] = [ 77 // Face 0 = U 78 [ 79 Connection { face: 1, side: Direction::Left }, 80 Connection { face: 2, side: Direction::Up }, 81 Connection { face: 3, side: Direction::Left }, 82 Connection { face: 5, side: Direction::Left }, 83 ], 84 85 // Face 1 86 [ 87 Connection { face: 4, side: Direction::Right }, 88 Connection { face: 2, side: Direction::Right }, 89 Connection { face: 0, side: Direction::Right }, 90 Connection { face: 5, side: Direction::Down }, 91 ], 92 93 // Face 2 94 [ 95 Connection { face: 1, side: Direction::Down }, 96 Connection { face: 4, side: Direction::Up }, 97 Connection { face: 3, side: Direction::Up }, 98 Connection { face: 0, side: Direction::Down }, 99 ], 100 101 // Face 3 102 [ 103 Connection { face: 4, side: Direction::Left }, 104 Connection { face: 5, side: Direction::Up }, 105 Connection { face: 0, side: Direction::Left }, 106 Connection { face: 2, side: Direction::Left }, 107 ], 108 109 // Face 4 110 [ 111 Connection { face: 1, side: Direction::Right }, 112 Connection { face: 5, side: Direction::Right }, 113 Connection { face: 3, side: Direction::Right }, 114 Connection { face: 2, side: Direction::Down }, 115 ], 116 117 // Face 5 118 [ 119 Connection { face: 4, side: Direction::Down }, 120 Connection { face: 1, side: Direction::Up }, 121 Connection { face: 0, side: Direction::Up }, 122 Connection { face: 3, side: Direction::Down }, 123 ], 124 ]; 125 126 127 #[derive(Copy, Clone, Debug)] 128 struct Connection { 129 pub face: usize, 130 pub side: Direction 131 } 132 133 struct Face { 134 pub tiles: [[Tile; CUBE_SIZE]; CUBE_SIZE], 135 offset_i: usize, 136 offset_j: usize 137 } 138 139 #[derive(PartialEq, Debug, Copy, Clone)] 140 struct Position { 141 f: usize, 142 i: usize, 143 j: usize, 144 d: Direction 145 } 146 147 #[allow(dead_code)] 148 impl Face { 149 pub fn empty() -> Face { 150 Face { 151 tiles: [[Tile::Skip; CUBE_SIZE]; CUBE_SIZE], 152 offset_i: 0, 153 offset_j: 0 154 } 155 } 156 157 pub fn is_empty(&self) -> bool { 158 self.tiles[0][0] == Tile::Skip 159 } 160 161 pub fn print(&self) { 162 for i in 0..CUBE_SIZE { 163 for j in 0..CUBE_SIZE { 164 print!("{}", self.tiles[i][j].to_char()); 165 } 166 println!(); 167 } 168 } 169 } 170 171 struct Cube { 172 pub faces: Vec<Face> 173 } 174 175 type StepFn = fn(&Cube, Position) -> Position; 176 177 impl Cube { 178 pub fn from_stdin() -> Cube { 179 let mut faces = vec![]; 180 let mut line = String::new(); 181 let mut offset_i = 0; 182 while faces.len() < 6 { 183 let mut row = [Face::empty(), Face::empty(), Face::empty(), 184 Face::empty(), Face::empty(), Face::empty()]; 185 for k in 0..CUBE_SIZE { 186 let _ = std::io::stdin().read_line(&mut line); 187 let bytes = &line.as_bytes(); 188 for l in 0..line.len()-1 { 189 row[l / CUBE_SIZE].tiles[k][l % CUBE_SIZE] = 190 Tile::from_byte(bytes[l]); 191 } 192 line.clear(); 193 } 194 let mut offset_j = 0; 195 for mut r in row { 196 r.offset_i = offset_i; 197 r.offset_j = offset_j; 198 if !r.is_empty() { 199 faces.push(r); 200 } 201 offset_j += CUBE_SIZE; 202 } 203 offset_i += CUBE_SIZE; 204 } 205 let _ = std::io::stdin().read_line(&mut line); // Read empty line 206 assert!(faces.len() == 6, "Cube has {} faces", faces.len()); 207 Cube { faces } 208 } 209 210 fn start_position(&self) -> Position { 211 let j = self.faces[0].tiles[0].iter() 212 .position(|t| *t == Tile::Walk).unwrap(); 213 Position { f: 0, i: 0, j, d: Direction::Right } 214 } 215 216 pub fn walk(&self, pos: Position, n: usize, step: StepFn) -> Position { 217 let mut p = pos; 218 for _ in 0..n { p = step(self, p); } 219 p 220 } 221 } 222 223 fn flips(d1: Direction, d2: Direction) -> bool { 224 match d1 { 225 Direction::Right | Direction::Up => 226 d2 == Direction::Right || d2 == Direction::Up, 227 Direction::Down | Direction::Left => 228 d2 == Direction::Down || d2 == Direction::Left 229 } 230 } 231 232 fn swaps(d1: Direction, d2: Direction) -> bool { 233 match d1 { 234 Direction::Right | Direction::Left => 235 d2 == Direction::Up || d2 == Direction::Down, 236 Direction::Up | Direction::Down => 237 d2 == Direction::Right || d2 == Direction::Left 238 } 239 } 240 241 fn validate_connections(conn: &[[Connection; 4]; 6]) { 242 for i in 0..6 { 243 for j in 0..4 { 244 let c = conn[i][j]; 245 let d = conn[c.face][c.side.value()]; 246 assert!(d.face == i, "Bad connection: face {}-{}", i, j); 247 assert!(d.side.value() == j, "Bad connection: side {}-{}", i, j); 248 } 249 } 250 } 251 252 fn overflow(i: i64, j: i64) -> Option<Direction> { 253 if i == -1 { return Some(Direction::Up) } 254 if j == -1 { return Some(Direction::Left) } 255 if i as usize == CUBE_SIZE { return Some(Direction::Down) } 256 if j as usize == CUBE_SIZE { return Some(Direction::Right) } 257 None 258 } 259 260 fn on_other_side(i: i64, flip: bool, positive: bool) -> usize { 261 const CUBE_SIZE_I64: i64 = CUBE_SIZE as i64; 262 (if i >= 0 && i < CUBE_SIZE_I64 { 263 if flip { CUBE_SIZE_I64 - i - 1 } else { i } 264 } else { 265 if positive { 0 } else { CUBE_SIZE_I64 - 1 } 266 }) as usize 267 } 268 269 fn step(cube: &Cube, p: Position) -> Position { 270 let s = p.d.step(); 271 let mut inext = s.0 + p.i as i64; 272 let mut jnext = s.1 + p.j as i64; 273 274 let ret = if let Some(d) = overflow(inext, jnext) { 275 let conn = CONNECTIONS[p.f][d.value()]; 276 let flip = flips(p.d, conn.side); 277 let new_direction = conn.side.opposite(); 278 let positive = new_direction.is_positive(); 279 if swaps(p.d, conn.side) { swap(&mut inext, &mut jnext) } 280 Position { 281 f: conn.face, 282 i: on_other_side(inext, flip, positive), 283 j: on_other_side(jnext, flip, positive), 284 d: conn.side.opposite() 285 } 286 } else { 287 Position { 288 f: p.f, 289 i: inext as usize, 290 j: jnext as usize, 291 d: p.d 292 } 293 }; 294 295 if cube.faces[ret.f].tiles[ret.i][ret.j] == Tile::Wall { p } else { ret } 296 } 297 298 fn password(cube: &Cube, p: Position) -> usize { 299 let f = &cube.faces[p.f]; 300 1000 * (p.i + f.offset_i + 1) + 4 * (p.j + f.offset_j + 1) + p.d.value() 301 } 302 303 fn main() { 304 validate_connections(&CONNECTIONS); 305 let cube = Cube::from_stdin(); 306 let mut position = cube.start_position(); 307 let (turns, steps) = read_instruction_line_from_stdin(); 308 for i in 0..turns.len() { 309 position = cube.walk(position, steps[i], step); 310 position.d = position.d.turn(turns[i]); 311 } 312 position = cube.walk(position, steps[steps.len()-1], step); 313 println!("{}", password(&cube, position)); 314 }