Add day 6
This commit is contained in:
1
2023/day6/.gitignore
vendored
Normal file
1
2023/day6/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target/
|
||||
39
2023/day6/Cargo.lock
generated
Normal file
39
2023/day6/Cargo.lock
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "day6"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"indoc",
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
10
2023/day6/Cargo.toml
Normal file
10
2023/day6/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "day6"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
indoc = "2.0.4"
|
||||
nom = "7.1.3"
|
||||
160
2023/day6/src/main.rs
Normal file
160
2023/day6/src/main.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete::{char, digit1, multispace0, newline},
|
||||
combinator::map,
|
||||
multi::{many1, separated_list1},
|
||||
sequence::{delimited, preceded, separated_pair, tuple},
|
||||
IResult,
|
||||
};
|
||||
|
||||
fn number(i: &str) -> IResult<&str, usize> {
|
||||
map(digit1, |f: &str| f.parse::<usize>().unwrap())(i)
|
||||
}
|
||||
|
||||
fn spaces(i: &str) -> IResult<&str, Vec<char>> {
|
||||
many1(char(' '))(i)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Race {
|
||||
time: usize,
|
||||
distance: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RaceSheet {
|
||||
races: Vec<Race>,
|
||||
}
|
||||
|
||||
impl RaceSheet {
|
||||
fn parse(s: &str) -> IResult<&str, Self> {
|
||||
let (rest, (times, distances)) = delimited(
|
||||
multispace0,
|
||||
separated_pair(
|
||||
preceded(
|
||||
tuple((tag("Time:"), spaces)),
|
||||
separated_list1(spaces, number),
|
||||
),
|
||||
newline,
|
||||
preceded(
|
||||
tuple((tag("Distance:"), spaces)),
|
||||
separated_list1(spaces, number),
|
||||
),
|
||||
),
|
||||
multispace0,
|
||||
)(s)?;
|
||||
|
||||
let races = times
|
||||
.into_iter()
|
||||
.zip(distances)
|
||||
.map(|(time, distance)| Race { time, distance })
|
||||
.collect::<Vec<Race>>();
|
||||
|
||||
Ok((rest, Self { races }))
|
||||
}
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> Result<usize, String> {
|
||||
let (rest, racesheet) = RaceSheet::parse(input).map_err(|e| e.to_string())?;
|
||||
if !rest.is_empty() {
|
||||
eprintln!("parsing rest found: {rest}");
|
||||
panic!();
|
||||
}
|
||||
let result = racesheet
|
||||
.races
|
||||
.into_iter()
|
||||
.map(|race| {
|
||||
(0..=race.time)
|
||||
.filter(|hold_time| {
|
||||
let time_travelled = race.time - hold_time;
|
||||
let speed = hold_time;
|
||||
let distance_travelled = time_travelled * speed;
|
||||
|
||||
distance_travelled > race.distance
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.len()
|
||||
})
|
||||
.product();
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> Result<usize, String> {
|
||||
let (rest, racesheet) = RaceSheet::parse(input).map_err(|e| e.to_string())?;
|
||||
if !rest.is_empty() {
|
||||
eprintln!("parsing rest found: {rest}");
|
||||
panic!();
|
||||
}
|
||||
|
||||
let time = racesheet
|
||||
.races
|
||||
.iter()
|
||||
.map(|race| race.time.to_string())
|
||||
.collect::<String>()
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
||||
let distance = racesheet
|
||||
.races
|
||||
.iter()
|
||||
.map(|race| race.distance.to_string())
|
||||
.collect::<String>()
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
||||
let result = (0..=time)
|
||||
.filter(|hold_time| {
|
||||
let time_travelled = time - hold_time;
|
||||
let speed = hold_time;
|
||||
let distance_travelled = time_travelled * speed;
|
||||
|
||||
distance_travelled > distance
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.len();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let input = include_str!("../input");
|
||||
|
||||
let args = std::env::args().skip(1).collect::<Vec<String>>();
|
||||
let part = args[0].parse::<usize>().unwrap();
|
||||
|
||||
if part == 1 {
|
||||
println!("Part 1 : {}", part1(input)?);
|
||||
} else if part == 2 {
|
||||
println!("Part 2 : {}", part2(input)?);
|
||||
} else {
|
||||
panic!("unknown part")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
fn example_01() {
|
||||
let input = indoc! {"
|
||||
Time: 7 15 30
|
||||
Distance: 9 40 200
|
||||
"};
|
||||
|
||||
assert_eq!(part1(&input).unwrap(), 288);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_02() {
|
||||
let input = indoc! {"
|
||||
Time: 7 15 30
|
||||
Distance: 9 40 200
|
||||
"};
|
||||
|
||||
assert_eq!(part2(&input).unwrap(), 71503);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user