Skip to content

Commit e9578a2

Browse files
committed
CQ problem 15
1 parent 79d681f commit e9578a2

File tree

5 files changed

+96
-2
lines changed

5 files changed

+96
-2
lines changed

codingquest_clp_solutions/input_data/.keep

Whitespace-only changes.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
0 0 2 3 0 1 1 0
2+
1 0 3 1 0 0 0 0
3+
4 0 1 0 0 0 8 6
4+
0 0 0 0 0 7 0 0
5+
2 0 0 0 0 0 0 0
6+
6 4 4 0 0 1 0 0
7+
0 0 0 0 0 0 0 0
8+
5 5 3 0 0 0 0 0

codingquest_clp_solutions/src/helpers.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ use std::fs;
22
use std::path::PathBuf;
33

44
pub fn get_problem_input_data(problem: u32) -> crate::Result<String> {
5+
get_problem_data(problem, "problem")
6+
}
7+
8+
pub fn get_problem_example_data(problem: u32) -> crate::Result<String> {
9+
get_problem_data(problem, "example")
10+
}
11+
12+
fn get_problem_data(problem: u32, prefix: &str) -> crate::Result<String> {
513
Ok(fs::read_to_string(
6-
[env!("CARGO_MANIFEST_DIR"), "input_data", &format!("problem_{problem}.txt")]
14+
[env!("CARGO_MANIFEST_DIR"), "input_data", &format!("{prefix}_{problem}.txt")]
715
.iter()
816
.collect::<PathBuf>(),
917
)?)

codingquest_clp_solutions/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use codingquest_clp::build_solvers;
77
pub mod helpers;
88
pub mod problem_13;
99
pub mod problem_14;
10+
pub mod problem_15;
1011

1112
pub type Error = codingquest_clp::Error;
1213
pub type Result<T> = codingquest_clp::Result<T>;
1314

1415
build_solvers! {
15-
[13, 14]
16+
[13, 14, 15]
1617
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::collections::{HashMap, HashSet, VecDeque};
2+
3+
use codingquest_clp::aoclp::positioning::pt::{matrix_to_map, Pt};
4+
use codingquest_clp::solvers_impl::input::get_input;
5+
use itertools::Itertools;
6+
7+
use crate::helpers::get_problem_input_data;
8+
9+
pub fn solve() -> u64 {
10+
let bodies: CelestialBodies = sensor_data().into();
11+
bodies.avg_mass()
12+
}
13+
14+
fn sensor_data() -> Vec<Vec<u64>> {
15+
get_input(get_problem_input_data(15).unwrap())
16+
.unwrap()
17+
.safe_into_many_vecs()
18+
}
19+
20+
struct CelestialBody(HashMap<Pt, u64>);
21+
22+
impl CelestialBody {
23+
pub fn mass(&self) -> u64 {
24+
self.0.values().sum()
25+
}
26+
}
27+
28+
impl From<HashMap<Pt, u64>> for CelestialBody {
29+
fn from(value: HashMap<Pt, u64>) -> Self {
30+
Self(value)
31+
}
32+
}
33+
34+
struct CelestialBodies(Vec<CelestialBody>);
35+
36+
impl CelestialBodies {
37+
pub fn avg_mass(&self) -> u64 {
38+
self.0.iter().map(CelestialBody::mass).sum::<u64>() / (self.0.len() as u64)
39+
}
40+
41+
fn body(start: Pt, data: &HashMap<Pt, u64>, cache: &mut HashSet<Pt>) -> CelestialBody {
42+
let mut pieces = HashMap::new();
43+
let mut stack = VecDeque::new();
44+
pieces.insert(start, data[&start]);
45+
stack.push_back(start);
46+
while let Some(pt) = stack.pop_front() {
47+
let neighbours = pt
48+
.four_neighbours()
49+
.filter(|neighbour| !cache.contains(neighbour))
50+
.filter(|neighbour| !pieces.contains_key(neighbour))
51+
.filter(|neighbour| data.get(neighbour).is_some_and(|&data| data != 0))
52+
.collect_vec();
53+
pieces.extend(neighbours.iter().map(|pt| (*pt, data[pt])));
54+
stack.extend(neighbours.iter().copied());
55+
cache.extend(neighbours);
56+
}
57+
58+
pieces.into()
59+
}
60+
}
61+
62+
impl From<Vec<Vec<u64>>> for CelestialBodies {
63+
fn from(value: Vec<Vec<u64>>) -> Self {
64+
let data = matrix_to_map(value);
65+
let (bodies, _) =
66+
data.iter()
67+
.fold((Vec::new(), HashSet::new()), |(mut bodies, mut cache), (pt, d)| {
68+
if !cache.contains(pt) && *d != 0 {
69+
let body = Self::body(*pt, &data, &mut cache);
70+
bodies.push(body);
71+
}
72+
(bodies, cache)
73+
});
74+
75+
Self(bodies)
76+
}
77+
}

0 commit comments

Comments
 (0)