diff --git a/adventofcode.cabal b/adventofcode.cabal index dc3ca92..7e3632e 100644 --- a/adventofcode.cabal +++ b/adventofcode.cabal @@ -2,7 +2,7 @@ -- -- see: https://github.com/sol/hpack -- --- hash: ea04591b11d049b24eb195b76d379646dcfbc1c5bf4ee126d894309a7a7a3708 +-- hash: c000ca3243983619481d89396b163acf8fb77f12488850d0f27e659ab2f1bd40 name: adventofcode version: 0.1.0.0 @@ -44,6 +44,7 @@ library Day12 Day13 Day14 + Day15 other-modules: Paths_adventofcode build-depends: diff --git a/app/Main.hs b/app/Main.hs index 97c2e8c..65adfb3 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -22,6 +22,7 @@ import qualified Day11 import qualified Day12 import qualified Day13 import qualified Day14 +import qualified Day15 showSol :: [Char] -> Doc -> IO () showSol txt d = putText . toS . render $ @@ -49,6 +50,7 @@ solutions = Map.fromList [(["01"], day01) ,(["12"], day12) ,(["13"], day13) ,(["14"], day14) + ,(["15"], day15) ] @@ -173,3 +175,11 @@ day14 = do showSol "Solution 1" (int (fromMaybe 0 sol1)) sol2 <- Day14.solution2 Day14.input showSol "Solution 2" (int sol2) + +day15 :: IO () +day15 = do + putText "Day 15:" + let sol1 = Day15.solution1 Day15.input + showSol "Solution 1" (int sol1) + let sol2 = Day15.solution2 Day15.input + showSol "Solution 1" (int sol2) diff --git a/package.yaml b/package.yaml index af95cb9..80a495c 100644 --- a/package.yaml +++ b/package.yaml @@ -27,6 +27,7 @@ library: - Day12 - Day13 - Day14 + - Day15 dependencies: - base >=4.7 && <5 - protolude diff --git a/src/Day15.hs b/src/Day15.hs new file mode 100644 index 0000000..2b6fd52 --- /dev/null +++ b/src/Day15.hs @@ -0,0 +1,88 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-| +description: + +--- Day 15: Dueling Generators --- + +Here, you encounter a pair of dueling generators. The generators, called +generator A and generator B, are trying to agree on a sequence of numbers. +However, one of them is malfunctioning, and so the sequences don't always match. + +As they do this, a judge waits for each of them to generate its next value, +compares the lowest 16 bits of both values, and keeps track of the number of +times those parts of the values match. + +The generators both work on the same principle. To create its next value, a +generator will take the previous value it produced, multiply it by a factor +(generator A uses 16807; generator B uses 48271), and then keep the remainder of +dividing that resulting product by 2147483647. That final remainder is the value +it produces next. + +To calculate each generator's first value, it instead uses a specific starting +value as its "previous value" (as listed in your puzzle input). + +For example, suppose that for starting values, generator A uses 65, while +generator B uses 8921. Then, the first five pairs of generated values are: + +--Gen. A-- --Gen. B-- + 1092455 430625591 +1181022009 1233683848 + 245556042 1431495498 +1744312007 137874439 +1352636452 285222916 +In binary, these pairs are (with generator A's value first in each pair): + +00000000000100001010101101100111 +00011001101010101101001100110111 + +01000110011001001111011100111001 +01001001100010001000010110001000 + +00001110101000101110001101001010 +01010101010100101110001101001010 + +01100111111110000001011011000111 +00001000001101111100110000000111 + +01010000100111111001100000100100 +00010001000000000010100000000100 + +Here, you can see that the lowest (here, rightmost) 16 bits of the third value +match: 1110001101001010. Because of this one match, after processing these five +pairs, the judge would have added only 1 to its total. + +To get a significant sample, the judge would like to consider 40 million pairs. +(In the example above, the judge would eventually find a total of 588 pairs that +match in their lowest 16 bits.) + +After 40 million pairs, what is the judge's final count? + +|-} +module Day15 where + +import Protolude + +input :: (Int64,Int64) +input = (618,814) + +testInput :: (Int64,Int64) +testInput = (65,8921) + +generatorA :: Int64 -> Int64 +generatorA x = x * 16807 `rem` 2147483647 + +generatorB :: Int64 -> Int64 +generatorB x = x * 48271 `rem` 2147483647 + +toInt16 :: Int64 -> Int16 +toInt16 = fromIntegral + +solution1 input = + let lst1 = map toInt16 $ iterate generatorA (fst input) + lst2 = map toInt16 $ iterate generatorB (snd input) + in length (filter (uncurry (==)) (take 40000000 (zip lst1 lst2))) + +solution2 input = + let lst1 = map toInt16 . filter ((== 0) . (`rem` 4)) $ iterate generatorA (fst input) + lst2 = map toInt16 . filter ((== 0) . (`rem` 8)) $ iterate generatorB (snd input) + in length (filter (uncurry (==)) (take 5000000 (zip lst1 lst2))) diff --git a/test/Spec.hs b/test/Spec.hs index ac525d5..3695102 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -19,6 +19,7 @@ import qualified Day11 import qualified Day12 import qualified Day13 import qualified Day14 +import qualified Day15 main :: IO () main = defaultMain $ @@ -37,6 +38,7 @@ main = defaultMain $ , testDay12 , testDay13 , testDay14 + , testDay15 ] testDay01 = @@ -259,3 +261,15 @@ testDay14 = (assertFailure "Should be 1242 groups") ] ] + +testDay15 = + testGroup "Day 15" + [ testGroup "Solution 1" + [ testCase "Example" $ + Day15.solution1 Day15.testInput @?= 588 + ] + , testGroup "Solution 2" + [ testCase "Example" $ + Day15.solution2 Day15.testInput @?= 309 + ] + ]