Optimize day6 with unstable rust

This commit is contained in:
HoLLy 2021-12-06 20:23:24 +01:00
Родитель 99790e94a9
Коммит 8b7c927e1e
2 изменённых файлов: 158 добавлений и 0 удалений

Просмотреть файл

@ -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};

154
day-6/src/main_unstable.rs Normal file
Просмотреть файл

@ -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]));
}