Day 12
This commit is contained in:
parent
d0a7ddea55
commit
82aa5ccf03
16
day12/Cargo.lock
generated
Normal file
16
day12/Cargo.lock
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.75"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day12"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
]
|
9
day12/Cargo.toml
Normal file
9
day12/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day12"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.75"
|
1000
day12/input
Normal file
1000
day12/input
Normal file
File diff suppressed because it is too large
Load Diff
363
day12/log
Normal file
363
day12/log
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
Compiling day12 v0.1.0 (/home/max/aoc2023/day12)
|
||||||
|
warning: unused imports: `Deref`, `Index`, `RangeBounds`, `Range`, `borrow::Borrow`
|
||||||
|
--> src/main.rs:1:50
|
||||||
|
|
|
||||||
|
1 | use std::{str::FromStr, slice::SliceIndex, ops::{Index, Deref, RangeBounds, Range, RangeFrom}, borrow::Borrow, io::stdin, collections::Ha...
|
||||||
|
| ^^^^^ ^^^^^ ^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(unused_imports)]` on by default
|
||||||
|
|
||||||
|
warning: unused import: `slice::SliceIndex`
|
||||||
|
--> src/main.rs:1:25
|
||||||
|
|
|
||||||
|
1 | use std::{str::FromStr, slice::SliceIndex, ops::{Index, Deref, RangeBounds, Range, RangeFrom}, borrow::Borrow, io::stdin, collections::Ha...
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: variable does not need to be mutable
|
||||||
|
--> src/main.rs:194:9
|
||||||
|
|
|
||||||
|
194 | let mut rows: Vec<Row> = stdin().lines().map(|l| {
|
||||||
|
| ----^^^^
|
||||||
|
| |
|
||||||
|
| help: remove this `mut`
|
||||||
|
|
|
||||||
|
= note: `#[warn(unused_mut)]` on by default
|
||||||
|
|
||||||
|
warning: methods `enumerate`, `optimize`, and `multiply` are never used
|
||||||
|
--> src/main.rs:25:8
|
||||||
|
|
|
||||||
|
20 | impl Row {
|
||||||
|
| -------- methods in this implementation
|
||||||
|
...
|
||||||
|
25 | fn enumerate<F>(&self, f: &mut F)
|
||||||
|
| ^^^^^^^^^
|
||||||
|
...
|
||||||
|
32 | fn optimize(&mut self) {
|
||||||
|
| ^^^^^^^^
|
||||||
|
...
|
||||||
|
44 | fn multiply(self, n: usize) -> Self {
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(dead_code)]` on by default
|
||||||
|
|
||||||
|
warning: methods `compatible` and `enumerate` are never used
|
||||||
|
--> src/main.rs:96:8
|
||||||
|
|
|
||||||
|
94 | impl <'r> RowView<'r> {
|
||||||
|
| --------------------- methods in this implementation
|
||||||
|
95 |
|
||||||
|
96 | fn compatible(&self, buffer: &[bool]) -> bool {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
...
|
||||||
|
148 | fn enumerate<F>(&self, buf: &mut [bool], window: RangeFrom<usize>, f: &mut F)
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
warning: function `pretty` is never used
|
||||||
|
--> src/main.rs:188:4
|
||||||
|
|
|
||||||
|
188 | fn pretty(row: &[bool]) -> String {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
warning: `day12` (bin "day12") generated 6 warnings (run `cargo fix --bin "day12"` to apply 2 suggestions)
|
||||||
|
Finished release [optimized] target(s) in 0.32s
|
||||||
|
Running `target/release/day12`
|
||||||
|
Counting solutions for RowView { bits: [None, None, None, Some(false), Some(true), Some(true), Some(true)], pattern: [1, 1, 3], freedom: 0 }
|
||||||
|
Descending p=0 consumed=0 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=2 consumed=1 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=4 consumed=2 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=8 consumed=3 freedom=0
|
||||||
|
no blocks remain
|
||||||
|
1 at position 5
|
||||||
|
1 at position 3
|
||||||
|
1 at position 1
|
||||||
|
Counting solutions for RowView { bits: [Some(false), None, None, Some(false), Some(false), None, None, Some(false), Some(false), Some(false), None, Some(true), Some(true), Some(false)], pattern: [1, 1, 3], freedom: 7 }
|
||||||
|
Descending p=0 consumed=0 freedom=7
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 0..1, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=3 consumed=1 freedom=6
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 3..4, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 4..5, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Descending p=7 consumed=2 freedom=4
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 7..10, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 8..11, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Bit cleared in range 9..12, continuing
|
||||||
|
Trying offset 3
|
||||||
|
Descending...
|
||||||
|
Descending p=14 consumed=3 freedom=1
|
||||||
|
no blocks remain
|
||||||
|
1 at position 11
|
||||||
|
Trying offset 4
|
||||||
|
Bit cleared in range 11..14, continuing
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 3
|
||||||
|
Descending...
|
||||||
|
Descending p=8 consumed=2 freedom=3
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 8..11, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 9..12, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 11
|
||||||
|
Trying offset 3
|
||||||
|
Bit cleared in range 11..14, continuing
|
||||||
|
2 at position 7
|
||||||
|
Trying offset 4
|
||||||
|
Bit cleared in range 7..8, continuing
|
||||||
|
Trying offset 5
|
||||||
|
Bit cleared in range 8..9, continuing
|
||||||
|
Trying offset 6
|
||||||
|
Bit cleared in range 9..10, continuing
|
||||||
|
2 at position 2
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Descending p=4 consumed=1 freedom=5
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 4..5, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
2 at position 7
|
||||||
|
Trying offset 3
|
||||||
|
Bit cleared in range 7..8, continuing
|
||||||
|
Trying offset 4
|
||||||
|
Bit cleared in range 8..9, continuing
|
||||||
|
Trying offset 5
|
||||||
|
Bit cleared in range 9..10, continuing
|
||||||
|
4 at position 3
|
||||||
|
Trying offset 3
|
||||||
|
Bit cleared in range 3..4, continuing
|
||||||
|
Trying offset 4
|
||||||
|
Bit cleared in range 4..5, continuing
|
||||||
|
Trying offset 5
|
||||||
|
Descending...
|
||||||
|
Descending p=7 consumed=1 freedom=2
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 7..8, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 8..9, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Bit cleared in range 9..10, continuing
|
||||||
|
4 at position 6
|
||||||
|
Trying offset 6
|
||||||
|
Descending...
|
||||||
|
Descending p=8 consumed=1 freedom=1
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 8..9, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 9..10, continuing
|
||||||
|
4 at position 7
|
||||||
|
Trying offset 7
|
||||||
|
Bit cleared in range 7..8, continuing
|
||||||
|
Counting solutions for RowView { bits: [None, Some(true), None, Some(true), None, Some(true), None, Some(true), None, Some(true), None, Some(true), None, Some(true), None], pattern: [1, 3, 1, 6], freedom: 1 }
|
||||||
|
Descending p=0 consumed=0 freedom=1
|
||||||
|
Trying offset 0
|
||||||
|
found blocker at 1
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=3 consumed=1 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=7 consumed=2 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=9 consumed=3 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=16 consumed=4 freedom=0
|
||||||
|
no blocks remain
|
||||||
|
1 at position 10
|
||||||
|
1 at position 8
|
||||||
|
1 at position 4
|
||||||
|
1 at position 2
|
||||||
|
Counting solutions for RowView { bits: [None, None, None, None, Some(false), Some(true), Some(false), Some(false), Some(false), Some(true), Some(false), Some(false), Some(false)], pattern: [4, 1, 1], freedom: 5 }
|
||||||
|
Descending p=0 consumed=0 freedom=5
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=5 consumed=1 freedom=5
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=7 consumed=2 freedom=5
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 7..8, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 8..9, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Descending p=11 consumed=3 freedom=3
|
||||||
|
no blocks remain
|
||||||
|
1 at position 10
|
||||||
|
Trying offset 3
|
||||||
|
Bit 9 set, giving up
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 1
|
||||||
|
Bit 5 set, giving up
|
||||||
|
1 at position 1
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 1..5, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Bit cleared in range 2..6, continuing
|
||||||
|
Trying offset 3
|
||||||
|
Bit cleared in range 3..7, continuing
|
||||||
|
Trying offset 4
|
||||||
|
Bit cleared in range 4..8, continuing
|
||||||
|
Trying offset 5
|
||||||
|
Bit cleared in range 5..9, continuing
|
||||||
|
Counting solutions for RowView { bits: [None, None, None, None, Some(false), Some(true), Some(true), Some(true), Some(true), Some(true), Some(true), Some(false), Some(false), Some(true), Some(true), Some(true), Some(true), Some(true), Some(false)], pattern: [1, 6, 5], freedom: 5 }
|
||||||
|
Descending p=0 consumed=0 freedom=5
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=2 consumed=1 freedom=5
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 2..8, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 3..9, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Bit cleared in range 4..10, continuing
|
||||||
|
Trying offset 3
|
||||||
|
Descending...
|
||||||
|
Descending p=12 consumed=2 freedom=2
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 12..17, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=19 consumed=3 freedom=1
|
||||||
|
no blocks remain
|
||||||
|
1 at position 14
|
||||||
|
Trying offset 2
|
||||||
|
Bit 13 set, giving up
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 4
|
||||||
|
Bit 5 set, giving up
|
||||||
|
1 at position 1
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=3 consumed=1 freedom=4
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 3..9, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Bit cleared in range 4..10, continuing
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 3
|
||||||
|
Bit 5 set, giving up
|
||||||
|
2 at position 2
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Descending p=4 consumed=1 freedom=3
|
||||||
|
Trying offset 0
|
||||||
|
Bit cleared in range 4..10, continuing
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 2
|
||||||
|
Bit 5 set, giving up
|
||||||
|
3 at position 3
|
||||||
|
Trying offset 3
|
||||||
|
Descending...
|
||||||
|
Descending p=5 consumed=1 freedom=2
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 6
|
||||||
|
Trying offset 1
|
||||||
|
Bit 5 set, giving up
|
||||||
|
4 at position 4
|
||||||
|
Trying offset 4
|
||||||
|
Bit cleared in range 4..5, continuing
|
||||||
|
Trying offset 5
|
||||||
|
found blocker at 6
|
||||||
|
Counting solutions for RowView { bits: [None, Some(true), Some(true), Some(true), None, None, None, None, None, None, None, None], pattern: [3, 2, 1], freedom: 4 }
|
||||||
|
Descending p=0 consumed=0 freedom=4
|
||||||
|
Trying offset 0
|
||||||
|
found blocker at 3
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=5 consumed=1 freedom=3
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=8 consumed=2 freedom=3
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Descending p=10 consumed=3 freedom=3
|
||||||
|
no blocks remain
|
||||||
|
1 at position 9
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=11 consumed=3 freedom=2
|
||||||
|
no blocks remain
|
||||||
|
2 at position 10
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Descending p=12 consumed=3 freedom=1
|
||||||
|
no blocks remain
|
||||||
|
3 at position 11
|
||||||
|
Trying offset 3
|
||||||
|
Descending...
|
||||||
|
Descending p=13 consumed=3 freedom=0
|
||||||
|
no blocks remain
|
||||||
|
4 at position 12
|
||||||
|
4 at position 6
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Descending p=9 consumed=2 freedom=2
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 10
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
2 at position 11
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
3 at position 12
|
||||||
|
7 at position 7
|
||||||
|
Trying offset 2
|
||||||
|
Descending...
|
||||||
|
Descending p=10 consumed=2 freedom=1
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 11
|
||||||
|
Trying offset 1
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
2 at position 12
|
||||||
|
9 at position 8
|
||||||
|
Trying offset 3
|
||||||
|
Descending...
|
||||||
|
Descending p=11 consumed=2 freedom=0
|
||||||
|
Trying offset 0
|
||||||
|
Descending...
|
||||||
|
Cache hit
|
||||||
|
1 at position 12
|
||||||
|
10 at position 9
|
||||||
|
10 at position 2
|
||||||
|
Trying offset 2
|
||||||
|
Bit 1 set, giving up
|
||||||
|
Part 1: Total: 21
|
242
day12/src/main.rs
Normal file
242
day12/src/main.rs
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
use std::{str::FromStr, ops::RangeFrom, io::stdin, collections::HashMap, fmt::Display};
|
||||||
|
use anyhow::{Result, Error, anyhow};
|
||||||
|
|
||||||
|
#[derive(Debug,Clone,PartialEq,Eq)]
|
||||||
|
struct Row {
|
||||||
|
bits: Vec<Option<bool>>,
|
||||||
|
pattern: Vec<usize>,
|
||||||
|
freedom: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RowView<'r> {
|
||||||
|
bits: &'r [Option<bool>],
|
||||||
|
pattern: &'r [usize],
|
||||||
|
freedom: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cache = HashMap<(usize,usize), usize>;
|
||||||
|
|
||||||
|
impl Row {
|
||||||
|
fn view(&self) -> RowView<'_> {
|
||||||
|
RowView { bits: &self.bits, pattern: &self.pattern, freedom: self.freedom }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate<F>(&self, f: &mut F)
|
||||||
|
where F: FnMut(&[bool])
|
||||||
|
{
|
||||||
|
let mut buf = vec![false; self.bits.len()];
|
||||||
|
self.view().enumerate(&mut buf, 0.., f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn optimize(&mut self) {
|
||||||
|
let mut offset = 0;
|
||||||
|
for &block in &self.pattern {
|
||||||
|
if block > self.freedom {
|
||||||
|
for cell in &mut self.bits[offset + self.freedom .. offset + block] {
|
||||||
|
*cell = Some(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += block + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multiply(self, n: usize) -> Self {
|
||||||
|
let mut bits = self.bits;
|
||||||
|
bits.push(None);
|
||||||
|
bits = bits.repeat(n);
|
||||||
|
bits.pop();
|
||||||
|
|
||||||
|
let pattern = self.pattern.repeat(n);
|
||||||
|
|
||||||
|
Row { bits, pattern, freedom: self.freedom * n}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(&self) -> usize {
|
||||||
|
self.view().count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exhaustive_count(&self) -> usize {
|
||||||
|
self.view().exhaustive_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Row {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let (bits, nums) = s.split_once(' ')
|
||||||
|
.ok_or_else(|| anyhow!("Bad line {s}"))?;
|
||||||
|
|
||||||
|
let bits = bits.chars()
|
||||||
|
.map(|c| match c {
|
||||||
|
'.' => Ok(Some(false)),
|
||||||
|
'#' => Ok(Some(true)),
|
||||||
|
'?' => Ok(None),
|
||||||
|
oth => Err(anyhow!("Invalid character {oth}")),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
let pattern = nums.split(',')
|
||||||
|
.map(str::parse)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let size = (pattern.iter().sum::<usize>() + pattern.len())
|
||||||
|
.saturating_sub(1);
|
||||||
|
|
||||||
|
let freedom = bits.len()
|
||||||
|
.checked_sub(size).ok_or_else(|| anyhow!("Unsolvable row {s}"))?;
|
||||||
|
|
||||||
|
Ok(Self { bits, pattern, freedom })
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Row {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for bit in &self.bits {
|
||||||
|
write!(f, "{}", match bit {
|
||||||
|
None => '?',
|
||||||
|
Some(false) => '.',
|
||||||
|
Some(true) => '#',
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
write!(f, "{:?}", &self.pattern)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'r> RowView<'r> {
|
||||||
|
|
||||||
|
fn exhaustive_count(&self) -> usize {
|
||||||
|
let mut c = 0;
|
||||||
|
let mut buf = vec![false; self.bits.len()];
|
||||||
|
self.enumerate(&mut buf, 0.., &mut |_| c += 1);
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(&self) -> usize {
|
||||||
|
self.dfs(0, 0, self.freedom, &mut HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dfs(&self, position: usize, consumed: usize, freedom: usize, cache: &mut Cache) -> usize {
|
||||||
|
//eprintln!("DFS enter position={position} consumed={consumed} freedom={freedom}");
|
||||||
|
fn cached_dfs(this: &RowView, position: usize, consumed: usize, freedom: usize, cache: &mut Cache) -> usize {
|
||||||
|
if let Some(&solutions) = cache.get(&(consumed, position)) {
|
||||||
|
//eprintln!("Cache hit for position={position} consumed={consumed} freedom={freedom} = {solutions}");
|
||||||
|
return solutions
|
||||||
|
}
|
||||||
|
|
||||||
|
let solutions = this.dfs(position, consumed, freedom, cache);
|
||||||
|
cache.insert((consumed, position), solutions);
|
||||||
|
solutions
|
||||||
|
}
|
||||||
|
|
||||||
|
if consumed == self.pattern.len() {
|
||||||
|
if position <= self.bits.len() && self.bits[position..].iter().any(|b| b == &Some(true)) {
|
||||||
|
//eprintln!("Terminal conflict");
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
//eprintln!("Valid solution");
|
||||||
|
1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let current = self.pattern[consumed];
|
||||||
|
let mut solutions = 0;
|
||||||
|
for offset in 0..=freedom {
|
||||||
|
// Uncovered bit in prefix space, no point in continuing
|
||||||
|
if offset > 0 && self.bits[position+offset-1] == Some(true) { break }
|
||||||
|
|
||||||
|
// Block collides with empty cell, try next offset
|
||||||
|
if self.bits[position+offset..][..current].iter().any(|b| b == &Some(false)) { continue }
|
||||||
|
|
||||||
|
// Block is not last and cell following block is not empty
|
||||||
|
if position+offset+current < self.bits.len() && self.bits[position+offset+current] == Some(true) { continue }
|
||||||
|
|
||||||
|
solutions += cached_dfs(&self, position+offset+current+1, consumed+1, freedom - offset, cache);
|
||||||
|
}
|
||||||
|
//eprintln!("DFS leave position={position} consumed={consumed} freedom={freedom} -> {solutions}");
|
||||||
|
solutions
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate<F>(&self, buf: &mut [bool], window: RangeFrom<usize>, f: &mut F)
|
||||||
|
where F: FnMut(&[bool])
|
||||||
|
{
|
||||||
|
if let Some((&h, rest)) = self.pattern.split_first() {
|
||||||
|
for offset in 0..=self.freedom {
|
||||||
|
|
||||||
|
if self.bits[..offset].iter().any(|b| b == &Some(true)) { continue }
|
||||||
|
for b in &mut buf[window.clone()][..offset] {
|
||||||
|
*b = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.bits[offset..][..h].iter().any(|b| b == &Some(false)) { continue }
|
||||||
|
for b in &mut buf[window.clone()][offset..][..h] {
|
||||||
|
*b = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if rest.len() == 0 {
|
||||||
|
RowView { pattern: rest, bits: &self.bits[offset+h..], freedom: self.freedom - offset}
|
||||||
|
.enumerate(buf, window.start + offset + h .., f);
|
||||||
|
} else {
|
||||||
|
if self.bits[offset + h] == Some(true) { continue; }
|
||||||
|
buf[window.clone()][offset + h] = false;
|
||||||
|
RowView { pattern: rest, bits: &self.bits[offset+h+1..], freedom: self.freedom - offset }
|
||||||
|
.enumerate(buf, window.start + offset + h + 1 .., f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for b in buf[window.clone()].iter_mut() { *b = false }
|
||||||
|
if self.compatible(&buf[window]) {
|
||||||
|
f(&buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn pretty(row: &[bool]) -> String {
|
||||||
|
row.iter().map(|&f| if f {'#'} else {'.'}).collect()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_optimization() {
|
||||||
|
let row: Row = "#??##????#??? 8,1,1".parse().unwrap();
|
||||||
|
let row2 = row.clone();
|
||||||
|
assert_eq!(row.count(), row2.count());
|
||||||
|
}
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
|
||||||
|
let rows: Vec<Row> = stdin().lines().map(|l| {
|
||||||
|
l.unwrap().parse().unwrap()
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut rows = rows.clone();
|
||||||
|
|
||||||
|
for row in &mut rows {
|
||||||
|
row.optimize();
|
||||||
|
}
|
||||||
|
|
||||||
|
let total: usize = rows.iter().map(Row::count).sum();
|
||||||
|
println!("Part 1: Total: {total}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let mut rows: Vec<Row> = rows.into_iter().map(|r| r.multiply(5)).collect();
|
||||||
|
for r in &mut rows { r.optimize() }
|
||||||
|
|
||||||
|
let total: usize = rows.iter().map(Row::count).sum();
|
||||||
|
println!("Part 2: Total: {total}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
6
day12/test
Normal file
6
day12/test
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
???.### 1,1,3
|
||||||
|
.??..??...?##. 1,1,3
|
||||||
|
?#?#?#?#?#?#?#? 1,3,1,6
|
||||||
|
????.#...#... 4,1,1
|
||||||
|
????.######..#####. 1,6,5
|
||||||
|
?###???????? 3,2,1
|
Loading…
Reference in New Issue
Block a user