Optimize day6 with unstable rust
This commit is contained in:
Родитель
99790e94a9
Коммит
8b7c927e1e
|
@ -1,5 +1,9 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
// uncomment for unstable version
|
||||||
|
// #![allow(unused_attributes, incomplete_features)]
|
||||||
|
// #![feature(generic_const_exprs, const_for, const_mut_refs)]
|
||||||
|
|
||||||
use aoc_lib::AdventOfCode;
|
use aoc_lib::AdventOfCode;
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![feature(const_for)]
|
||||||
|
#![feature(const_mut_refs)]
|
||||||
|
|
||||||
|
use aoc_lib::*;
|
||||||
|
|
||||||
|
aoc_setup!(Day6, sample 1: 5934, sample 2: 26984457539, part 1: 360268);
|
||||||
|
|
||||||
|
pub struct Day6;
|
||||||
|
|
||||||
|
impl AdventOfCode for Day6 {
|
||||||
|
type Input = Vec<usize>; // can be u8
|
||||||
|
type Output = u64;
|
||||||
|
|
||||||
|
fn parse_input(s: &str) -> Self::Input {
|
||||||
|
s.split(',').map(|l| l.parse().unwrap()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_1(input: &Self::Input) -> Self::Output {
|
||||||
|
solve_smart::<80>(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_2(input: &Self::Input) -> Self::Output {
|
||||||
|
solve_smart::<256>(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn solve_naive<const DAYS: usize>(input: &[usize]) -> u64 {
|
||||||
|
let mut vec: Vec<usize> = input.iter().copied().collect();
|
||||||
|
|
||||||
|
for _day in 0..DAYS {
|
||||||
|
let start_len = vec.len();
|
||||||
|
for i in 0..start_len {
|
||||||
|
if vec[i] == 0 {
|
||||||
|
vec[i] = 6;
|
||||||
|
vec.push(8);
|
||||||
|
} else {
|
||||||
|
vec[i] -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec.len() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn solve_smart<const DAYS: usize>(input: &[usize]) -> u64
|
||||||
|
where
|
||||||
|
[(); DAYS + 8]: Sized,
|
||||||
|
{
|
||||||
|
let map = generate_map::<DAYS>();
|
||||||
|
// println!("map: {:?}", map);
|
||||||
|
|
||||||
|
// for every starting fish, calculate the amount of offspring they generate
|
||||||
|
let birthed_offspring: u64 = input
|
||||||
|
.iter()
|
||||||
|
.map(|&fish| (map[8 - fish + DAYS])) // lower number means born earlier, means more fish
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
birthed_offspring // + (input.len() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn generate_map<const LEN: usize>() -> [u64; LEN + 8]
|
||||||
|
where
|
||||||
|
[(); LEN + 8]: Sized,
|
||||||
|
{
|
||||||
|
// this map contains the number of offspring that are resultant from a fish born at time 0
|
||||||
|
let mut map = [0u64; LEN + 8];
|
||||||
|
|
||||||
|
let mut day = 0;
|
||||||
|
loop {
|
||||||
|
let added_fish = get_fish_count_from_map_day(&map, day);
|
||||||
|
map[day] = added_fish;
|
||||||
|
// println!("day: {}, added_fish: {}", day, added_fish);
|
||||||
|
|
||||||
|
day += 1;
|
||||||
|
|
||||||
|
if day >= LEN + 8 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
// rename me
|
||||||
|
// also const I think
|
||||||
|
const fn get_fish_count_from_map_day(map: &[u64], day: usize) -> u64 {
|
||||||
|
// always start with 1 fish
|
||||||
|
let mut added_fish = 1;
|
||||||
|
|
||||||
|
// look at all days that spawn a fish, see how many fish result from this day
|
||||||
|
// can't use ranges in const fn yet
|
||||||
|
let mut offspring_day = 9;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if day < offspring_day {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let remaining_days = day - offspring_day;
|
||||||
|
added_fish += map[remaining_days];
|
||||||
|
|
||||||
|
offspring_day += 7;
|
||||||
|
|
||||||
|
if offspring_day > day {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
added_fish
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_map() {
|
||||||
|
let map = generate_map::<{ 30 - 8 }>();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
map,
|
||||||
|
[
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8,
|
||||||
|
8
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_solve_naive() {
|
||||||
|
assert_eq!(5, solve_naive::<1>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(6, solve_naive::<2>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(7, solve_naive::<3>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(9, solve_naive::<4>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_naive::<5>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_naive::<6>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_naive::<7>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_naive::<8>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(11, solve_naive::<9>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(12, solve_naive::<10>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(15, solve_naive::<11>(&[3, 4, 3, 1, 2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_solve_smart() {
|
||||||
|
assert_eq!(5, solve_smart::<1>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(6, solve_smart::<2>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(7, solve_smart::<3>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(9, solve_smart::<4>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_smart::<5>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_smart::<6>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_smart::<7>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(10, solve_smart::<8>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(11, solve_smart::<9>(&[3, 4, 3, 1, 2])); // fails
|
||||||
|
assert_eq!(12, solve_smart::<10>(&[3, 4, 3, 1, 2]));
|
||||||
|
assert_eq!(15, solve_smart::<11>(&[3, 4, 3, 1, 2]));
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче