refactor: use generated boilerplate from lib
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
f53be47327
commit
cb82cbb433
8 changed files with 204 additions and 399 deletions
|
@ -1,8 +1,4 @@
|
||||||
use aoc_2022::file_to_lines;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
|
||||||
|
|
||||||
type Input = Vec<i32>;
|
type Input = Vec<i32>;
|
||||||
type Output = i32;
|
type Output = i32;
|
||||||
|
@ -24,53 +20,26 @@ fn n_biggest(n: usize, input: &Input) -> Output {
|
||||||
calories.iter().rev().take(n).sum()
|
calories.iter().rev().take(n).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_1(input: &Input) -> Output {
|
struct Day01;
|
||||||
n_biggest(1_usize, input)
|
impl Solution<Input, Output> for Day01 {
|
||||||
}
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
|
||||||
n_biggest(3_usize, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_lines(pathname)
|
file_to_lines(pathname)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| if s.is_empty() { -1 } else { s.parse().unwrap() })
|
.map(|s| if s.is_empty() { -1 } else { s.parse().unwrap() })
|
||||||
.collect()
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
n_biggest(1_usize, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
n_biggest(3_usize, input)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day01::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day01.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_01, Day01, 24000, 45000);
|
||||||
mod day_01 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day01.txt");
|
|
||||||
assert_eq!(part_1(&sample), 24000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day01.txt");
|
|
||||||
assert_eq!(part_2(&sample), 45000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,10 +2,14 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::{eyre::{eyre, Result}, Report};
|
use color_eyre::{
|
||||||
|
eyre::eyre,
|
||||||
|
Report,
|
||||||
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
type Input = Vec<Round>;
|
||||||
|
type Output = i32;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Shape {
|
enum Shape {
|
||||||
|
@ -133,53 +137,23 @@ impl Round {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Input = Vec<Round>;
|
struct Day02;
|
||||||
type Output = i32;
|
impl Solution<Input, Output> for Day02 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
fn part_1(input: &Input) -> Output {
|
|
||||||
input.iter().map(Round::score).sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
|
||||||
input.iter().map(Round::expected_score).sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_structs(pathname)
|
file_to_structs(pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
input.iter().map(Round::score).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
input.iter().map(Round::expected_score).sum()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day02::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day02.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_02, Day02, 15, 12);
|
||||||
mod day_02 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day02.txt");
|
|
||||||
assert_eq!(part_1(&sample), 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day02.txt");
|
|
||||||
assert_eq!(part_2(&sample), 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,15 +3,13 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::eyre::{Report, Result};
|
use color_eyre::eyre::Report;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
|
||||||
|
|
||||||
struct Backpack(HashSet<i32>, HashSet<i32>);
|
|
||||||
|
|
||||||
type Input = Vec<Backpack>;
|
type Input = Vec<Backpack>;
|
||||||
type Output = i32;
|
type Output = i32;
|
||||||
|
|
||||||
|
struct Backpack(HashSet<i32>, HashSet<i32>);
|
||||||
|
|
||||||
impl FromStr for Backpack {
|
impl FromStr for Backpack {
|
||||||
type Err = Report;
|
type Err = Report;
|
||||||
|
|
||||||
|
@ -49,13 +47,6 @@ impl Backpack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_1(input: &Input) -> Output {
|
|
||||||
input
|
|
||||||
.iter()
|
|
||||||
.map(|b| b.common_items().iter().sum::<i32>())
|
|
||||||
.sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn common_items(backpacks: &[Backpack]) -> HashSet<i32> {
|
fn common_items(backpacks: &[Backpack]) -> HashSet<i32> {
|
||||||
backpacks
|
backpacks
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -65,49 +56,29 @@ fn common_items(backpacks: &[Backpack]) -> HashSet<i32> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
struct Day03;
|
||||||
|
impl Solution<Input, Output> for Day03 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
|
file_to_structs(pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.map(|b| b.common_items().iter().sum::<i32>())
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
input
|
input
|
||||||
.chunks(3)
|
.chunks(3)
|
||||||
.map(|backpacks| common_items(backpacks).iter().sum::<i32>())
|
.map(|backpacks| common_items(backpacks).iter().sum::<i32>())
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_structs(pathname)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day03::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day03.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_03, Day03, 157, 70);
|
||||||
mod day_03 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day03.txt");
|
|
||||||
assert_eq!(part_1(&sample), 157);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day03.txt");
|
|
||||||
assert_eq!(part_2(&sample), 70);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,9 +3,10 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::eyre::{Report, Result};
|
use color_eyre::eyre::Report;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
type Input = Vec<Assignment>;
|
||||||
|
type Output = usize;
|
||||||
|
|
||||||
struct Assignment(RangeInclusive<i32>, RangeInclusive<i32>);
|
struct Assignment(RangeInclusive<i32>, RangeInclusive<i32>);
|
||||||
|
|
||||||
|
@ -48,53 +49,23 @@ impl Assignment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Input = Vec<Assignment>;
|
struct Day04;
|
||||||
type Output = usize;
|
impl Solution<Input, Output> for Day04 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
fn part_1(input: &Input) -> Output {
|
|
||||||
input.iter().filter(|a| a.fully_overlap()).count()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
|
||||||
input.iter().filter(|a| a.overlap()).count()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_structs(pathname)
|
file_to_structs(pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
input.iter().filter(|a| a.fully_overlap()).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
input.iter().filter(|a| a.overlap()).count()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day04::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day04.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_04, Day04, 2, 4);
|
||||||
mod day_04 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day04.txt");
|
|
||||||
assert_eq!(part_1(&sample), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day04.txt");
|
|
||||||
assert_eq!(part_2(&sample), 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,10 +3,11 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::eyre::{Report, Result};
|
use color_eyre::eyre::Report;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
type Input = Ship;
|
||||||
|
type Output = String;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Move {
|
struct Move {
|
||||||
|
@ -65,9 +66,6 @@ impl FromStr for Ship {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Input = Ship;
|
|
||||||
type Output = String;
|
|
||||||
|
|
||||||
fn stacks_to_string(stacks: &[Vec<char>]) -> String {
|
fn stacks_to_string(stacks: &[Vec<char>]) -> String {
|
||||||
stacks.iter().fold(String::new(), |acc, stack| {
|
stacks.iter().fold(String::new(), |acc, stack| {
|
||||||
if let Some(c) = stack.last() {
|
if let Some(c) = stack.last() {
|
||||||
|
@ -96,50 +94,23 @@ fn move_crates(input: &Input, one_by_one: bool) -> Output {
|
||||||
stacks_to_string(&stacks)
|
stacks_to_string(&stacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_1(input: &Input) -> Output {
|
struct Day05;
|
||||||
|
impl Solution<Input, Output> for Day05 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
|
file_to_string(pathname).parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
move_crates(input, true)
|
move_crates(input, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
fn part_2(input: &Input) -> Output {
|
||||||
move_crates(input, false)
|
move_crates(input, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_string(pathname).parse::<Input>().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day05::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day05.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_05, Day05, "CMZ".to_string(), "MCD".to_string());
|
||||||
mod day_05 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day05.txt");
|
|
||||||
assert_eq!(part_1(&sample), "CMZ".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day05.txt");
|
|
||||||
assert_eq!(part_2(&sample), "MCD".to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,10 +2,7 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
|
||||||
|
|
||||||
type Input = String;
|
type Input = String;
|
||||||
type Output = usize;
|
type Output = usize;
|
||||||
|
@ -23,90 +20,92 @@ fn unique_marker_index(buffer: &Input, n: usize) -> Output {
|
||||||
+ n
|
+ n
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_1(input: &Input) -> Output {
|
struct Day06;
|
||||||
unique_marker_index(input, 4)
|
impl Solution<Input, Output> for Day06 {
|
||||||
}
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
|
||||||
unique_marker_index(input, 14)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_string(pathname)
|
file_to_string(pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
unique_marker_index(input, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
unique_marker_index(input, 14)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day06::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day06.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_sample!(day_06, Day06, 7, 19);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod day_06 {
|
mod day_06_extended {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day06.txt");
|
|
||||||
assert_eq!(part_1(&sample), 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_1_example_1() {
|
fn test_part_1_example_1() {
|
||||||
assert_eq!(part_1(&"bvwbjplbgvbhsrlpgdmjqwftvncz".to_string()), 5);
|
assert_eq!(
|
||||||
|
Day06::part_1(&"bvwbjplbgvbhsrlpgdmjqwftvncz".to_string()),
|
||||||
|
5
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_1_example_2() {
|
fn test_part_1_example_2() {
|
||||||
assert_eq!(part_1(&"nppdvjthqldpwncqszvftbrmjlhg".to_string()), 6);
|
assert_eq!(
|
||||||
|
Day06::part_1(&"nppdvjthqldpwncqszvftbrmjlhg".to_string()),
|
||||||
|
6
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_1_example_3() {
|
fn test_part_1_example_3() {
|
||||||
assert_eq!(part_1(&"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".to_string()), 10);
|
assert_eq!(
|
||||||
|
Day06::part_1(&"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".to_string()),
|
||||||
|
10
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_1_example_4() {
|
fn test_part_1_example_4() {
|
||||||
assert_eq!(part_1(&"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".to_string()), 11);
|
assert_eq!(
|
||||||
}
|
Day06::part_1(&"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".to_string()),
|
||||||
|
11
|
||||||
#[test]
|
);
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day06.txt");
|
|
||||||
assert_eq!(part_2(&sample), 19);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_2_example_1() {
|
fn test_part_2_example_1() {
|
||||||
assert_eq!(part_2(&"bvwbjplbgvbhsrlpgdmjqwftvncz".to_string()), 23);
|
assert_eq!(
|
||||||
|
Day06::part_2(&"bvwbjplbgvbhsrlpgdmjqwftvncz".to_string()),
|
||||||
|
23
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_2_example_2() {
|
fn test_part_2_example_2() {
|
||||||
assert_eq!(part_2(&"nppdvjthqldpwncqszvftbrmjlhg".to_string()), 23);
|
assert_eq!(
|
||||||
|
Day06::part_2(&"nppdvjthqldpwncqszvftbrmjlhg".to_string()),
|
||||||
|
23
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_2_example_3() {
|
fn test_part_2_example_3() {
|
||||||
assert_eq!(part_2(&"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".to_string()), 29);
|
assert_eq!(
|
||||||
|
Day06::part_2(&"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".to_string()),
|
||||||
|
29
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_2_example_4() {
|
fn test_part_2_example_4() {
|
||||||
assert_eq!(part_2(&"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".to_string()), 26);
|
assert_eq!(
|
||||||
|
Day06::part_2(&"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".to_string()),
|
||||||
|
26
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@ use std::{cell::RefCell, cmp::min, collections::BTreeMap, rc::Rc, str::FromStr};
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::{eyre::Result, Report};
|
use color_eyre::Report;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
type Input = Filesystem;
|
||||||
|
type Output = usize;
|
||||||
|
|
||||||
type FileHandle = Rc<RefCell<AocFile>>;
|
type FileHandle = Rc<RefCell<AocFile>>;
|
||||||
|
|
||||||
|
@ -47,15 +48,15 @@ impl AocFile {
|
||||||
panic!("cannot cd in file")
|
panic!("cannot cd in file")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_under_100000(&self) -> (bool, usize, usize) {
|
fn size_under(&self, max_size: usize) -> (bool, usize, usize) {
|
||||||
match self {
|
match self {
|
||||||
AocFile::File(s) => (false, 0, *s),
|
AocFile::File(s) => (false, 0, *s),
|
||||||
AocFile::Directory(files) => {
|
AocFile::Directory(files) => {
|
||||||
let (running_total, size) = files
|
let (running_total, size) = files
|
||||||
.values()
|
.values()
|
||||||
.map(|f| f.borrow().size_under_100000())
|
.map(|f| f.borrow().size_under(max_size))
|
||||||
.fold((0_usize, 0_usize), |(mut running, size), (dir, r, s)| {
|
.fold((0_usize, 0_usize), |(mut running, size), (dir, r, s)| {
|
||||||
if dir && s <= 100000 {
|
if dir && s <= max_size {
|
||||||
running += s;
|
running += s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +113,8 @@ impl Filesystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [MARK] Helper functions for ‹FromStr› trait
|
||||||
|
|
||||||
fn cd(&mut self, dir: &str) {
|
fn cd(&mut self, dir: &str) {
|
||||||
match dir {
|
match dir {
|
||||||
".." => {
|
".." => {
|
||||||
|
@ -143,15 +146,28 @@ impl Filesystem {
|
||||||
|
|
||||||
for file in command.lines().skip(1) {
|
for file in command.lines().skip(1) {
|
||||||
let parts = file.split_ascii_whitespace().collect_vec();
|
let parts = file.split_ascii_whitespace().collect_vec();
|
||||||
if parts[0] == "dir" {
|
if parts[0] != "dir" {
|
||||||
/* no-op */
|
|
||||||
} else {
|
|
||||||
let name = parts[1];
|
let name = parts[1];
|
||||||
let size: usize = parts[0].parse().unwrap();
|
let size: usize = parts[0].parse().unwrap();
|
||||||
self.touch(name, size);
|
self.touch(name, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [MARK] Helper functions for ‹FromStr› trait
|
||||||
|
|
||||||
|
fn size_under(&self, max_size: usize) -> usize {
|
||||||
|
self.root.borrow().size_under(max_size).1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn purge(&self, total: usize, needed: usize) -> usize {
|
||||||
|
let used = self.root.borrow().size_under(0).2;
|
||||||
|
|
||||||
|
// to_be_freed >= needed - (total - used)
|
||||||
|
let to_be_freed = needed - (total - used);
|
||||||
|
|
||||||
|
self.root.borrow().smallest_bigger(to_be_freed).1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Filesystem {
|
impl FromStr for Filesystem {
|
||||||
|
@ -168,59 +184,23 @@ impl FromStr for Filesystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Input = Filesystem;
|
struct Day07;
|
||||||
type Output = usize;
|
impl Solution<Input, Output> for Day07 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
fn part_1(input: &Input) -> Output {
|
|
||||||
input.root.borrow().size_under_100000().1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
|
||||||
let (total, needed) = (70000000, 30000000);
|
|
||||||
let used = input.root.borrow().size_under_100000().2;
|
|
||||||
|
|
||||||
// to_be_freed >= needed - (total - used)
|
|
||||||
let to_be_freed = needed - (total - used);
|
|
||||||
|
|
||||||
input.root.borrow().smallest_bigger(to_be_freed).1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_string(pathname).parse().unwrap()
|
file_to_string(pathname).parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
input.size_under(100000)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
input.purge(70000000, 30000000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day07::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day07.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_07, Day07, 95437, 24933642);
|
||||||
mod day_07 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day07.txt");
|
|
||||||
assert_eq!(part_1(&sample), 95437);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day07.txt");
|
|
||||||
assert_eq!(part_2(&sample), 24933642);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,10 +2,7 @@ use std::{cmp::max, collections::BTreeSet};
|
||||||
|
|
||||||
use aoc_2022::*;
|
use aoc_2022::*;
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tracing::*;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
|
||||||
|
|
||||||
type Input = Vec<Vec<i8>>;
|
type Input = Vec<Vec<i8>>;
|
||||||
type Output = usize;
|
type Output = usize;
|
||||||
|
@ -51,15 +48,6 @@ fn count_in_columns(trees: &Input, counted: &mut Visited) {
|
||||||
count_in(trees, counted, true)
|
count_in(trees, counted, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_1(input: &Input) -> Output {
|
|
||||||
let mut counted = Visited::new();
|
|
||||||
|
|
||||||
count_in_rows(input, &mut counted);
|
|
||||||
count_in_columns(input, &mut counted);
|
|
||||||
|
|
||||||
counted.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count_visible(trees: &Input, position: SignedPosition, diff: SignedPosition) -> usize {
|
fn count_visible(trees: &Input, position: SignedPosition, diff: SignedPosition) -> usize {
|
||||||
let max_height = *index(trees, &position);
|
let max_height = *index(trees, &position);
|
||||||
let mut visible = 0;
|
let mut visible = 0;
|
||||||
|
@ -91,16 +79,9 @@ fn compute_scenic_score(trees: &Input, x: isize, y: isize) -> usize {
|
||||||
.product()
|
.product()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part_2(input: &Input) -> Output {
|
struct Day08;
|
||||||
(0..input.len())
|
impl Solution<Input, Output> for Day08 {
|
||||||
.flat_map(|y| {
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
(0..input[y].len()).map(move |x| compute_scenic_score(input, x as isize, y as isize))
|
|
||||||
})
|
|
||||||
.max()
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_input(pathname: &str) -> Input {
|
|
||||||
file_to_string(pathname)
|
file_to_string(pathname)
|
||||||
.lines()
|
.lines()
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
|
@ -109,40 +90,29 @@ fn parse_input(pathname: &str) -> Input {
|
||||||
.collect_vec()
|
.collect_vec()
|
||||||
})
|
})
|
||||||
.collect_vec()
|
.collect_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
let mut counted = Visited::new();
|
||||||
|
|
||||||
|
count_in_rows(input, &mut counted);
|
||||||
|
count_in_columns(input, &mut counted);
|
||||||
|
|
||||||
|
counted.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
(0..input.len())
|
||||||
|
.flat_map(|y| {
|
||||||
|
(0..input[y].len()).map(move |x| compute_scenic_score(input, x as isize, y as isize))
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt()
|
Day08::main()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.with_target(false)
|
|
||||||
.with_file(true)
|
|
||||||
.with_line_number(true)
|
|
||||||
.without_time()
|
|
||||||
.compact()
|
|
||||||
.init();
|
|
||||||
color_eyre::install()?;
|
|
||||||
|
|
||||||
let input = parse_input("inputs/day08.txt");
|
|
||||||
|
|
||||||
info!("Part 1: {}", part_1(&input));
|
|
||||||
info!("Part 2: {}", part_2(&input));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
test_sample!(day_08, Day08, 21, 8);
|
||||||
mod day_08 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_1() {
|
|
||||||
let sample = parse_input("samples/day08.txt");
|
|
||||||
assert_eq!(part_1(&sample), 21);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_part_2() {
|
|
||||||
let sample = parse_input("samples/day08.txt");
|
|
||||||
assert_eq!(part_2(&sample), 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue