perf improvements and solution for year2022 day01

This commit is contained in:
fuckwit 2023-11-22 21:47:10 +01:00
parent 96edd60a7c
commit f0a198d6f9
8 changed files with 2326 additions and 31 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"rust-analyzer.showUnlinkedFileNotification": false
}

2255
input/year2022/day01.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,3 +10,7 @@ pub mod year2016 {
pub mod day02;
pub mod day03;
}
pub mod year2022 {
pub mod day01;
}

View File

@ -6,7 +6,7 @@ struct Solution {
year: u32,
day: u32,
input: &'static str,
run: fn(&str) -> (String, String),
run: fn(&str) -> (String, Duration, String, Duration),
}
macro_rules! solution {
@ -23,9 +23,13 @@ macro_rules! solution {
]),
run: |input: &str| {
use aoc::$year::$day::*;
let part1_start = Instant::now();
let part1 = part1(&input).to_string();
let part1_elapsed = part1_start.elapsed();
let part2_start = Instant::now();
let part2 = part2(&input).to_string();
(part1, part2)
let part2_elapsed = part2_start.elapsed();
(part1, part1_elapsed, part2, part2_elapsed)
},
}
};
@ -54,18 +58,18 @@ fn main() {
} in solutions
{
let start = Instant::now();
let (aw1, aw2) = (run)(input);
let (aw1, el1, aw2, el2) = (run)(input);
let elapsed = start.elapsed();
overall_duration += elapsed;
println!("{year} Day {day:02} ({:?})", elapsed);
println!(" Part 1: {aw1}");
println!(" Part 2: {aw2}");
println!("{year} Day {day:02} ({elapsed:?})");
println!(" Part 1: {aw1} ({el1:?})");
println!(" Part 2: {aw2} ({el2:?})");
}
println!("Total solutions: {count} ({overall_duration:?})")
}
fn solutions() -> impl Iterator<Item = Solution> {
std::iter::empty().chain(year2016())
std::iter::empty().chain(year2016()).chain(year2022())
}
fn year2016() -> Vec<Solution> {
@ -75,3 +79,9 @@ fn year2016() -> Vec<Solution> {
solution!(year2016, day03),
]
}
fn year2022() -> Vec<Solution> {
vec![
solution!(year2022, day01),
]
}

View File

@ -2,11 +2,11 @@ use std::collections::HashSet;
use crate::util::{index::*, parse::ParseExt};
fn parse(input: &str) -> Vec<(u8, u32)> {
fn parse(input: &str) -> impl Iterator<Item = (u8, u32)> + '_ {
let dirs = input.bytes().filter(u8::is_ascii_uppercase);
let steps = input.u32s();
let steps: Vec<_> = input.u32s().collect();
dirs.zip(steps).collect()
dirs.zip(steps)
}
pub fn part1(input: &str) -> impl std::fmt::Display {

View File

@ -25,11 +25,7 @@ pub fn part1(input: &str) -> impl std::fmt::Display {
#[inline]
#[rustfmt::skip]
fn within(coord: &Ix2) -> bool {
[
[0, 0], [1, 0], [2, 0],
[0, 1], [1, 1], [2, 1],
[0, 2], [1, 2], [2, 2]
].contains(&coord.0)
coord.x() >= 0 && coord.x() <= 2 && coord.y() >= 0 && coord.y() <= 2
}
#[inline]
@ -54,13 +50,14 @@ pub fn part2(input: &str) -> impl std::fmt::Display {
#[inline]
#[rustfmt::skip]
fn within(coord: &Ix2) -> bool {
[
[2, 0],
[1, 1], [2, 1], [3, 1],
[0, 2], [1, 2], [2, 2], [3, 2], [4, 2],
[1, 3], [2, 3], [3, 3],
[2, 4],
].contains(&coord.0)
match coord.0 {
[0, 2] |
[1, 1] | [1, 2] | [1, 3] |
[2, 0] | [2, 1] | [2, 2] | [2, 3] | [2, 4] |
[3, 1] | [3, 2] | [3, 3] |
[4, 2] => true,
_ => false
}
}
#[inline]

View File

@ -1,5 +1,6 @@
use crate::util::parse::ParseExt;
#[inline]
fn valid_triangle(v: &[u32; 3]) -> bool {
v[0] + v[1] > v[2] && v[1] + v[2] > v[0] && v[0] + v[2] > v[1]
}
@ -9,6 +10,10 @@ pub fn part1(input: &str) -> impl std::fmt::Display {
.lines()
.map(|s| {
s.u32s()
// This is faster than `collect().try_into().expect("")`
// presumably because of the allocation of the Vec
// and the additional check for the Option for each line
// incure a bit of overhead
.fold(([0u32; 3], 0), |(mut a, i), v| {
a[i] = v;
(a, i + 1)
@ -31,14 +36,10 @@ pub fn part2(input: &str) -> impl std::fmt::Display {
let l1: Vec<u32> = l1.u32s().collect();
let l2: Vec<u32> = l2.u32s().collect();
let l3: Vec<u32> = l3.u32s().collect();
if valid_triangle(&[l1[0], l2[0], l3[0]]) {
valid += 1;
}
if valid_triangle(&[l1[1], l2[1], l3[1]]) {
valid += 1;
}
if valid_triangle(&[l1[2], l2[2], l3[2]]) {
valid += 1;
for i in 0..2 {
if valid_triangle(&[l1[i], l2[i], l3[i]]) {
valid += 1;
}
}
}
valid
@ -51,5 +52,5 @@ fn test_part1() {
#[test]
fn test_part2() {
assert_eq!("", part2("").to_string());
assert_eq!("2", part2("100 200 300\n101 201 301\n102 202 302").to_string());
}

25
src/year2022/day01.rs Normal file
View File

@ -0,0 +1,25 @@
use crate::util::parse::ParseExt;
fn calories(input: &str) -> impl Iterator<Item = u32> + '_ {
input.split("\n\n").map(|set| set.u32s().sum())
}
pub fn part1(input: &str) -> impl std::fmt::Display {
calories(input).max().expect("must have one max")
}
pub fn part2(input: &str) -> impl std::fmt::Display {
let mut items: Vec<_> = calories(input).collect();
items.sort_unstable();
items.iter().rev().take(3).sum::<u32>()
}
#[test]
fn test_part1() {
assert_eq!("24000", part1("1000\n2000\n3000\n\n4000\n\n5000\n6000\n\n7000\n8000\n9000\n\n10000").to_string())
}
#[test]
fn test_part2() {
assert_eq!("4", part2("R8, R4, R4, R8").to_string())
}