Skip to content

Commit c5838af

Browse files
committed
Day23
1 parent ce6d5cd commit c5838af

File tree

6 files changed

+308
-1
lines changed

6 files changed

+308
-1
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ members = [
2121
"day19",
2222
"day20",
2323
"day21",
24-
"day22"
24+
"day22",
25+
"day23"
2526
]

day23/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "advent_of_code_2022_day23"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]

day23/examples/advent_input.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
let res = advent_of_code_2022_day23::elfs_game_of_plating("./day23/resources/input.txt");
3+
println!("{:?}", res)
4+
}

day23/examples/advent_input_part2.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
let res = advent_of_code_2022_day23::elfs_game_of_plating_till_stable("./day23/resources/input.txt");
3+
println!("{:?}", res)
4+
}

day23/resources/input.txt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#..##.....###..##..##...#.#..#..#.#.#.#..#...###..#.....#.##..##.#.##.#.##
2+
..###.##.....#...####.........####..##....########.#.#..########.......#..
3+
##.....##..##.#..#.#....#.##..###.#..#.#.....##..#.###...##..#..##....#...
4+
.####..#...#.....#....###....###.###.##..##..#.##..#.#..##..###....##..###
5+
#.##.#.#.#.###..###.#..##...##.##...#.###.#.#.#.....#.##.#.#.#...#...#.###
6+
##...#......###...#.#.#.##.#.##..#..##..#.....##.#####..######.##..#.#...#
7+
.#....##.....##.#.....#...###..#.#.#..#.......###.....##....##.#..#.##....
8+
....#.#.####..#.#...#.##.####....##..#.#..#.#..##.###.####....#.##..###.##
9+
...#.####..###..#..##.##..#.#..##.##...#....####.####...#..###.#####.#.#.#
10+
#....####.#.#..######...#.#.##.#...######.#..#.#..##...#.......##...#...#.
11+
......##..##...#..#....###...#..##.#.#.#...###.#..####.###...####...#..#..
12+
...#.###.#.#.#.###...##.......#.###...#....#.....#.....##.##.##.#..###.#.#
13+
##.##.###.###..#.#..##.#.####.#.#.#.##...#.###......##...#.#.###..##...#.#
14+
.###.###...#...##.#.#.#.#..#....#####..##.#.###..#.#...##.##..#...#..##.#.
15+
..###...####.##.#.#...###..##...#.####.#####..#..#..#.#####.#..#.#...#....
16+
..###..##.##....##....#.##..#####.#..##..####...#.#..#..##..#..###.##..#..
17+
.....##.#....##.##..#.#...##.#.##..#....#.#.#..###.###.###..#..##.#..#.###
18+
.#..##..#...#..#..#.##.##..####.#..#..####...##.#...##.###...#.#.##.#..###
19+
.#######.#.#.##.#...##.#...#####..###...##..#######.###.#######..##..#####
20+
#..##.###.##..#.##.#.#.#.....#.###.##...#.##.##.....#..###.#..#.#..##.####
21+
......#...#.###.###.#.##.##.####.####.......#.#.#......##...##.#####.###..
22+
#.#.#.#.######...###.#####....#.######.#...#.#.##.#.###.#..##.##.....####.
23+
...#.########.##.#....#.##...#...#...#.#.##.##..##...###.#.#######..#...#.
24+
..###.###.#.####.###..##...####..#.###.####.##....#.##.#...##..#........#.
25+
#...#..###..#.#..#..##....#..###.###..#.######.##.#####..#.#.#.##.###..#.#
26+
#.##.#.##.#..#..#######.###.....#...#..##.#......#.##.....#..##.##...#.##.
27+
.#.#.####.##.###..#####...##.#..###.##.#.###..####...#####.#..##.##..##.##
28+
.#....##..#...#..###...#.##.###.#.#.....#...#.###..##...#.#...#...#..#..#.
29+
##.#..######.#####....#..#.#.###...#..#.##..#.#.###.#...##..######..#....#
30+
..##.##.#...#......#####...#..##.#..#...#..###.#.###..######.#.....#.#....
31+
#.###.###..#.#.#.##.###..#####...###.###.#.#.#..##..#..##..#.#...######.#.
32+
####...#....##..####.#.##..##....#.#.###...##..###.#.#..#..##..#.#...####.
33+
#...##.##..#..##.##.#..####.#.#####.#....#.###..#...##.##...##....####.#..
34+
#.##.###.#..#....#.#.###.##..##..##.###.####.###.#..#..#...#.#.##.##.#....
35+
....##..#...#.######....#..#.####...#.....##..#...#.##.....#..#.#...##.##.
36+
...##..#...#.#.####.##.#.##...#.###..##.#.....#####...####.##.#.#..#.###.#
37+
##..###..#....###.#..##...######..##.####..#..####.###.###.#.###.#.#######
38+
..##.#..##.#####..####......#...##.#.#...#....#.##...#.######.###.##.##...
39+
#..####.##....##.##...#######.#...#.#..####..###....#......##..#.#######..
40+
......#....#..#.##.#...####.#.##.##.##..###.#..####..##..#...##.####..#.##
41+
.#####.#....##..#...##..###.#.#.####.##.#####..#..#.###.####.#####.######.
42+
...#.....#.#.###.#.#.##....###..#.#.####..##.#.#.##.##.#.###.#...###..#...
43+
#......#...####.#....#..#..##.#.#..##.##..#..#..###.##..#...#######..#.##.
44+
#.#.#.####.#..#.....##.##.###.#.#...#.#.#.##.#....##..##....##.#..##.#.##.
45+
.....#.#..#.#.##.##.#.#.#####.###.##.#..######.#..#.#.#..#####.##...###...
46+
#...#..#..#....#...#####.#.##..#.#.##.#.###.##..#####.##...##.#.##.####..#
47+
.#.#..#.#...######.#.#..#..#...#####....#..#.#.######.######.#..#.....####
48+
##.###....##..####.....#####...###.##..##.#...#.#.#..##.##..#.#.##.#.#.#..
49+
###.......###......####.#.##.....######.#.#..##.###.#..#.#..##.##.##..#...
50+
..#...#...###.###...#.#...###.####.##.##.#.##.#...##.##.#......##.#.####.#
51+
##.#.....#.#.#....#....#.####.#...##.#.#.#..#..###...#####......#...#.#.#.
52+
..#.##....#..#.....#....#....#.#.##.......####.#..#.#.##.#.###....##....##
53+
#.#..#..#...#####.##.......#.#.##.....##.#.#.###.......#####.#..#.#...#..#
54+
..#####.#...##.#.#.#.##......#.#.######....#.####.##...##.###..#.###.#.#..
55+
.##..##...#..#.#.#...#.#...#.#####.......#..##..##.##..........#..#..##...
56+
.#.#..#####...##.##.##....##..#...###.#####...##..#.....#.#####.#....##..#
57+
##.####..#.#...#.#.####.####...#####..#.#.##....#...##.#....##.##.##...##.
58+
#..#..#.....#...........#..#...##.####.#..#..##.#.....#...#..#.##.########
59+
#.....#..#.#.##.##.#.###..##..#.#.#..#.##.#.#####....####.#..#.###.#..#.#.
60+
##...#...##.######.#.#####.......##.#.##..###..####..##..#...##.#####.#.##
61+
....#...#..#...####.###.##.#...##...#...####.####..##...##..#.#...##.##.#.
62+
#######.###.######..##..##...##...#..#...##.#.#.##..#...#.##.#.#.#.##..#.#
63+
...#..#.##.##....###.....#.##.##.####.#######..########.##..##.##.#######.
64+
#.#.##.#...#####.##.#...##.#..#.##...#.###.#...##.###...#.##..#...#...###.
65+
##.#..#....###.#...#.###...#.##.###.##.####....##...#.##..##......##....#.
66+
.###...####.##...##.#...#....#####.##...#.#..##..##.##..#..#..##...#..#...
67+
#.##...#.##....##.##...#..#.##..###..##....####.#..#.###.#......##...#..##
68+
#...#..#...###......##..#.....###.#.#.##..#.#.###...####.#.##..##..#..##.#
69+
..###...#..#..#..####....##.#..##..#....###...###...###.###.#.#.####.####.
70+
###......#.......#...#.#.#.....##.##..#...##...#.#...#.#.##.#.#...###.....
71+
#.##.##....###.###.###.#..#.####.#.###.#.#.#.#..###..####.##.#.####..#####
72+
#.#..#..#.###..#.#...#....#..#.#.#...##.##....#.#.....#.####..#..##..##.##
73+
#...#####..#..#.###.##.##.####.##..###....#.###.###.#.#....#.....####.#..#
74+
###..##.##.###.#.###..#..###.####..#.#...##.#..###.#...##...#..##.......##

day23/src/lib.rs

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
use std::collections::{BTreeSet, BTreeMap};
2+
3+
#[allow(dead_code)]
4+
fn print_positions(positions: &BTreeSet<(isize, isize)>) {
5+
let pos_bounds = position_bounds(positions);
6+
// println!("{:?}", pos_bounds);
7+
(pos_bounds.0.1..=pos_bounds.1.1).rev().for_each(
8+
|y| {
9+
(pos_bounds.0.0..=pos_bounds.1.0).for_each(
10+
|x| {
11+
if positions.contains(&(x, y)) {
12+
print!("#")
13+
} else {
14+
print!(".")
15+
}
16+
}
17+
);
18+
println!();
19+
}
20+
)
21+
}
22+
23+
fn position_bounds(positions: &BTreeSet<(isize, isize)>) -> ((isize, isize), (isize, isize)) {
24+
(
25+
(
26+
positions.iter().map(|(x, _)| *x).min_by(|lx, rx| lx.cmp(rx)).unwrap(),
27+
positions.iter().map(|(_, y)| *y).min_by(|ly, ry| ly.cmp(ry)).unwrap()
28+
),
29+
(
30+
positions.iter().map(|(x, _)| *x).max_by(|lx, rx| lx.cmp(rx)).unwrap(),
31+
positions.iter().map(|(_, y)| *y).max_by(|ly, ry| ly.cmp(ry)).unwrap()
32+
)
33+
)
34+
}
35+
36+
fn initial_positions(plots: &str) -> BTreeSet<(isize, isize)> {
37+
let mut bt = BTreeSet::new();
38+
plots.lines().rev().enumerate()
39+
.for_each(
40+
|(y, l)| {
41+
l.chars().enumerate()
42+
.for_each(
43+
|(x, c)| {
44+
if c == '#' {
45+
bt.insert((x as isize, y as isize));
46+
}
47+
}
48+
)
49+
}
50+
);
51+
bt
52+
}
53+
54+
fn check_north(pos: &(isize, isize), positions: &BTreeSet<(isize, isize)>) -> bool {
55+
let nw = !positions.contains(&(pos.0 - 1, pos.1 + 1));
56+
let n = !positions.contains(&(pos.0, pos.1 + 1));
57+
let ne = !positions.contains(&(pos.0 + 1, pos.1 + 1));
58+
nw && n && ne
59+
}
60+
61+
fn check_south(pos: &(isize, isize), positions: &BTreeSet<(isize, isize)>) -> bool {
62+
let sw = !positions.contains(&(pos.0 - 1, pos.1 - 1));
63+
let s = !positions.contains(&(pos.0, pos.1 - 1));
64+
let se = !positions.contains(&(pos.0 + 1, pos.1 - 1));
65+
sw && s && se
66+
}
67+
68+
fn check_east(pos: &(isize, isize), positions: &BTreeSet<(isize, isize)>) -> bool {
69+
let ne = !positions.contains(&(pos.0 + 1, pos.1 + 1));
70+
let e = !positions.contains(&(pos.0 + 1, pos.1));
71+
let se = !positions.contains(&(pos.0 + 1, pos.1 - 1));
72+
ne && e && se
73+
}
74+
75+
fn check_west(pos: &(isize, isize), positions: &BTreeSet<(isize, isize)>) -> bool {
76+
let nw = !positions.contains(&(pos.0 - 1, pos.1 + 1));
77+
let w = !positions.contains(&(pos.0 - 1, pos.1));
78+
let sw = !positions.contains(&(pos.0 - 1, pos.1 - 1));
79+
nw && w && sw
80+
}
81+
82+
fn round(positions: &BTreeSet<(isize, isize)>, round: usize) -> BTreeSet<(isize, isize)> {
83+
let intents: BTreeMap<_, _> = positions.iter()
84+
.map(
85+
|pos| {
86+
let round_tests = vec![
87+
(check_north(pos, positions), (pos.0, pos.1 + 1)),
88+
(check_south(pos, positions), (pos.0, pos.1 - 1)),
89+
(check_west(pos, positions), (pos.0 - 1, pos.1)),
90+
(check_east(pos, positions), (pos.0 + 1, pos.1))
91+
];
92+
if round_tests.iter().all(|(b, _)| *b) {
93+
(pos, *pos)
94+
} else {
95+
let round_cycle = round_tests.iter().cycle();
96+
let mut round_intent = None;
97+
for (test, intent) in round_cycle.skip(round).take(4) {
98+
if *test {
99+
round_intent = Some(intent);
100+
break;
101+
}
102+
}
103+
let fround_intent = round_intent.unwrap_or(pos);
104+
(pos, *fround_intent)
105+
}
106+
}
107+
)
108+
.collect();
109+
let unique_intents = intents.values()
110+
.fold(
111+
(BTreeSet::new(), BTreeSet::new()),
112+
|(mut uniq, mut dup), int| {
113+
if dup.contains(int) {
114+
()
115+
} else if uniq.contains(int) {
116+
uniq.remove(int);
117+
dup.insert(int);
118+
} else {
119+
uniq.insert(int);
120+
};
121+
(uniq, dup)
122+
}
123+
).0;
124+
125+
intents.iter()
126+
.filter_map(
127+
|(pos, int)| {
128+
if unique_intents.contains(&int) {
129+
Some(*int)
130+
} else {
131+
Some(**pos)
132+
}
133+
}
134+
)
135+
.collect()
136+
}
137+
138+
fn empty_plots(positions: &BTreeSet<(isize, isize)>) -> u64 {
139+
let (minbounds, maxbounds) = position_bounds(positions);
140+
(minbounds.0..=maxbounds.0).fold(
141+
0,
142+
|cum, x| {
143+
cum + (minbounds.1..=maxbounds.1).fold(
144+
0,
145+
|ycum, y| {
146+
if positions.contains(&(x, y)) {
147+
ycum
148+
} else {
149+
ycum + 1
150+
}
151+
}
152+
)
153+
}
154+
)
155+
}
156+
157+
fn game_of_plating(plots: &str, rounds: usize) -> (u64, u64) {
158+
let mut positions = initial_positions(plots);
159+
let mut stable_round = 0;
160+
for r in 0..rounds {
161+
let tmp = round(&positions, r);
162+
stable_round = r + 1;
163+
if tmp.eq(&positions) {
164+
break;
165+
} else {
166+
positions = tmp;
167+
}
168+
}
169+
(empty_plots(&positions), stable_round as u64)
170+
}
171+
172+
pub fn elfs_game_of_plating(input_path: &str) -> u64 {
173+
let content = std::fs::read_to_string(input_path);
174+
match content {
175+
Ok(content) => game_of_plating(&content, 10).0,
176+
Err(er) => {
177+
println!("{}", er);
178+
0
179+
}
180+
}
181+
}
182+
183+
pub fn elfs_game_of_plating_till_stable(input_path: &str) -> u64 {
184+
let content = std::fs::read_to_string(input_path);
185+
match content {
186+
Ok(content) => game_of_plating(&content, std::usize::MAX).1,
187+
Err(er) => {
188+
println!("{}", er);
189+
0
190+
}
191+
}
192+
}
193+
194+
#[cfg(test)]
195+
mod tests {
196+
use super::*;
197+
198+
const TEST_INP1: &str =
199+
r#"....#..
200+
..###.#
201+
#...#.#
202+
.#...##
203+
#.###..
204+
##.#.##
205+
.#..#.."#;
206+
207+
#[test]
208+
fn test_input1() {
209+
assert_eq!(game_of_plating(TEST_INP1, 10).0, 110)
210+
}
211+
212+
#[test]
213+
fn test_input1_part2() {
214+
assert_eq!(game_of_plating(TEST_INP1, std::usize::MAX).1, 20)
215+
}
216+
}

0 commit comments

Comments
 (0)