Skip to content

Commit c27d5a5

Browse files
committed
add day12
1 parent a8766d2 commit c27d5a5

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

2024/day12/.gitignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
input.txt
2+
flamegraph.svg
3+
perf.data*
4+
### Rust
5+
# Generated by Cargo
6+
# will have compiled files and executables
7+
debug/
8+
target/
9+
10+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
11+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
12+
Cargo.lock
13+
14+
# These are backup files generated by rustfmt
15+
**/*.rs.bk
16+
17+
# MSVC Windows builds of rustc generate these, which store debugging information
18+
*.pdb
19+

2024/day12/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "day12"
3+
authors = ["mirsella <[email protected]>"]
4+
version = "0.1.0"
5+
edition = "2021"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
regex = { workspace = true }
11+
itertools = { workspace = true }
12+
pathfinding = { workspace = true }
13+
rayon = { workspace = true }
14+
indexmap = { workspace = true }
15+
hashbrown = { workspace = true }
16+
fix_fn = { workspace = true }

2024/day12/src/main.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
use hashbrown::HashSet;
2+
use itertools::Itertools;
3+
use std::collections::BTreeSet;
4+
// use std::collections::HashSet;
5+
use pathfinding::{
6+
matrix::{directions::DIRECTIONS_4, Matrix},
7+
prelude::bfs_reach,
8+
};
9+
10+
type Regions = HashSet<BTreeSet<(usize, usize)>>;
11+
fn part1(input: &str) -> usize {
12+
let m = Matrix::from_rows(input.lines().map(str::chars)).unwrap();
13+
let mut regions: Regions = Default::default();
14+
for pos in m.keys() {
15+
if regions.iter().any(|r| r.contains(&pos)) {
16+
continue;
17+
}
18+
let region = bfs_reach(pos, |&p| m.neighbours(p, false).filter(|&n| m[n] == m[pos]))
19+
.collect::<BTreeSet<_>>();
20+
regions.insert(region);
21+
}
22+
let mut price = 0;
23+
for region in regions.iter() {
24+
let mut fences = 0;
25+
for &pos in region {
26+
let neighbours = m.neighbours(pos, false).collect_vec();
27+
fences += neighbours.iter().filter(|n| !region.contains(n)).count();
28+
fences += 4 - neighbours.len();
29+
}
30+
price += fences * region.len();
31+
}
32+
price
33+
}
34+
35+
fn part2(input: &str) -> usize {
36+
let m = Matrix::from_rows(input.lines().map(str::chars)).unwrap();
37+
let mut regions: Regions = Default::default();
38+
for pos in m.keys() {
39+
if regions.iter().any(|r| r.contains(&pos)) {
40+
continue;
41+
}
42+
let region = bfs_reach(pos, |&p| m.neighbours(p, false).filter(|&n| m[n] == m[pos]))
43+
.collect::<BTreeSet<_>>();
44+
regions.insert(region);
45+
}
46+
let mut price = 0;
47+
for region in regions.iter() {
48+
let mut corners = 0;
49+
for dir in DIRECTIONS_4 {
50+
let mut sides = HashSet::new();
51+
for pos in region {
52+
let tmp = (pos.0 as isize + dir.0, pos.1 as isize + dir.1);
53+
if !region.contains(&(tmp.0 as usize, tmp.1 as usize)) {
54+
sides.insert(tmp);
55+
}
56+
}
57+
let mut extra_sides = HashSet::new();
58+
for side in &sides {
59+
let mut tmp = (side.0 + dir.1, side.1 + dir.0);
60+
while sides.contains(&tmp) {
61+
extra_sides.insert(tmp);
62+
tmp = (tmp.0 + dir.1, tmp.1 + dir.0);
63+
}
64+
}
65+
corners += sides.len() - extra_sides.len();
66+
}
67+
price += corners * region.len();
68+
}
69+
price
70+
}
71+
72+
fn main() {
73+
let input = include_str!("../input.txt");
74+
println!("Part 1: {}", part1(input));
75+
println!("Part 2: {}", part2(input));
76+
}
77+
78+
#[cfg(test)]
79+
mod tests {
80+
const INPUT: &str = "RRRRIICCFF
81+
RRRRIICCCF
82+
VVRRRCCFFF
83+
VVRCCCJFFF
84+
VVVVCJJCFE
85+
VVIVCCJJEE
86+
VVIIICJJEE
87+
MIIIIIJJEE
88+
MIIISIJEEE
89+
MMMISSJEEE";
90+
#[test]
91+
fn part1() {
92+
assert_eq!(super::part1(INPUT), 1930);
93+
}
94+
#[test]
95+
fn part2() {
96+
assert_eq!(super::part2(INPUT), 1206);
97+
}
98+
#[test]
99+
fn part2_2() {
100+
assert_eq!(
101+
super::part2(
102+
"AAAA
103+
BBCD
104+
BBCC
105+
EEEC"
106+
),
107+
80
108+
);
109+
}
110+
#[test]
111+
fn part2_3() {
112+
assert_eq!(
113+
super::part2(
114+
"EEEEE
115+
EXXXX
116+
EEEEE
117+
EXXXX
118+
EEEEE"
119+
),
120+
236
121+
);
122+
}
123+
124+
#[test]
125+
fn part2_4() {
126+
assert_eq!(
127+
super::part2(
128+
"AAAAAA
129+
AAABBA
130+
AAABBA
131+
ABBAAA
132+
ABBAAA
133+
AAAAAA"
134+
),
135+
368
136+
);
137+
}
138+
}

0 commit comments

Comments
 (0)