Skip to content

Commit c7ad8a0

Browse files
committed
Add day 17
1 parent b0e1335 commit c7ad8a0

File tree

5 files changed

+239
-0
lines changed

5 files changed

+239
-0
lines changed

Day17_input.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#.##.##.
2+
.##..#..
3+
....#..#
4+
.##....#
5+
#..##...
6+
.###..#.
7+
..#.#..#
8+
.....#..

day17a/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "day17a"
3+
version = "0.1.0"
4+
authors = ["Linus Kardell <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]

day17a/src/main.rs

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use std::io;
2+
use std::io::Read;
3+
4+
struct Tile {
5+
enabled: bool,
6+
enabled_neighbors: u8,
7+
enabled_check_cycle: usize,
8+
}
9+
10+
fn main() {
11+
let mut input = String::new();
12+
io::stdin().read_to_string(&mut input).unwrap();
13+
14+
const CYCLES: usize = 6;
15+
let lines = input.lines().count();
16+
let columns = input.lines().next().unwrap().chars().count();
17+
18+
// 3D Grid for looking up whether a tile is enabled. The grid can can grow one position per cycle, so keep headroom
19+
// in each direction equal to the number of cycles.
20+
let mut tile_lookup: Vec<Vec<Vec<_>>> = (0..CYCLES * 2 + columns).map(|_| {
21+
(0..CYCLES * 2 + lines).map(|_| {
22+
// Inwards and outwards are mirror images, so no point in keeping both directions around
23+
(0..1 + CYCLES).map(|_| Tile {
24+
enabled: false,
25+
enabled_neighbors: 0,
26+
enabled_check_cycle: usize::MAX,
27+
}).collect()
28+
}).collect()
29+
}).collect();
30+
31+
let mut enabled_tiles = Vec::new();
32+
33+
// Enable tiles marked with #
34+
for (y, line) in input.lines().enumerate() {
35+
for (x, character) in line.chars().enumerate() {
36+
if character == '#' {
37+
let pos = (x + CYCLES, y + CYCLES, 0);
38+
tile_lookup[pos.0][pos.1][pos.2].enabled = true;
39+
enabled_tiles.push(pos);
40+
}
41+
}
42+
}
43+
44+
for cycle in 0..CYCLES {
45+
// List of enabled tiles and their neighbors
46+
let mut touched_tiles = Vec::new();
47+
48+
for &tile_pos in &enabled_tiles {
49+
// Iterate 0-2 and later subtract one.
50+
for x in 0..3 {
51+
for y in 0..3 {
52+
// Don't try to go downward into the mirror if we're at the bottom layer
53+
for z in if tile_pos.2 == 0 { 1 } else { 0 }..3 {
54+
let neigh_pos = (tile_pos.0 + x - 1, tile_pos.1 + y - 1, tile_pos.2 + z - 1);
55+
let tile = &mut tile_lookup[neigh_pos.0][neigh_pos.1][neigh_pos.2];
56+
if tile.enabled_check_cycle != cycle {
57+
tile.enabled_check_cycle = cycle;
58+
// Count is from a prevous cycle, and need to be reset
59+
tile.enabled_neighbors = 0;
60+
// Pushing position when resetting makes sure we don't add duplicates
61+
touched_tiles.push(neigh_pos);
62+
}
63+
// Tile is not neighbor of itself
64+
if neigh_pos != tile_pos {
65+
tile.enabled_neighbors += if neigh_pos.2 == 0 && tile_pos.2 == 1 {
66+
// If the current tile is above z-axis origin, and we are incrementing a tile at origin,
67+
// we should inrement it twice, since it should also be incremented by our mirror below
68+
// origin, which is not included in the simulation.
69+
2
70+
} else {
71+
1
72+
};
73+
}
74+
}
75+
}
76+
}
77+
}
78+
79+
enabled_tiles = touched_tiles.into_iter().filter(|&tile_pos| {
80+
let tile = &mut tile_lookup[tile_pos.0][tile_pos.1][tile_pos.2];
81+
let enabled = if tile.enabled {
82+
[2, 3].contains(&tile.enabled_neighbors)
83+
} else {
84+
tile.enabled_neighbors == 3
85+
};
86+
tile.enabled = enabled;
87+
enabled
88+
}).collect();
89+
}
90+
91+
println!("{}", enabled_tiles.iter().map(|&(_, _, z)| {
92+
if z != 0 {
93+
// If this is above z-axis origin, we also need to count its mirror
94+
2
95+
} else {
96+
1
97+
}
98+
}).sum::<usize>());
99+
}

day17b/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "day17b"
3+
version = "0.1.0"
4+
authors = ["Linus Kardell <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]

day17b/src/main.rs

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use std::io;
2+
use std::io::Read;
3+
4+
struct Tile {
5+
enabled: bool,
6+
enabled_neighbors: u8,
7+
enabled_check_cycle: usize,
8+
}
9+
10+
fn main() {
11+
let mut input = String::new();
12+
io::stdin().read_to_string(&mut input).unwrap();
13+
14+
const CYCLES: usize = 6;
15+
let lines = input.lines().count();
16+
let columns = input.lines().next().unwrap().chars().count();
17+
18+
// 5D Grid for looking up whether a tile is enabled. The grid can can grow one position per cycle, so keep headroom
19+
// in each direction equal to the number of cycles.
20+
let mut tile_lookup: Vec<Vec<Vec<Vec<_>>>> = (0..CYCLES * 2 + columns).map(|_| {
21+
(0..CYCLES * 2 + lines).map(|_| {
22+
// Inwards and outwards are mirror images, so no point in keeping all four quadrants around
23+
(0..1 + CYCLES).map(|_| {
24+
(0..1 + CYCLES).map(|_| Tile {
25+
enabled: false,
26+
enabled_neighbors: 0,
27+
enabled_check_cycle: usize::MAX,
28+
}).collect()
29+
}).collect()
30+
}).collect()
31+
}).collect();
32+
33+
let mut enabled_tiles = Vec::new();
34+
35+
// Enable tiles marked with #
36+
for (y, line) in input.lines().enumerate() {
37+
for (x, character) in line.chars().enumerate() {
38+
if character == '#' {
39+
let pos = (x + CYCLES, y + CYCLES, 0, 0);
40+
tile_lookup[pos.0][pos.1][pos.2][pos.3].enabled = true;
41+
enabled_tiles.push(pos);
42+
}
43+
}
44+
}
45+
46+
for cycle in 0..CYCLES {
47+
// List of enabled tiles and their neighbors
48+
let mut touched_tiles = Vec::new();
49+
50+
for &tile_pos in &enabled_tiles {
51+
// Iterate 0-2 and later subtract one.
52+
for x in 0..3 {
53+
for y in 0..3 {
54+
// Don't try to go downward into the mirror if we're at the bottom layer
55+
for z in if tile_pos.2 == 0 { 1 } else { 0 }..3 {
56+
for t in if tile_pos.3 == 0 { 1 } else { 0 }..3 {
57+
let neigh_pos = (
58+
tile_pos.0 + x - 1, tile_pos.1 + y - 1,
59+
tile_pos.2 + z - 1, tile_pos.3 + t - 1,
60+
);
61+
let tile = &mut tile_lookup[neigh_pos.0][neigh_pos.1][neigh_pos.2][neigh_pos.3];
62+
if tile.enabled_check_cycle != cycle {
63+
tile.enabled_check_cycle = cycle;
64+
// Count is from a prevous cycle, and need to be reset
65+
tile.enabled_neighbors = 0;
66+
// Pushing position when resetting makes sure we don't add duplicates
67+
touched_tiles.push(neigh_pos);
68+
}
69+
// Tile is not neighbor of itself
70+
if neigh_pos != tile_pos {
71+
let mut increment = 1;
72+
if neigh_pos.2 == 0 && tile_pos.2 == 1 {
73+
// If the current tile is above z-axis origin, and we are incrementing a tile at origin,
74+
// we should inrement it twice, since it should also be incremented by our mirror below
75+
// origin, which is not included in the simulation.
76+
increment *= 2;
77+
}
78+
if neigh_pos.3 == 0 && tile_pos.3 == 1 {
79+
// Same for t-axis
80+
increment *= 2;
81+
}
82+
tile.enabled_neighbors += increment;
83+
}
84+
}
85+
}
86+
}
87+
}
88+
}
89+
90+
enabled_tiles = touched_tiles.into_iter().filter(|&tile_pos| {
91+
let tile = &mut tile_lookup[tile_pos.0][tile_pos.1][tile_pos.2][tile_pos.3];
92+
let enabled = if tile.enabled {
93+
[2, 3].contains(&tile.enabled_neighbors)
94+
} else {
95+
tile.enabled_neighbors == 3
96+
};
97+
tile.enabled = enabled;
98+
enabled
99+
}).collect();
100+
}
101+
102+
println!("{}", enabled_tiles.iter().map(|&(_, _, z, t)| {
103+
let mut copies = 1;
104+
if z != 0 {
105+
// If this is above z-axis origin, we also need to count its mirror
106+
copies *= 2;
107+
}
108+
if t != 0 {
109+
// Same for t-axis
110+
copies *= 2;
111+
}
112+
copies
113+
}).sum::<usize>());
114+
}

0 commit comments

Comments
 (0)