make p2 linear time

This commit is contained in:
kageru 2023-12-13 12:30:51 +01:00
parent 8e36759477
commit 1338681cf4

View File

@ -12,13 +12,23 @@ fn parse_input(raw: &str) -> Parsed {
.collect()
}
fn find_reflection(block: &[I], blacklist: Option<usize>) -> Option<usize> {
fn find_reflection<const DEVIATIONS: u32>(block: &[I]) -> Option<usize> {
'outer: for i in 0..block.len() - 1 {
let mut offset = 0;
let mut deviations = DEVIATIONS;
loop {
match try { (block.get(i.checked_sub(offset)?)?, block.get(i + 1 + offset)?) } {
None if Some(i) != blacklist => return Some(i + 1),
Some((a, b)) if a == b => offset += 1,
match try { block.get(i.checked_sub(offset)?)? ^ block.get(i + 1 + offset)? } {
None if deviations == 0 => return Some(i + 1),
Some(0) => offset += 1,
Some(diff) => {
let diff = diff.count_ones();
if diff > deviations {
continue 'outer;
} else {
offset += 1;
deviations -= diff;
}
}
_ => continue 'outer,
}
}
@ -26,13 +36,6 @@ fn find_reflection(block: &[I], blacklist: Option<usize>) -> Option<usize> {
None
}
fn part1(blocks: &Parsed) -> usize {
blocks
.iter()
.map(|block| find_reflection(block, None).map(|n| n * 100).or_else(|| find_reflection(&transpose(block), None)).unwrap())
.sum()
}
fn transpose(orig: &[I]) -> Vec<I> {
let max = orig.iter().max().unwrap();
let len = (I::BITS - max.leading_zeros()) as usize;
@ -47,31 +50,17 @@ fn transpose(orig: &[I]) -> Vec<I> {
out
}
fn part1(blocks: &Parsed) -> usize {
blocks
.iter()
.map(|block| find_reflection::<0>(block).map(|n| n * 100).or_else(|| find_reflection::<0>(&transpose(block))).unwrap())
.sum()
}
fn part2(blocks: &Parsed) -> usize {
blocks
.iter()
.map(|block| {
let mut block = block.to_owned();
let mut transposed = transpose(&block);
let p1 = find_reflection(&block, None).map(|n| n - 1);
let p1_transposed = find_reflection(&transposed, None).map(|n| n - 1);
let max = block.iter().max().unwrap();
let len = (I::BITS - max.leading_zeros()) as usize;
for i in 0..block.len() {
for j in 0..len {
block[i] ^= 1 << j;
transposed[j] ^= 1 << i;
if let Some(reflection) =
find_reflection(&block, p1).map(|n| n * 100).or_else(|| find_reflection(&transposed, p1_transposed))
{
return reflection;
}
block[i] ^= 1 << j;
transposed[j] ^= 1 << i;
}
}
unreachable!()
})
.map(|block| find_reflection::<1>(&block).map(|n| n * 100).or_else(|| find_reflection::<1>(&transpose(&block))).unwrap())
.sum()
}
@ -91,15 +80,35 @@ boilerplate! {
##......#
..#.##.#.
..##..##.
#.#.##.#."
#.#.##.#.",
TEST_INPUT_475 == "\
#..##....
.#.##....
##....##.
#.#.#.##.
.####.##.
###..#..#
#.#.#.##.
.#.#.####
..#.#.##.
.##..####
#####.##.
.#.#.####
.#...####
.#.#.####
.#.#.####
#####.##.
.##..####"
for tests: {
part1: {
TEST_INPUT_HORIZONTAL => 400,
TEST_INPUT_VERTICAL => 5,
TEST_INPUT_475 => 7,
},
part2: {
TEST_INPUT_HORIZONTAL => 100,
TEST_INPUT_VERTICAL => 300,
TEST_INPUT_475 => 1300,
},
},
unittests: {