Created
December 7, 2023 00:23
-
-
Save icub3d/7a17525f4185d7442c323209d7e5fe1e to your computer and use it in GitHub Desktop.
Advent of Code 2023 - Day 06
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use nom::{ | |
bytes::complete::tag, | |
character::complete::{digit1, space1}, | |
multi::separated_list0, | |
sequence::tuple, | |
IResult, | |
}; | |
#[derive(Debug)] | |
struct Race { | |
time: usize, | |
distance: usize, | |
} | |
impl Race { | |
fn new(time: usize, distance: usize) -> Self { | |
Self { time, distance } | |
} | |
fn winners(&self) -> usize { | |
let mut winners = 0; | |
for i in 0..self.time { | |
let distance = (self.time - i) * i; | |
if distance > self.distance { | |
winners += 1; | |
} | |
} | |
winners | |
} | |
fn winners_faster(&self, counter: &mut usize) -> usize { | |
let mut begin = 0; | |
for i in 0..self.time { | |
*counter += 1; | |
let distance = (self.time - i) * i; | |
if distance > self.distance { | |
begin = i; | |
break; | |
} | |
} | |
let mut end = 0; | |
for i in (begin..self.time).rev() { | |
*counter += 1; | |
let distance = (self.time - i) * i; | |
if distance > self.distance { | |
end = i; | |
break; | |
} | |
} | |
end - begin + 1 | |
} | |
} | |
fn parse_p2(input: &str) -> IResult<&str, Race> { | |
let (input, (_, time, _)) = tuple((tag("Time:"), digit1, tag("\n")))(input)?; | |
let (input, (_, distance)) = tuple((tag("Distance:"), digit1))(input)?; | |
Ok(( | |
input, | |
Race::new( | |
time.parse::<usize>().unwrap(), | |
distance.parse::<usize>().unwrap(), | |
), | |
)) | |
} | |
fn parse(input: &str) -> IResult<&str, Vec<Race>> { | |
let (input, (_, _, times, _)) = tuple(( | |
tag("Time:"), | |
space1, | |
separated_list0(space1, digit1), | |
tag("\n"), | |
))(input)?; | |
let (input, (_, _, distances)) = | |
tuple((tag("Distance:"), space1, separated_list0(space1, digit1)))(input)?; | |
Ok(( | |
input, | |
times | |
.iter() | |
.map(|s| s.parse::<usize>().unwrap()) | |
.zip(distances.iter().map(|s| s.parse::<usize>().unwrap())) | |
.map(|(time, distance)| Race::new(time, distance)) | |
.collect(), | |
)) | |
} | |
fn main() { | |
let input = std::fs::read_to_string("input").unwrap(); | |
let races = parse(&input).unwrap().1; | |
// Part 1 | |
let now = std::time::Instant::now(); | |
let p1 = races.iter().map(|r| r.winners()).product::<usize>(); | |
println!( | |
"p1: {} ({}) ({:?}))", | |
p1, | |
races.iter().map(|r| r.time).sum::<usize>(), | |
now.elapsed() | |
); | |
let now = std::time::Instant::now(); | |
let mut counter = 0; | |
let p1_faster = races | |
.iter() | |
.map(|r| r.winners_faster(&mut counter)) | |
.product::<usize>(); | |
println!( | |
"p1_faster: {} ({}) ({:?})", | |
p1_faster, | |
counter, | |
now.elapsed() | |
); | |
// Part 2 | |
let p2_input = str::replace(&input, " ", ""); | |
let race = parse_p2(&p2_input).unwrap().1; | |
let now = std::time::Instant::now(); | |
let p2 = race.winners(); | |
println!("p2: {} ({}) ({:?})", p2, race.time, now.elapsed()); | |
let now = std::time::Instant::now(); | |
let mut counter = 0; | |
let p2_faster = race.winners_faster(&mut counter); | |
println!( | |
"p2_faster: {} ({}) ({:?})", | |
p2_faster, | |
counter, | |
now.elapsed() | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.Text.Lazy (pack, replace, unpack) | |
import qualified Text.Parsec as Parsec | |
parseInputLine :: Parsec.Parsec String () [Int] | |
parseInputLine = do | |
Parsec.many1 Parsec.alphaNum | |
Parsec.char ':' | |
Parsec.spaces | |
ints <- Parsec.many1 Parsec.digit `Parsec.sepBy` Parsec.spaces | |
return $ map read ints | |
parser :: String -> [Int] | |
parser input = case Parsec.parse parseInputLine "" input of | |
Left e -> error $ show e | |
Right r -> r | |
calcDistance :: Int -> Int -> Int | |
calcDistance total time = (total - time) * time | |
winner :: Int -> Int -> Int -> Int | |
winner distance totalTime time = if calcDistance totalTime time > distance then 1 else 0 | |
winners :: (Int, Int) -> Int | |
winners (time, distance) = sum $ map (winner distance time) [0 .. time] | |
winnerTo :: Int -> Int -> Int | |
winnerTo time distance = length $ takeWhile (< distance) $ map (calcDistance time) [0 ..] | |
winnerFrom :: Int -> Int -> Int | |
winnerFrom time distance = length $ takeWhile (< distance) $ map (calcDistance time) (reverse [0 .. time]) | |
winnersFaster :: (Int, Int) -> Int | |
winnersFaster (time, distance) = time - (winnerTo time distance + winnerFrom time distance) + 1 | |
main :: IO () | |
main = do | |
input <- readFile "input" | |
l <- return $ map parser $ lines input | |
let zipped = zip (head l) (last l) | |
putStrLn $ "p1: " ++ show (product $ map winners zipped) | |
putStrLn $ "p1 (faster): " ++ show (product $ map winnersFaster zipped) | |
let p2Input = unpack $ replace (pack " ") (pack "") (pack input) | |
l <- return $ map parser $ lines p2Input | |
let zipped = zip (head l) (last l) | |
putStrLn $ "p2: " ++ show (product $ map winnersFaster zipped) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment