day04 finished
This commit is contained in:
parent
d7c85a75f6
commit
33eb92e9d1
10 changed files with 1184 additions and 55 deletions
6
data/day04/example01.txt
Normal file
6
data/day04/example01.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
2-4,6-8
|
||||
2-3,4-5
|
||||
5-7,7-9
|
||||
2-8,3-7
|
||||
6-6,4-6
|
||||
2-6,4-8
|
||||
1000
data/day04/input.txt
Normal file
1000
data/day04/input.txt
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,27 @@
|
|||
use itertools::Itertools;
|
||||
use std::{fs, io};
|
||||
|
||||
pub fn read_data(day_num: usize, file: &str) -> io::Result<String> {
|
||||
fn read_data(day_num: usize, file: &str) -> io::Result<String> {
|
||||
fs::read_to_string(format!("data/day{:02}/{}", day_num, file))
|
||||
}
|
||||
|
||||
pub fn read_lines(day_num: usize, file: &str) -> io::Result<Vec<String>> {
|
||||
let lines = read_data(day_num, file)?;
|
||||
let x = lines
|
||||
.split('\n')
|
||||
.with_position()
|
||||
.filter_map(|line| match line {
|
||||
itertools::Position::First(line)
|
||||
| itertools::Position::Middle(line)
|
||||
| itertools::Position::Only(line) => Some(line.to_owned()),
|
||||
itertools::Position::Last(line) => {
|
||||
if line.len() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(line.to_owned())
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok(x)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ impl DayTrait for Day {
|
|||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let vector = Day::parse(lines)?;
|
||||
let max = vector.iter().max().ok_or(CalorieError::Empty)?;
|
||||
Ok(ResultType::IntResult(*max))
|
||||
}
|
||||
|
||||
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let vector = Day::parse(lines)?;
|
||||
let sum = vector.iter().sorted_by(|a, b| Ord::cmp(b, a)).take(3).sum();
|
||||
Ok(ResultType::IntResult(sum))
|
||||
|
|
@ -27,9 +27,9 @@ impl DayTrait for Day {
|
|||
}
|
||||
|
||||
impl Day {
|
||||
fn parse(lines: &str) -> Result<Vec<i64>, CalorieError> {
|
||||
fn parse(lines: &[String]) -> Result<Vec<i64>, CalorieError> {
|
||||
Ok(lines
|
||||
.split("\n")
|
||||
.iter()
|
||||
.batching(|it| {
|
||||
let result = it
|
||||
.take_while(|line| line.len() != 0)
|
||||
|
|
@ -57,13 +57,13 @@ pub enum CalorieError {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common::file::read_data;
|
||||
use crate::common::file::read_lines;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
fn test_part1() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_data(day.get_day_number(), "example01.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(24_000);
|
||||
let result = day.part1(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
@ -74,7 +74,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_part2() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_data(day.get_day_number(), "example01.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(45_000);
|
||||
let result = day.part2(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
@ -84,7 +84,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_parse() -> Result<()> {
|
||||
let lines = read_data(DAY_NUMBER, "example01.txt")?;
|
||||
let lines = read_lines(DAY_NUMBER, "example01.txt")?;
|
||||
let expected = vec![6000, 4000, 11000, 24000, 10000];
|
||||
let result = Day::parse(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ impl DayTrait for Day {
|
|||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let sum = lines
|
||||
.split("\n")
|
||||
.map(RPS::parse_line)
|
||||
.iter()
|
||||
.map(|line| RPS::parse_line(&line))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.map(|(first, second)| second.asses_pair(&first))
|
||||
|
|
@ -24,10 +24,10 @@ impl DayTrait for Day {
|
|||
Ok(ResultType::IntResult(sum))
|
||||
}
|
||||
|
||||
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let sum = lines
|
||||
.split("\n")
|
||||
.map(Strategy::parse_line)
|
||||
.iter()
|
||||
.map(|line| Strategy::parse_line(&line))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.map(|(first, second)| second.fullfill(&first).asses_pair(&first))
|
||||
|
|
@ -155,7 +155,7 @@ impl TryFrom<&str> for Strategy {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common::file::read_data;
|
||||
use crate::common::file::read_lines;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
|
|
@ -182,7 +182,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_part1() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_data(day.get_day_number(), "example01.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(15);
|
||||
let result = day.part1(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
@ -214,7 +214,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_part2() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_data(day.get_day_number(), "example01.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::NoResult;
|
||||
let result = day.part2(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use super::template::{DayTrait, ResultType};
|
||||
use itertools::Itertools;
|
||||
use thiserror::Error;
|
||||
|
||||
use super::template::{DayTrait, ResultType};
|
||||
|
||||
const DAY_NUMBER: usize = 3;
|
||||
|
||||
pub struct Day;
|
||||
|
|
@ -12,25 +11,25 @@ impl DayTrait for Day {
|
|||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let sum = lines
|
||||
.split('\n')
|
||||
.map(|rucksack| find_double(rucksack).and_then(priority))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.iter()
|
||||
.sum();
|
||||
.map(|line| find_double(&line))
|
||||
.map_ok(priority)
|
||||
.flatten_ok()
|
||||
.fold_ok(0, |a, b| a + b)?;
|
||||
Ok(ResultType::IntResult(sum))
|
||||
}
|
||||
|
||||
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let sum = lines
|
||||
.split('\n')
|
||||
.iter()
|
||||
.chunks(3)
|
||||
.into_iter()
|
||||
.map(|chunk| find_badge(&chunk.collect::<Vec<_>>()).and_then(priority))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.iter()
|
||||
.sum();
|
||||
.map(|chunk| find_badge(&chunk.collect::<Vec<_>>()))
|
||||
.map_ok(priority)
|
||||
.flatten_ok()
|
||||
.fold_ok(0, |a, b| a + b)?;
|
||||
Ok(ResultType::IntResult(sum))
|
||||
}
|
||||
}
|
||||
|
|
@ -72,7 +71,7 @@ fn find_double(content: &str) -> Result<char, RucksackError> {
|
|||
Err(RucksackError::NoDoubleFound)?
|
||||
}
|
||||
|
||||
fn find_badge<'a>(elves: &[&str]) -> Result<char, RucksackError> {
|
||||
fn find_badge<'a>(elves: &[&String]) -> Result<char, RucksackError> {
|
||||
if elves.len() < 2 {
|
||||
return Err(RucksackError::NeedAtLeastTwo);
|
||||
};
|
||||
|
|
@ -93,7 +92,7 @@ fn find_badge<'a>(elves: &[&str]) -> Result<char, RucksackError> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common::file::read_data;
|
||||
use crate::common::file::read_lines;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
|
|
@ -109,7 +108,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_part1() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_data(day.get_day_number(), "example01.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(157);
|
||||
let result = day.part1(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
@ -117,24 +116,10 @@ mod test {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_badge() -> Result<(), RucksackError> {
|
||||
let input = vec![
|
||||
"vJrwpWtwJgWrhcsFMMfFFhFp",
|
||||
"jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL",
|
||||
"PmmdzqPrVvPwwTWBwg",
|
||||
];
|
||||
let expected = 18;
|
||||
let result = find_badge(&input).and_then(priority)?;
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_data(day.get_day_number(), "example01.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(70);
|
||||
let result = day.part2(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
|
|
|||
114
src/days/day04/mod.rs
Normal file
114
src/days/day04/mod.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use super::template::{DayTrait, ResultType};
|
||||
use itertools::Itertools;
|
||||
use std::num::ParseIntError;
|
||||
use thiserror::Error;
|
||||
|
||||
const DAY_NUMBER: usize = 4;
|
||||
|
||||
pub struct Day;
|
||||
|
||||
impl DayTrait for Day {
|
||||
fn get_day_number(&self) -> usize {
|
||||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let sum = lines
|
||||
.iter()
|
||||
.map(|line| parse(&line))
|
||||
.filter_ok(fully_contained)
|
||||
.fold_ok(0i64, |a, _| a + 1)?;
|
||||
Ok(ResultType::IntResult(sum))
|
||||
}
|
||||
|
||||
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let sum = lines
|
||||
.iter()
|
||||
.map(|line| parse(&line))
|
||||
.filter_ok(overlaps)
|
||||
.fold_ok(0i64, |a, _| a + 1)?;
|
||||
Ok(ResultType::IntResult(sum))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum SectionError {
|
||||
#[error("Can't parse line: {0}")]
|
||||
InvalidLine(String),
|
||||
|
||||
#[error("Can't parse range: {0}")]
|
||||
InvalidRange(String),
|
||||
|
||||
#[error("Could not parse Number")]
|
||||
NotInteger(#[from] ParseIntError),
|
||||
}
|
||||
|
||||
type Range = (i64, i64);
|
||||
|
||||
fn parse_range(range: &str) -> Result<Range, SectionError> {
|
||||
let nums: Vec<_> = range
|
||||
.split('-')
|
||||
.map(|num| num.parse::<i64>())
|
||||
.try_collect()?;
|
||||
if nums.len() != 2 {
|
||||
Err(SectionError::InvalidLine(range.to_owned()))
|
||||
} else {
|
||||
Ok(nums.iter().copied().collect_tuple().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(line: &str) -> Result<(Range, Range), SectionError> {
|
||||
let ranges: Vec<_> = line.split(',').map(parse_range).try_collect()?;
|
||||
if ranges.len() != 2 {
|
||||
Err(SectionError::InvalidRange(line.to_owned()))
|
||||
} else {
|
||||
Ok(ranges.iter().copied().collect_tuple().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fn fully_contained((first, second): &(Range, Range)) -> bool {
|
||||
(first.0 >= second.0 && first.1 <= second.1) || (second.0 >= first.0 && second.1 <= first.1)
|
||||
}
|
||||
|
||||
fn overlaps((first, second): &(Range, Range)) -> bool {
|
||||
first.0 <= second.1 && second.0 <= first.1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common::file::read_lines;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
fn test_parse() -> Result<()> {
|
||||
let input = "2-4,6-8";
|
||||
let expected = ((2, 4), (6, 8));
|
||||
let result = parse(input)?;
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part1() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(2);
|
||||
let result = day.part1(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::IntResult(4);
|
||||
let result = day.part2(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
mod day01;
|
||||
mod day02;
|
||||
mod day03;
|
||||
mod day04;
|
||||
mod template;
|
||||
|
||||
pub use template::DayTrait;
|
||||
|
|
@ -10,13 +11,14 @@ pub mod day_provider {
|
|||
use super::*;
|
||||
use thiserror::Error;
|
||||
|
||||
const MAX_DAY: usize = 3;
|
||||
const MAX_DAY: usize = 4;
|
||||
|
||||
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
|
||||
match day_num {
|
||||
1 => Ok(Box::new(day01::Day)),
|
||||
2 => Ok(Box::new(day02::Day)),
|
||||
3 => Ok(Box::new(day03::Day)),
|
||||
4 => Ok(Box::new(day04::Day)),
|
||||
_ => Err(ProviderError::InvalidNumber(day_num)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@ pub enum ResultType {
|
|||
|
||||
pub trait DayTrait {
|
||||
fn get_day_number(&self) -> usize;
|
||||
fn part1(&self, lines: &str) -> Result<ResultType>;
|
||||
fn part2(&self, lines: &str) -> Result<ResultType>;
|
||||
fn part1(&self, lines: &[String]) -> Result<ResultType>;
|
||||
fn part2(&self, lines: &[String]) -> Result<ResultType>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ mod days;
|
|||
mod macros;
|
||||
|
||||
use anyhow::Result;
|
||||
use common::file::read_data;
|
||||
use common::file::read_lines;
|
||||
use days::{day_provider, DayTrait, ResultType};
|
||||
use std::{
|
||||
env,
|
||||
|
|
@ -47,7 +47,7 @@ fn output(day: usize, part: usize, result: ResultType, time: Duration) -> () {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_part(day: &Box<dyn DayTrait>, is_part1: bool, lines: &str) -> Result<Duration> {
|
||||
fn run_part(day: &Box<dyn DayTrait>, is_part1: bool, lines: &[String]) -> Result<Duration> {
|
||||
let now = Instant::now();
|
||||
let result = if is_part1 {
|
||||
day.part1(lines)?
|
||||
|
|
@ -70,7 +70,7 @@ fn run_part(day: &Box<dyn DayTrait>, is_part1: bool, lines: &str) -> Result<Dura
|
|||
}
|
||||
|
||||
fn run(day: &Box<dyn DayTrait>, part1: bool, part2: bool) -> Result<Duration> {
|
||||
let lines = read_data(day.get_day_number(), "input.txt")?;
|
||||
let lines = read_lines(day.get_day_number(), "input.txt")?;
|
||||
let elapsed1 = if part1 {
|
||||
run_part(day, true, &lines)?
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue