Skip to content

Commit

Permalink
Day 24: Never Tell Me The Odds (part 2)
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 26, 2023
1 parent d0e884e commit 6354573
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ Development occurs in language-specific directories:
|[Day21.hs](hs/src/Day21.hs)|[Day21.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day21.kt)|[day21.py](py/aoc2023/day21.py)|[day21.rs](rs/src/day21.rs)|
|[Day22.hs](hs/src/Day22.hs)|[Day22.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day22.kt)|[day22.py](py/aoc2023/day22.py)|[day22.rs](rs/src/day22.rs)|
||[Day23.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day23.kt)||[day23.rs](rs/src/day23.rs)|
|[Day24.hs](hs/src/Day24.hs) ½|[Day24.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day24.kt) ½|[day24.py](py/aoc2023/day24.py) ½|[day24.rs](rs/src/day24.rs) ½|
|[Day24.hs](hs/src/Day24.hs)|[Day24.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day24.kt) ½|[day24.py](py/aoc2023/day24.py) ½|[day24.rs](rs/src/day24.rs) ½|
|[Day25.hs](hs/src/Day25.hs)|[Day25.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day25.kt)|[day25.py](py/aoc2023/day25.py)|[day25.rs](rs/src/day25.rs)|
39 changes: 35 additions & 4 deletions hs/src/Day24.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@ import Control.Monad ((>=>), filterM, guard, when)
import Data.Char (isSpace)
import Data.Functor (($>))
import Data.List (tails)
import Data.Maybe (catMaybes)
import Data.Ratio ((%), denominator, numerator)
import Data.Text (Text)
import qualified Data.Text as T (dropWhile, lines, singleton, stripPrefix)
import Data.Text.Read (Reader)
import qualified Data.Text.Read as T (decimal, signed)
import Data.Text.Read (Reader)
import GHC.Exts (the)

parseLine :: (Num a) => Reader ((a, a, a), (a, a, a))
parseLine text = do
let decimal' = fmap (first fromIntegral) . T.signed T.decimal . T.dropWhile isSpace
skip token = maybe (Left $ "expected " ++ [token]) Right . T.stripPrefix (T.singleton token) . T.dropWhile isSpace
skip token = maybe (Left $ "expected " ++ [token]) Right .
T.stripPrefix (T.singleton token) . T.dropWhile isSpace
(x, text) <- decimal' text
(y, text) <- skip ',' text >>= decimal'
(z, text) <- skip ',' text >>= decimal'
Expand All @@ -41,7 +45,34 @@ part1 lo hi input = do
y = m0 * x + b0
length <$> filterM ok [(line0, line1) | line0:lines' <- tails lines, line1 <- lines']

part2 :: Text -> Either String Int
part2 :: (Integral a) => Text -> Either String a
part2 input = do
points <- mapM (readEntire parseLine) $ T.lines input
Left "unimplemented"
foldr (<>) (Left "no solution") $ do
((x0, y0, z0), (vx0, vy0, vz0)):points <- tails points
let offset ((x, y, z), (vx, vy, vz)) =
((x - x0, y - y0, z - z0), (vx - vx0, vy - vy0, vz - vz0))
((x1, y1, z1), (vx1, vy1, vz1)):points <- tails $ offset <$> points
let px1 = y1 * vz1 - z1 * vy1
py1 = z1 * vx1 - x1 * vz1
pz1 = x1 * vy1 - y1 * vx1
guard $ px1 /= 0 || py1 /= 0 || pz1 /= 0 -- 0 and 1 are skew
((x2, y2, z2), (vx2, vy2, vz2)):points <- tails points
let px2 = y2 * vz2 - z2 * vy2
py2 = z2 * vx2 - x2 * vz2
pz2 = x2 * vy2 - y2 * vx2
guard $ px2 /= 0 || py2 /= 0 || pz2 /= 0 -- 0 and 2 are skew
let mx = py1 * pz2 - pz1 * py2
my = pz1 * px2 - px1 * pz2
mz = px1 * py2 - py1 * px2
guard $ mx /= 0 || my /= 0 || mz /= 0 -- 1 and 2 are skew
let u1 = (y1 * vx1 - x1 * vy1) % (my * vx1 - mx * vy1)
u2 = (y2 * vx2 - x2 * vy2) % (my * vx2 - mx * vy2)
f _ _ _ 0 = Nothing
f m u p v = Just $ 1 % v * (m % 1 * u - p % 1)
t1 = the $ catMaybes [f mx u1 x1 vx1, f my u1 y1 vy1, f mz u1 z1 vz1]
t2 = the $ catMaybes [f mx u2 x2 vx2, f my u2 y2 vy2, f mz u2 z2 vz2]
let offset = (mx + my + mz) % 1 * (u1 * t2 - u2 * t1) / (t2 - t1)
pure $ if denominator offset /= 1
then Left "non-integral solution"
else Right $ x0 + y0 + z0 + numerator offset
4 changes: 2 additions & 2 deletions hs/test/Day24Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Day24Spec (spec) where
import Data.Text (Text)
import qualified Data.Text as T (unlines)
import Day24 (part1, part2)
import Test.Hspec (Spec, describe, it, shouldBe, xit)
import Test.Hspec (Spec, describe, it, shouldBe)

example :: Text
example = T.unlines
Expand All @@ -21,5 +21,5 @@ spec = do
it "examples" $ do
part1 7 27 example `shouldBe` Right 2
describe "part 2" $ do
xit "examples" $ do
it "examples" $ do
part2 example `shouldBe` Right 47

0 comments on commit 6354573

Please sign in to comment.