Skip to content

Commit 7240499

Browse files
committed
Solve day23
1 parent 8d480c0 commit 7240499

File tree

5 files changed

+291
-6
lines changed

5 files changed

+291
-6
lines changed

.vscode/launch.json

+40-5
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,36 @@
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7+
{
8+
"type": "lldb",
9+
"request": "launch",
10+
"name": "Debug current unit tests",
11+
"cargo": {
12+
"args": [
13+
"test",
14+
"--package",
15+
"advent_of_code",
16+
"--bin",
17+
"${fileBasenameNoExtension}",
18+
"--",
19+
"tests",
20+
"--nocapture"
21+
],
22+
},
23+
"args": [],
24+
"cwd": "${workspaceFolder}"
25+
},
726
{
827
"type": "lldb",
928
"request": "launch",
1029
"name": "Debug unit tests in executable 'advent_of_code'",
1130
"cargo": {
12-
"args": ["test", "--no-run", "--bin=advent_of_code", "--package=advent_of_code"],
31+
"args": [
32+
"test",
33+
"--no-run",
34+
"--bin=advent_of_code",
35+
"--package=advent_of_code"
36+
],
1337
"filter": {
1438
"name": "advent_of_code",
1539
"kind": "bin"
@@ -23,21 +47,32 @@
2347
"request": "launch",
2448
"name": "Debug executable 'advent_of_code'",
2549
"cargo": {
26-
"args": ["build", "--bin=advent_of_code", "--package=advent_of_code"],
50+
"args": [
51+
"build",
52+
"--bin=advent_of_code",
53+
"--package=advent_of_code"
54+
],
2755
"filter": {
2856
"name": "advent_of_code",
2957
"kind": "bin"
3058
}
3159
},
32-
"args": ["1"],
60+
"args": [
61+
"1"
62+
],
3363
"cwd": "${workspaceFolder}"
3464
},
3565
{
3666
"type": "lldb",
3767
"request": "launch",
3868
"name": "Debug unit tests in library 'advent_of_code'",
3969
"cargo": {
40-
"args": ["test", "--no-run", "--lib", "--package=advent_of_code"],
70+
"args": [
71+
"test",
72+
"--no-run",
73+
"--lib",
74+
"--package=advent_of_code"
75+
],
4176
"filter": {
4277
"name": "advent_of_code",
4378
"kind": "lib"
@@ -47,4 +82,4 @@
4782
"cwd": "${workspaceFolder}"
4883
}
4984
]
50-
}
85+
}

src/bin/23.rs

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
use advent_of_code::helpers::{Point, PointDirection, PointGrid};
2+
use parse_display::{Display, FromStr};
3+
4+
#[derive(Debug, Display, FromStr)]
5+
enum Content {
6+
#[display("#")]
7+
Elf,
8+
}
9+
10+
fn parse_input(_input: &str) -> PointGrid<Content> {
11+
let mut grid: PointGrid<Content> = PointGrid::default();
12+
13+
for (y, l) in _input.lines().map(|l| l.chars()).enumerate() {
14+
for (x, c) in l.enumerate() {
15+
if c == '#' {
16+
grid.insert(
17+
Point {
18+
x: x as isize,
19+
y: y as isize,
20+
},
21+
Content::Elf,
22+
);
23+
}
24+
}
25+
}
26+
27+
grid
28+
}
29+
30+
fn get_proposed_moves(
31+
grid: &PointGrid<Content>,
32+
cycle: usize,
33+
) -> (bool, PointGrid<Vec<Point<isize>>>) {
34+
let mut proposed_by: PointGrid<Vec<Point<isize>>> = PointGrid::default();
35+
let mut anyone_moved: bool = false;
36+
let mut directions_order = [
37+
PointDirection::North,
38+
PointDirection::South,
39+
PointDirection::West,
40+
PointDirection::East,
41+
];
42+
directions_order.rotate_left(cycle);
43+
44+
for elf in grid.points.keys() {
45+
// print!("Point {} proposes: ", elf);
46+
if PointDirection::all_with_diagonals()
47+
.all(|d| grid.get(&elf.get_point_in_direction(d, 1)).is_none())
48+
{
49+
// println!("rest.");
50+
proposed_by.insert(*elf, vec![*elf]);
51+
continue;
52+
}
53+
54+
anyone_moved = true;
55+
let mut movable = false;
56+
for d in directions_order.iter() {
57+
match d {
58+
PointDirection::North => {
59+
if [
60+
PointDirection::North,
61+
PointDirection::NorthEast,
62+
PointDirection::NorthWest,
63+
]
64+
.iter()
65+
.all(|d| grid.get(&elf.get_point_in_direction(d, 1)).is_none())
66+
{
67+
let proposed_position =
68+
elf.get_point_in_direction(&PointDirection::North, 1);
69+
if let Some(v) = proposed_by.get(&proposed_position) {
70+
let mut new_list = v.clone();
71+
new_list.push(*elf);
72+
// println!("move to {}, (with {:?})", proposed_position, new_list);
73+
proposed_by.insert(proposed_position, new_list);
74+
} else {
75+
// println!("move to {}", proposed_position);
76+
proposed_by.insert(proposed_position, vec![*elf]);
77+
}
78+
movable = true;
79+
break;
80+
}
81+
}
82+
PointDirection::South => {
83+
if [
84+
PointDirection::South,
85+
PointDirection::SouthEast,
86+
PointDirection::SouthWest,
87+
]
88+
.iter()
89+
.all(|d| grid.get(&elf.get_point_in_direction(d, 1)).is_none())
90+
{
91+
let proposed_position =
92+
elf.get_point_in_direction(&PointDirection::South, 1);
93+
if let Some(v) = proposed_by.get(&proposed_position) {
94+
let mut new_list = v.clone();
95+
new_list.push(*elf);
96+
// println!("move to {}, (with {:?})", proposed_position, new_list);
97+
proposed_by.insert(proposed_position, new_list);
98+
} else {
99+
// println!("move to {}", proposed_position);
100+
proposed_by.insert(proposed_position, vec![*elf]);
101+
}
102+
movable = true;
103+
break;
104+
}
105+
}
106+
PointDirection::West => {
107+
if [
108+
PointDirection::West,
109+
PointDirection::NorthWest,
110+
PointDirection::SouthWest,
111+
]
112+
.iter()
113+
.all(|d| grid.get(&elf.get_point_in_direction(d, 1)).is_none())
114+
{
115+
let proposed_position =
116+
elf.get_point_in_direction(&PointDirection::West, 1);
117+
if let Some(v) = proposed_by.get(&proposed_position) {
118+
let mut new_list = v.clone();
119+
new_list.push(*elf);
120+
// println!("move to {}, (with {:?})", proposed_position, new_list);
121+
proposed_by.insert(proposed_position, new_list);
122+
} else {
123+
// println!("move to {}", proposed_position);
124+
proposed_by.insert(proposed_position, vec![*elf]);
125+
}
126+
movable = true;
127+
break;
128+
}
129+
}
130+
PointDirection::East => {
131+
if [
132+
PointDirection::East,
133+
PointDirection::NorthEast,
134+
PointDirection::SouthEast,
135+
]
136+
.iter()
137+
.all(|d| grid.get(&elf.get_point_in_direction(d, 1)).is_none())
138+
{
139+
let proposed_position =
140+
elf.get_point_in_direction(&PointDirection::East, 1);
141+
if let Some(v) = proposed_by.get(&proposed_position) {
142+
let mut new_list = v.clone();
143+
new_list.push(*elf);
144+
// println!("move to {}, (with {:?})", proposed_position, new_list);
145+
proposed_by.insert(proposed_position, new_list);
146+
} else {
147+
// println!("move to {}", proposed_position);
148+
proposed_by.insert(proposed_position, vec![*elf]);
149+
}
150+
movable = true;
151+
break;
152+
}
153+
}
154+
_ => unimplemented!(),
155+
}
156+
}
157+
158+
if !movable {
159+
// println!("stuck, stay at {}", elf);
160+
proposed_by.insert(*elf, vec![*elf]);
161+
}
162+
}
163+
164+
(anyone_moved, proposed_by)
165+
}
166+
167+
fn do_proposed_move(proposed_list: &PointGrid<Vec<Point<isize>>>) -> PointGrid<Content> {
168+
let mut grid: PointGrid<Content> = PointGrid::default();
169+
170+
for (pos, elves) in proposed_list.points.iter() {
171+
if elves.len() > 1 {
172+
for elf in elves {
173+
grid.insert(*elf, Content::Elf);
174+
}
175+
} else {
176+
grid.insert(*pos, Content::Elf);
177+
}
178+
}
179+
180+
grid
181+
}
182+
183+
pub fn part_one(_input: &str) -> Option<isize> {
184+
let mut grid: PointGrid<Content> = parse_input(_input);
185+
186+
for i in 0..10 {
187+
let (anyone_moved, proposed_list) = get_proposed_moves(&grid, i % 4);
188+
if !anyone_moved {
189+
break;
190+
}
191+
grid = do_proposed_move(&proposed_list);
192+
}
193+
194+
let (min, max) = grid.dimensions();
195+
let tiles = ((max.x + 1) - min.x) * ((max.y + 1) - min.y);
196+
Some(tiles - grid.points.keys().len() as isize)
197+
}
198+
199+
pub fn part_two(_input: &str) -> Option<isize> {
200+
let mut grid: PointGrid<Content> = parse_input(_input);
201+
let mut tracker: isize = 1;
202+
203+
loop {
204+
let (anyone_moved, proposed_list) = get_proposed_moves(&grid, (tracker as usize - 1) % 4);
205+
if !anyone_moved {
206+
break;
207+
}
208+
grid = do_proposed_move(&proposed_list);
209+
tracker += 1;
210+
}
211+
212+
Some(tracker)
213+
}
214+
215+
fn main() {
216+
let input = &advent_of_code::read_file("inputs", 23);
217+
advent_of_code::solve!(1, part_one, input);
218+
advent_of_code::solve!(2, part_two, input);
219+
}
220+
221+
#[cfg(test)]
222+
mod tests {
223+
use super::*;
224+
225+
#[test]
226+
fn test_part_one() {
227+
let input = advent_of_code::read_file("examples", 23);
228+
assert_eq!(part_one(&input), Some(110));
229+
}
230+
231+
#[ignore]
232+
#[test]
233+
fn test_part_two() {
234+
let input = advent_of_code::read_file("examples", 23);
235+
assert_eq!(part_two(&input), Some(20));
236+
}
237+
}

src/examples/23.txt

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

src/examples/23_1.txt

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

src/helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl Point<isize> {
116116
y: self.y - distance,
117117
},
118118
PointDirection::NorthEast => Self {
119-
x: self.x - distance,
119+
x: self.x + distance,
120120
y: self.y - distance,
121121
},
122122
PointDirection::East => Self {

0 commit comments

Comments
 (0)