aboutsummaryrefslogtreecommitdiff
path: root/2022
diff options
context:
space:
mode:
Diffstat (limited to '2022')
-rw-r--r--2022/22/a.rs81
-rw-r--r--2022/22/b.rs314
-rw-r--r--2022/22/common.rs111
3 files changed, 506 insertions, 0 deletions
diff --git a/2022/22/a.rs b/2022/22/a.rs
new file mode 100644
index 0000000..40f9c44
--- /dev/null
+++ b/2022/22/a.rs
@@ -0,0 +1,81 @@
1use std::cmp::max;
2mod common;
3use common::*;
4
5#[derive(Copy, Clone, Debug)]
6pub struct Position {
7 pub i: usize,
8 pub j: usize,
9 pub d: Direction
10}
11
12pub struct Map {
13 pub tiles: Vec<Vec<Tile>>
14}
15
16type StepFn = fn(&Map, Position) -> Position;
17
18impl Map {
19 pub fn from_stdin() -> Map {
20 let mut maxlen = 0;
21 let mut tiles = vec![];
22 let mut line = String::new();
23 while std::io::stdin().read_line(&mut line).unwrap() > 1 {
24 let v = line[0..line.len()-1].as_bytes().iter()
25 .map(|b| Tile::from_byte(*b)).collect::<Vec<_>>();
26 maxlen = max(maxlen, v.len());
27 tiles.push(v);
28 line.clear();
29 }
30 for v in &mut tiles {
31 while v.len() < maxlen { v.push(Tile::Skip); }
32 }
33 Map { tiles }
34 }
35
36 pub fn start_position(&self) -> Position {
37 let first_valid = self.tiles[0].iter()
38 .position(|t| *t == Tile::Walk).unwrap();
39 Position { i: 0, j: first_valid, d: Direction::Right }
40 }
41
42 pub fn walk(&self, pos: Position, n: usize, step: StepFn) -> Position {
43 let mut p = pos;
44 for _ in 0..n { p = step(self, p); }
45 p
46 }
47}
48
49fn step(map: &Map, position: Position) -> Position {
50 let imax = map.tiles.len();
51 let jmax = map.tiles[0].len();
52 let s = position.d.step();
53 let mut p = position;
54 loop {
55 let inext = ((s.0 + imax as i64) as usize + p.i) % imax;
56 let jnext = ((s.1 + jmax as i64) as usize + p.j) % jmax;
57 p = Position { i: inext, j: jnext, d: p.d };
58 match map.tiles[p.i][p.j] {
59 Tile::Walk => return p,
60 Tile::Wall => return position,
61 Tile::Skip => ()
62 }
63 }
64}
65
66fn password(p: Position) -> usize {
67 1000 * (p.i+1) + 4 * (p.j+1) + p.d.value()
68}
69
70fn main() {
71 let map = Map::from_stdin();
72 let (turns, steps) = read_instruction_line_from_stdin();
73 let mut position = map.start_position();
74
75 for i in 0..turns.len() {
76 position = map.walk(position, steps[i], step);
77 position.d = position.d.turn(turns[i]);
78 }
79 position = map.walk(position, steps[steps.len()-1], step);
80 println!("{}", password(position));
81}
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 @@
1use std::mem::swap;
2mod common;
3use common::*;
4
5// Use 4 for the test input, 50 for the real one
6//const CUBE_SIZE: usize = 4;
7const 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/*
20const 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
76const 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)]
128struct Connection {
129 pub face: usize,
130 pub side: Direction
131}
132
133struct 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)]
140struct Position {
141 f: usize,
142 i: usize,
143 j: usize,
144 d: Direction
145}
146
147#[allow(dead_code)]
148impl 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
171struct Cube {
172 pub faces: Vec<Face>
173}
174
175type StepFn = fn(&Cube, Position) -> Position;
176
177impl 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
223fn 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
232fn 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
241fn 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
252fn 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
260fn 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
269fn 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
298fn 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
303fn 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}
diff --git a/2022/22/common.rs b/2022/22/common.rs
new file mode 100644
index 0000000..881513c
--- /dev/null
+++ b/2022/22/common.rs
@@ -0,0 +1,111 @@
1use std::cmp::*;
2
3#[derive(PartialEq, Copy, Clone, Debug)]
4pub enum Tile { Walk, Wall, Skip }
5
6#[allow(dead_code)]
7impl Tile {
8 pub fn from_byte(b: u8) -> Tile {
9 match b {
10 b'.' => Tile::Walk,
11 b'#' => Tile::Wall,
12 b' ' => Tile::Skip,
13 _ => panic!("not a valid tile {}", b)
14 }
15 }
16
17 pub fn to_char(&self) -> char {
18 match self {
19 Tile::Walk => '.',
20 Tile::Wall => '#',
21 Tile::Skip => ' '
22 }
23 }
24}
25
26#[derive(PartialEq, Copy, Clone, Debug)]
27pub enum Direction { Up, Down, Right, Left }
28
29#[allow(dead_code)]
30impl Direction {
31 pub fn from_char(c: char) -> Direction {
32 match c {
33 'U' => Direction::Up,
34 'D' => Direction::Down,
35 'R' => Direction::Right,
36 'L' => Direction::Left,
37 _ => panic!("invalid char for direction")
38 }
39 }
40
41 pub fn turn(&self, t: Direction) -> Direction {
42 match t {
43 Direction::Right => match self {
44 Direction::Up => Direction::Right,
45 Direction::Right => Direction::Down,
46 Direction::Down => Direction::Left,
47 Direction::Left => Direction::Up
48 },
49 Direction::Left => match self {
50 Direction::Up => Direction::Left,
51 Direction::Left => Direction::Down,
52 Direction::Down => Direction::Right,
53 Direction::Right => Direction::Up
54 }
55 _ => panic!("cannot turn up or down")
56 }
57 }
58
59 pub fn step(&self) -> (i64, i64) {
60 match self {
61 Direction::Up => (-1, 0),
62 Direction::Down => (1, 0),
63 Direction::Right => (0, 1),
64 Direction::Left => (0, -1)
65 }
66 }
67
68 pub fn value(&self) -> usize {
69 match self {
70 Direction::Right => 0,
71 Direction::Down => 1,
72 Direction::Left => 2,
73 Direction::Up => 3
74 }
75 }
76
77 pub fn opposite(&self) -> Direction {
78 match self {
79 Direction::Right => Direction::Left,
80 Direction::Left => Direction::Right,
81 Direction::Up => Direction::Down,
82 Direction::Down => Direction::Up
83 }
84 }
85
86 pub fn is_positive(&self) -> bool {
87 *self == Direction::Down || *self == Direction::Right
88 }
89}
90
91pub fn read_instruction_line_from_stdin() -> (Vec<Direction>, Vec<usize>) {
92 let mut dir = vec![];
93 let mut step = vec![];
94 let mut line = String::new();
95 let _ = std::io::stdin().read_line(&mut line);
96 let mut i = 0;
97 while i < line.len()-1 {
98 match line.chars().nth(i).unwrap() {
99 '0'..='9' => {
100 let j = line[i..].find(|c: char| !c.is_digit(10)).unwrap() + i;
101 step.push(line[i..j].parse::<usize>().unwrap());
102 i = j;
103 },
104 c => {
105 dir.push(Direction::from_char(c));
106 i += 1;
107 }
108 }
109 }
110 (dir, step)
111}

Generated with cgit - Back to sebastiano.tronto.net