Day 4
This commit is contained in:
parent
2415fd02c2
commit
fba8779f72
2 changed files with 124 additions and 4 deletions
106
src/day4/mod.rs
Normal file
106
src/day4/mod.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::utils::Day;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Day4 {
|
||||||
|
pub input: String,
|
||||||
|
pub acc: usize,
|
||||||
|
pub cards: HashMap::<usize /* Card # */, Vec<usize> /* (won card indexes) */>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Day4 {
|
||||||
|
fn recurse(&mut self, cards: &Vec<usize>) {
|
||||||
|
for card in cards {
|
||||||
|
self.acc += 1;
|
||||||
|
|
||||||
|
if let Some(won_cards) = self.cards.get(card) {
|
||||||
|
self.recurse(&won_cards.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Day for Day4 {
|
||||||
|
fn part1(&mut self) -> String {
|
||||||
|
let mut sum = 0usize;
|
||||||
|
|
||||||
|
for line in self.input.lines() {
|
||||||
|
let (winning, numbers) = line.split_once(": ").unwrap().1.split_once(" | ").unwrap();
|
||||||
|
let winning = winning.split_whitespace().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut winning_numbers = Vec::<&str>::new();
|
||||||
|
for number in numbers.split_whitespace() {
|
||||||
|
if winning.contains(&number) && !winning_numbers.contains(&number) {
|
||||||
|
winning_numbers.push(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if winning_numbers.len() != 0 {
|
||||||
|
sum += winning_numbers.iter().skip(1).fold(1usize, |acc, _| acc * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sum.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(&mut self) -> String {
|
||||||
|
self.cards = HashMap::<usize /* Card # */, Vec<usize> /* won card indexes */>::new();
|
||||||
|
for (i, line) in self.input.lines().enumerate() {
|
||||||
|
let (winning, numbers) = line.split_once(": ").unwrap().1.split_once(" | ").unwrap();
|
||||||
|
let winning = winning.split_whitespace().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut winning_numbers = Vec::<&str>::new();
|
||||||
|
for number in numbers.split_whitespace() {
|
||||||
|
if winning.contains(&number) && !winning_numbers.contains(&number) {
|
||||||
|
winning_numbers.push(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cards.insert(i + 1, winning_numbers.into_iter().enumerate().map(|(j, _)| (i + 1) + (j + 1)).collect());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.recurse(&self.cards.keys().map(|e| *e).collect::<Vec<_>>());
|
||||||
|
|
||||||
|
self.acc.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{day4::Day4, utils::Day};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passes_example_1() {
|
||||||
|
dbg!(Day4 {
|
||||||
|
input: r#"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||||
|
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||||
|
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||||
|
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||||
|
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||||
|
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11"#
|
||||||
|
.to_string(),
|
||||||
|
acc: 0usize,
|
||||||
|
cards: HashMap::new()
|
||||||
|
}
|
||||||
|
.solve(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passes_example_2() {
|
||||||
|
dbg!(Day4 {
|
||||||
|
input: r#"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||||
|
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||||
|
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||||
|
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||||
|
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||||
|
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11"#
|
||||||
|
.to_string(),
|
||||||
|
acc: 0usize,
|
||||||
|
cards: HashMap::new()
|
||||||
|
}
|
||||||
|
.solve(2));
|
||||||
|
}
|
||||||
|
}
|
22
src/main.rs
22
src/main.rs
|
@ -1,15 +1,16 @@
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant}, collections::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use crate::{day1::Day1, day2::Day2, day3::Day3, utils::Day};
|
use crate::{day1::Day1, day2::Day2, day3::Day3, utils::Day, day4::Day4};
|
||||||
|
|
||||||
pub mod day1;
|
pub mod day1;
|
||||||
pub mod day2;
|
pub mod day2;
|
||||||
pub mod day3;
|
pub mod day3;
|
||||||
|
pub mod day4;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
@ -76,13 +77,25 @@ async fn main() {
|
||||||
games: vec![],
|
games: vec![],
|
||||||
}),
|
}),
|
||||||
3 => Box::new(Day3 { input: response }),
|
3 => Box::new(Day3 { input: response }),
|
||||||
|
4 => Box::new(Day4 { input: response, acc: 0usize, cards: HashMap::new() }),
|
||||||
_ => panic!("Invalid day #"),
|
_ => panic!("Invalid day #"),
|
||||||
};
|
};
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let result = day.solve(part);
|
let result = day.solve(part);
|
||||||
let end = std::time::Instant::now();
|
let end = std::time::Instant::now();
|
||||||
println!("Solution: {result}");
|
println!("Solution: {result}");
|
||||||
println!("Solved in {}ns", (end - start).as_nanos() as f64 / 1000.0);
|
|
||||||
|
let timing = (end - start).as_nanos();
|
||||||
|
let (timing, timing_units) = if timing >= 1000000000 {
|
||||||
|
(timing as f64 / 1000000000.0, "s")
|
||||||
|
} else if timing >= 1000000 {
|
||||||
|
(timing as f64 / 1000000.0, "ms")
|
||||||
|
} else if timing >= 1000 {
|
||||||
|
(timing as f64 / 1000.0, "µs")
|
||||||
|
} else {
|
||||||
|
(timing as f64, "ns")
|
||||||
|
};
|
||||||
|
println!("Solved in {timing}{timing_units}");
|
||||||
}
|
}
|
||||||
Subcommands::Benchmark {
|
Subcommands::Benchmark {
|
||||||
day,
|
day,
|
||||||
|
@ -109,6 +122,7 @@ async fn main() {
|
||||||
games: vec![],
|
games: vec![],
|
||||||
}),
|
}),
|
||||||
3 => Box::new(Day3 { input: response }),
|
3 => Box::new(Day3 { input: response }),
|
||||||
|
4 => Box::new(Day4 { input: response, acc: 0usize, cards: HashMap::new() }),
|
||||||
_ => panic!("Invalid day #"),
|
_ => panic!("Invalid day #"),
|
||||||
};
|
};
|
||||||
let mut timings = Vec::<Duration>::new();
|
let mut timings = Vec::<Duration>::new();
|
||||||
|
@ -121,7 +135,7 @@ async fn main() {
|
||||||
day.solve(part);
|
day.solve(part);
|
||||||
let end = Instant::now();
|
let end = Instant::now();
|
||||||
timings.push(end - start);
|
timings.push(end - start);
|
||||||
|
|
||||||
print!("\r{:.2}%", (i as f32 / n as f32) * 100.0);
|
print!("\r{:.2}%", (i as f32 / n as f32) * 100.0);
|
||||||
let _ = std::io::stdout().flush();
|
let _ = std::io::stdout().flush();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue