aboutsummaryrefslogtreecommitdiff
path: root/2023/24-Never_Tell_Me_The_Odds/first.hs
diff options
context:
space:
mode:
Diffstat (limited to '2023/24-Never_Tell_Me_The_Odds/first.hs')
-rw-r--r--2023/24-Never_Tell_Me_The_Odds/first.hs81
1 files changed, 81 insertions, 0 deletions
diff --git a/2023/24-Never_Tell_Me_The_Odds/first.hs b/2023/24-Never_Tell_Me_The_Odds/first.hs
new file mode 100644
index 0000000..0964c12
--- /dev/null
+++ b/2023/24-Never_Tell_Me_The_Odds/first.hs
@@ -0,0 +1,81 @@
+-- requires cabal install --lib megaparsec parser-combinators heap vector
+module Main (main) where
+
+import Control.Applicative.Permutations
+import Control.Monad (void, when)
+import qualified Data.Char as C
+import Data.Either
+import Data.Functor
+import qualified Data.Heap as H
+import qualified Data.List as L
+import qualified Data.Map as M
+import Data.Maybe
+import Data.Ratio
+import qualified Data.Set as S
+import qualified Data.Vector as V
+import qualified Data.Vector.Unboxed as VU
+import Data.Void (Void)
+import Text.Megaparsec
+import Text.Megaparsec.Char
+
+import Debug.Trace
+
+exampleExpectedOutput = 2
+
+type Hail = (Rational, Rational, Rational, Rational, Rational, Rational)
+type Input = [Hail]
+
+type Parser = Parsec Void String
+
+parseNumber :: Parser Integer
+parseNumber = read <$> some (char '-' <|> digitChar) <* optional (char ',') <* optional hspace <* optional (char '@' <* hspace)
+
+parseHail :: Parser Hail
+parseHail = (,,,,,) <$> (fromInteger <$> parseNumber)
+ <*> (fromInteger <$> parseNumber)
+ <*> (fromInteger <$> parseNumber)
+ <*> (fromInteger <$> parseNumber)
+ <*> (fromInteger <$> parseNumber)
+ <*> (fromInteger <$> parseNumber)
+
+parseInput' :: Parser Input
+parseInput' = some (parseHail <* eol) <* eof
+
+parseInput :: String -> IO Input
+parseInput filename = do
+ input <- readFile filename
+ case runParser parseInput' filename input of
+ Left bundle -> error $ errorBundlePretty bundle
+ Right input' -> return input'
+
+compute :: Rational -> Rational -> Input -> Int
+compute mini maxi = compute'
+ where
+ compute' :: Input -> Int
+ compute' (_:[]) = 0
+ compute' ((x1, y1, _, a1, b1, _):hs) = L.foldl' computeOne 0 hs + compute' hs
+ where
+ (x2, y2) = (x1 + a1, y1 + b1)
+ computeOne :: Int -> Hail -> Int
+ computeOne acc (x3, y3, _, a3, b3, _) | valid = acc + 1
+ | otherwise = acc
+ where
+ valid | denominator == 0 || t < 0 || u < 0 = False
+ | x >= mini && x <= maxi && y >= mini && y <= maxi = True
+ | otherwise = False
+ (x4, y4) = (x3 + a3, y3 + b3)
+ denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
+ a = x1 * y2 - y1 * x2
+ b = x3 * y4 - y3 * x4
+ numeratorX = b * a1 - a * a3
+ numeratorY = b * b1 - a * b3
+ (x, y) = (numeratorX / denominator, numeratorY / denominator)
+ (t, u) = ((x - x1) / a1, (x - x3) / a3)
+
+main :: IO ()
+main = do
+ example <- parseInput "example"
+ let exampleOutput = compute 7 27 example
+ when (exampleOutput /= exampleExpectedOutput) (error $ "example failed: got " ++ show exampleOutput ++ " instead of " ++ show exampleExpectedOutput)
+ input <- parseInput "input"
+ print $ compute 200000000000000 400000000000000 input