This commit is contained in:
nora 2024-12-07 20:31:52 +01:00
parent db1e54bf56
commit a5ff62c89c

View file

@ -1,3 +1,5 @@
use core::str;
use helper::{parse_unwrap, Day, Variants}; use helper::{parse_unwrap, Day, Variants};
pub fn main() { pub fn main() {
@ -15,8 +17,11 @@ helper::define_variants! {
basic => crate::part2,sample_count=500; basic => crate::part2,sample_count=500;
no_string_fmt => crate::part2_no_string_fmt,sample_count=1000; no_string_fmt => crate::part2_no_string_fmt,sample_count=1000;
order => crate::part2_order,sample_count=1000; order => crate::part2_order,sample_count=1000;
parsing => crate::part2_parsing,sample_count=5000; parsing => crate::part2_parsing,sample_count=2000;
parsing2 => crate::part2_parsing2,sample_count=5000; parsing2 => crate::part2_parsing2,sample_count=2000;
parsing3 => crate::part2_parsing3;
// This is fast on CPUs that have slow division, but slower on CPUs with fast division.
no_div => crate::part2_no_div;
} }
} }
@ -286,6 +291,161 @@ fn part2_parsing2(input: &str) -> u64 {
total total
} }
fn part2_parsing3(input: &str) -> u64 {
let mut total = 0;
let mut values = Vec::with_capacity(100);
let mut input = input.as_bytes();
while input.len() > 1 {
values.clear();
let parse1 = |a: u8| (a - b'0') as u64;
let mut i = 0;
let mut result = 0;
while input[i] != b':' {
let next = parse1(input[i]);
result *= 10;
result += next;
i += 1;
}
i += 2; // ': '
loop {
let mut val = parse1(input[i]);
i += 1;
if input[i] >= b'0' {
val *= 10;
val += parse1(input[i]);
i += 1;
if input[i] >= b'0' {
val *= 10;
val += parse1(input[i]);
i += 1;
values.push((1000, val));
} else {
values.push((100, val));
}
} else {
values.push((10, val));
}
if input[i] == b'\n' {
break;
}
i += 1; // ' '
}
i += 1;
input = &input[i..];
fn does_work(values: &[(u64, u64)], result: u64) -> bool {
if values.len() == 1 {
return values[0].1 == result;
}
let (thousand, l) = *values.last().unwrap();
let next = &values[..(values.len() - 1)];
let concat_works = result % thousand == l;
let mul_works = result % l == 0;
let sub_works = l <= result;
// Concat is the least common, so doing it first helps remove the most possibilities.
false
|| (concat_works && does_work(next, result / thousand))
|| (mul_works && does_work(next, result / l))
|| (sub_works && does_work(next, result - l))
}
if does_work(&values, result) {
total += result;
}
}
total
}
fn part2_no_div(input: &str) -> u64 {
let mut total = 0;
let mut values: Vec<(fn(u64) -> (u64, u64), u64)> = Vec::with_capacity(100);
let mut input = input.as_bytes();
while input.len() > 1 {
values.clear();
let parse1 = |a: u8| (a - b'0') as u64;
let mut i = 0;
let mut result = 0;
while input[i] != b':' {
let next = parse1(input[i]);
result *= 10;
result += next;
i += 1;
}
i += 2; // ': '
loop {
let mut val = parse1(input[i]);
i += 1;
if input[i] >= b'0' {
val *= 10;
val += parse1(input[i]);
i += 1;
if input[i] >= b'0' {
val *= 10;
val += parse1(input[i]);
i += 1;
values.push((|x| (x / 1000, x % 1000), val));
} else {
values.push((|x| (x / 100, x % 100), val));
}
} else {
values.push((|x| (x / 10, x % 10), val));
}
if input[i] == b'\n' {
break;
}
i += 1; // ' '
}
i += 1;
input = &input[i..];
fn does_work(values: &[(fn(u64) -> (u64, u64), u64)], result: u64) -> bool {
if values.len() == 1 {
return values[0].1 == result;
}
let (thousand, l) = *values.last().unwrap();
let next = &values[..(values.len() - 1)];
let (concat_result, concat_mod) = thousand(result);
let concat_works = concat_mod == l;
let mul_works = result % l == 0;
let mul_result = result / l;
let sub_works = l <= result;
// Concat is the least common, so doing it first helps remove the most possibilities.
false
|| (concat_works && does_work(next, concat_result))
|| (mul_works && does_work(next, mul_result))
|| (sub_works && does_work(next, result - l))
}
if does_work(&values, result) {
total += result;
}
}
total
}
helper::tests! { helper::tests! {
day07 Day07; day07 Day07;
part1 { part1 {