Skip to content

Commit 4b1a0c7

Browse files
committed
day 17 rust nicer solution
- uses const generics
1 parent 1deec4d commit 4b1a0c7

File tree

2 files changed

+79
-127
lines changed

2 files changed

+79
-127
lines changed

src/days/day17.rs

Lines changed: 79 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,85 @@
11
use anyhow::Result;
2+
use hashbrown::HashMap;
3+
use itertools::Itertools;
24
use libaoc::{aoc, AocResult, Timer};
3-
use std::collections::BTreeMap;
5+
use std::convert::TryInto;
6+
7+
type Coords<const SIZE: usize> = [i32; SIZE];
8+
9+
fn get_neighbors<const SIZE: usize>(
10+
location: Coords<SIZE>,
11+
data: &HashMap<Coords<SIZE>, bool>,
12+
) -> i32 {
13+
let offsets = [[-1i32, 0, 1]; SIZE];
414

5-
fn get_neighbors_3(coords: (i32, i32, i32), data: &BTreeMap<(i32, i32, i32), bool>) -> i32 {
615
let mut count = 0;
7-
for x in (coords.0 - 1)..=(coords.0 + 1) {
8-
for y in (coords.1 - 1)..=(coords.1 + 1) {
9-
for z in (coords.2 - 1)..=(coords.2 + 1) {
10-
if ((x, y, z) != coords) && *data.get(&(x, y, z)).unwrap_or(&false) {
11-
count += 1;
12-
}
13-
}
16+
for current in offsets.iter().multi_cartesian_product() {
17+
let coords: Vec<_> = current.iter().map(|x| **x).collect();
18+
let coords: Coords<SIZE> = coords.try_into().unwrap();
19+
20+
let coords: Vec<_> = coords.iter().zip(&location).map(|(a, b)| a + b).collect();
21+
let coords: Coords<SIZE> = coords.try_into().unwrap();
22+
23+
if location != coords && *data.get(&coords).unwrap_or(&false) {
24+
count += 1;
1425
}
1526
}
1627

1728
count
1829
}
1930

20-
fn get_neighbors_4(coords: (i32, i32, i32, i32), data: &BTreeMap<(i32, i32, i32, i32), bool>) -> i32 {
21-
let mut count = 0;
22-
for x in (coords.0 - 1)..=(coords.0 + 1) {
23-
for y in (coords.1 - 1)..=(coords.1 + 1) {
24-
for z in (coords.2 - 1)..=(coords.2 + 1) {
25-
for w in (coords.3 - 1)..=(coords.3 + 1) {
26-
if ((x, y, z, w) != coords) && *data.get(&(x, y, z, w)).unwrap_or(&false) {
27-
count += 1;
28-
}
31+
fn game<const SIZE: usize>(mut data: HashMap<[i32; SIZE], bool>, width: i32, height: i32) -> u32 {
32+
let mut min_pos = [0; SIZE];
33+
let mut size = [1; SIZE];
34+
size[0] = width;
35+
size[1] = height;
36+
37+
let mut new = HashMap::new();
38+
for _ in 0..6 {
39+
for i in min_pos.iter_mut() {
40+
*i -= 1;
41+
}
42+
43+
for i in size.iter_mut() {
44+
*i += 1;
45+
}
46+
47+
let iterators: Vec<Vec<_>> = min_pos
48+
.iter()
49+
.zip(&size)
50+
.map(|(&a, &b)| (a..b).into_iter().collect())
51+
.collect();
52+
for coords in iterators.iter().multi_cartesian_product() {
53+
let coords: Vec<_> = coords.iter().map(|x| **x).collect();
54+
let coords: Coords<SIZE> = coords.try_into().unwrap();
55+
56+
let current_state = *data.get(&coords).unwrap_or(&false);
57+
let neighbors = get_neighbors(coords, &data);
58+
let new_state = if current_state {
59+
if neighbors == 2 || neighbors == 3 {
60+
true
61+
} else {
62+
false
63+
}
64+
} else {
65+
if neighbors == 3 {
66+
true
67+
} else {
68+
false
2969
}
30-
}
70+
};
71+
72+
new.insert(coords, new_state);
73+
}
74+
75+
(data, new) = (new, data);
76+
new.clear();
77+
}
78+
79+
let mut count = 0;
80+
for &value in data.values() {
81+
if value {
82+
count += 1;
3183
}
3284
}
3385

@@ -51,122 +103,23 @@ pub fn solve(timer: &mut Timer, input: &str) -> Result<AocResult> {
51103
.collect();
52104
timer.lap("Parse");
53105

54-
let mut data_3 = BTreeMap::new();
55-
let mut data_4 = BTreeMap::new();
106+
let mut data_3 = HashMap::new();
107+
let mut data_4 = HashMap::new();
56108
for (y, row) in input.iter().enumerate() {
57109
for (x, &item) in row.iter().enumerate() {
58-
data_3.insert((x as i32, y as i32, 0), item);
59-
data_4.insert((x as i32, y as i32, 0, 0), item);
110+
data_3.insert([x as i32, y as i32, 0], item);
111+
data_4.insert([x as i32, y as i32, 0, 0], item);
60112
}
61113
}
62114
timer.lap("Construct maps");
63115

64-
let mut min_pos = (0, 0, 0);
65-
let mut size = (input[0].len() as i32, input.len() as i32, 1);
66-
67-
for _ in 0..6 {
68-
let mut new = BTreeMap::new();
69-
70-
min_pos.0 -= 1;
71-
min_pos.1 -= 1;
72-
min_pos.2 -= 1;
73-
74-
size.0 += 1;
75-
size.1 += 1;
76-
size.2 += 1;
77-
78-
for x in min_pos.0..size.0 {
79-
for y in min_pos.1..size.1 {
80-
for z in min_pos.2..size.2 {
81-
let coords = (x, y, z);
82-
let current_state = *data_3.get(&coords).unwrap_or(&false);
83-
let neighbors = get_neighbors_3(coords, &data_3);
84-
let new_state = if current_state {
85-
if neighbors == 2 || neighbors == 3 {
86-
true
87-
} else {
88-
false
89-
}
90-
} else {
91-
if neighbors == 3 {
92-
true
93-
} else {
94-
false
95-
}
96-
};
97-
98-
new.insert(coords, new_state);
99-
}
100-
}
101-
}
102-
103-
data_3 = new;
104-
}
105-
106-
let mut count = 0;
107-
for &value in data_3.values() {
108-
if value {
109-
count += 1;
110-
}
111-
}
112-
let part1 = count;
116+
let width = input[0].len() as i32;
117+
let height = input.len() as i32;
113118

119+
let part1 = game(data_3, width, height);
114120
timer.lap("Part 1");
115121

116-
117-
let mut min_pos = (0, 0, 0, 0);
118-
let mut size = (input[0].len() as i32, input.len() as i32, 1, 1);
119-
120-
for _ in 0..6 {
121-
let mut new = BTreeMap::new();
122-
123-
min_pos.0 -= 1;
124-
min_pos.1 -= 1;
125-
min_pos.2 -= 1;
126-
min_pos.3 -= 1;
127-
128-
size.0 += 1;
129-
size.1 += 1;
130-
size.2 += 1;
131-
size.3 += 1;
132-
133-
for x in min_pos.0..size.0 {
134-
for y in min_pos.1..size.1 {
135-
for z in min_pos.2..size.2 {
136-
for w in min_pos.3..size.3 {
137-
let coords = (x, y, z, w);
138-
let current_state = *data_4.get(&coords).unwrap_or(&false);
139-
let neighbors = get_neighbors_4(coords, &data_4);
140-
let new_state = if current_state {
141-
if neighbors == 2 || neighbors == 3 {
142-
true
143-
} else {
144-
false
145-
}
146-
} else {
147-
if neighbors == 3 {
148-
true
149-
} else {
150-
false
151-
}
152-
};
153-
154-
new.insert(coords, new_state);
155-
}
156-
}
157-
}
158-
}
159-
160-
data_4 = new;
161-
}
162-
163-
let mut count = 0;
164-
for &value in data_4.values() {
165-
if value {
166-
count += 1;
167-
}
168-
}
169-
let part2 = count;
122+
let part2 = game(data_4, width, height);
170123
timer.lap("Part 2");
171124

172125
Ok(AocResult::new(part1, part2))

src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#![feature(str_split_once)]
33
#![feature(min_const_generics)]
44
#![feature(destructuring_assignment)]
5-
#![feature(const_in_array_repeat_expressions)]
65

76
use anyhow::{anyhow, Result};
87
use clap::{App, Arg, ArgMatches};

0 commit comments

Comments
 (0)