Skip to content

Instantly share code, notes, and snippets.

@icub3d
Created December 7, 2023 00:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save icub3d/7a17525f4185d7442c323209d7e5fe1e to your computer and use it in GitHub Desktop.
Save icub3d/7a17525f4185d7442c323209d7e5fe1e to your computer and use it in GitHub Desktop.
Advent of Code 2023 - Day 06
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()
);
}
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