Skip to content

Commit cff3bc7

Browse files
committed
add day12
1 parent 374a43b commit cff3bc7

File tree

5 files changed

+137
-1
lines changed

5 files changed

+137
-1
lines changed

2023/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ members = [
1313
"day9",
1414
"day10",
1515
"day11",
16-
# "day12",
16+
"day12",
1717
# "day13",
1818
# "day14",
1919
# "day15",

2023/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+

2023/day12/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "day12"
3+
authors = ["mirsella <mirsella@protonmail.com>"]
4+
version = "0.1.0"
5+
edition = "2021"
6+

2023/day12/build.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::fs::File;
2+
use std::io::{self, Read};
3+
use std::path::PathBuf;
4+
use std::{env, fs};
5+
6+
fn replace_in_file(file_path: &PathBuf, old: &str, new: &str) -> io::Result<()> {
7+
let mut contents = String::new();
8+
File::open(file_path)?.read_to_string(&mut contents)?;
9+
let new_contents = contents.replace(old, new);
10+
if contents != new_contents {
11+
println!("Updating {}", file_path.display());
12+
fs::write(file_path, new_contents)?;
13+
}
14+
Ok(())
15+
}
16+
17+
fn main() -> io::Result<()> {
18+
let pkg_name = env::var("CARGO_PKG_NAME").unwrap();
19+
replace_in_file(
20+
&"../Cargo.toml".into(),
21+
&format!("# \"{pkg_name}\""),
22+
&format!("\"{pkg_name}\""),
23+
)?;
24+
25+
replace_in_file(&"./Cargo.toml".into(), "\n[workspace]", "")?;
26+
27+
Ok(())
28+
}

2023/day12/src/main.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use std::iter;
2+
3+
fn find_all_permutations(pattern: &str, counts: impl Iterator<Item = usize>) -> usize {
4+
let mut bytes = vec![b'.'];
5+
bytes.extend(pattern.trim_end_matches('.').as_bytes());
6+
let pattern = bytes;
7+
let mut vec = vec![0; pattern.len() + 1];
8+
vec[0] = 1;
9+
10+
for (i, _) in pattern.iter().take_while(|&&c| c != b'#').enumerate() {
11+
vec[i + 1] = 1;
12+
}
13+
14+
for count in counts {
15+
let mut nvec = vec![0; pattern.len() + 1];
16+
let mut chunk = 0;
17+
18+
for (i, &c) in pattern.iter().enumerate() {
19+
match c == b'.' {
20+
true => chunk = 0,
21+
false => chunk += 1,
22+
}
23+
if c != b'#' {
24+
nvec[i + 1] += nvec[i];
25+
}
26+
if chunk >= count && pattern[i - count] != b'#' {
27+
nvec[i + 1] += vec[i - count];
28+
}
29+
}
30+
vec = nvec;
31+
}
32+
vec.last().copied().unwrap()
33+
}
34+
35+
fn part1(input: &str) -> usize {
36+
input
37+
.lines()
38+
.map(|l| {
39+
let (pattern, count) = l.split_once(' ').unwrap();
40+
let counts = count.split(',').map(|c| c.parse().unwrap());
41+
find_all_permutations(pattern, counts)
42+
})
43+
.sum()
44+
}
45+
fn part2(input: &str) -> usize {
46+
input
47+
.lines()
48+
.map(|l| {
49+
let (pattern, count) = l.split_once(' ').unwrap();
50+
let counts: Vec<usize> = count.split(',').map(|c| c.parse().unwrap()).collect();
51+
let unfolded_pattern = (0..4)
52+
.map(|_| pattern.to_string() + "?")
53+
.chain(iter::once(pattern.to_string()))
54+
.collect::<String>();
55+
let unfolded_counts = counts.iter().copied().cycle().take(5 * counts.len());
56+
find_all_permutations(&unfolded_pattern, unfolded_counts)
57+
})
58+
.sum()
59+
}
60+
fn main() {
61+
let input = include_str!("../input.txt");
62+
println!("Part 1: {}", part1(input));
63+
println!("Part 2: {}", part2(input));
64+
}
65+
66+
#[cfg(test)]
67+
mod tests {
68+
const INPUT: &str = "???.### 1,1,3
69+
.??..??...?##. 1,1,3
70+
?#?#?#?#?#?#?#? 1,3,1,6
71+
????.#...#... 4,1,1
72+
????.######..#####. 1,6,5
73+
?###???????? 3,2,1";
74+
75+
#[test]
76+
fn part1() {
77+
assert_eq!(super::part1(INPUT), 21);
78+
}
79+
#[test]
80+
fn part2() {
81+
assert_eq!(super::part2(INPUT), 525152);
82+
}
83+
}

0 commit comments

Comments
 (0)