day 5
This commit is contained in:
@@ -19,6 +19,7 @@ import Data.String as String
|
||||
import Data.Tuple.Nested (type (/\), (/\))
|
||||
import Parsing (ParseError(..), fail, region, runParser) as Parse
|
||||
import Parsing (Parser)
|
||||
import Parsing.BigInt as Parse
|
||||
import Parsing.Combinators (sepBy) as Parse
|
||||
import Parsing.String (regex, string) as Parse
|
||||
import Partial.Unsafe (unsafeCrashWith, unsafePartial)
|
||||
@@ -40,7 +41,7 @@ parser =
|
||||
ctx :: forall a. String -> Parser String a -> Parser String a
|
||||
ctx c = Parse.region \(Parse.ParseError m pos) -> Parse.ParseError (c <> " > " <> m) pos
|
||||
|
||||
idRange = (/\) <$> (ctx "first id" $ bigint <* Parse.string "-") <*> (ctx "second id" bigint)
|
||||
idRange = (/\) <$> (ctx "first id" $ Parse.bigint <* Parse.string "-") <*> (ctx "second id" Parse.bigint)
|
||||
in
|
||||
List.toUnfoldable <$> Parse.sepBy (ctx "id range" idRange) (Parse.string ",")
|
||||
|
||||
@@ -71,19 +72,6 @@ isValid id =
|
||||
in
|
||||
len <= 1 || valid unit
|
||||
|
||||
bigint :: Parser String BigInt
|
||||
bigint = do
|
||||
section <- bigintRegex <|> Parse.fail "Expected Int"
|
||||
case BigInt.fromString section of
|
||||
Nothing -> Parse.fail "Expected Int"
|
||||
Just x -> pure x
|
||||
|
||||
bigintRegex :: Parser String String
|
||||
bigintRegex =
|
||||
either unsafeCrashWith identity $ Parse.regex pattern mempty
|
||||
where
|
||||
pattern = "[+-]?[0-9]+"
|
||||
|
||||
-- might use a small amount of memory lol
|
||||
bigintRange :: BigInt -> BigInt -> Array BigInt
|
||||
bigintRange a b = ST.run do
|
||||
|
||||
1227
src/Day5.purs
Normal file
1227
src/Day5.purs
Normal file
File diff suppressed because it is too large
Load Diff
106
src/Day5/Ingredient.purs
Normal file
106
src/Day5/Ingredient.purs
Normal file
@@ -0,0 +1,106 @@
|
||||
module Day5.Ingredient where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Rec.Class (Step(..), tailRec)
|
||||
import Data.Array as Array
|
||||
import Data.BigInt (BigInt)
|
||||
import Data.BigInt as BigInt
|
||||
import Data.Either (Either)
|
||||
import Data.Filterable (filter)
|
||||
import Data.Foldable (any, sum)
|
||||
import Data.FoldableWithIndex (foldlWithIndex)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.List as List
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Show.Generic (genericShow)
|
||||
import Data.Tuple.Nested (type (/\), (/\))
|
||||
import Effect.Console as Console
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import Parsing (ParseError, runParser) as Parse
|
||||
import Parsing (Parser)
|
||||
import Parsing.BigInt (bigint) as Parse
|
||||
import Parsing.Combinators (manyTill, sepBy) as Parse
|
||||
import Parsing.String (string) as Parse
|
||||
|
||||
type Id = BigInt
|
||||
type IdRange = BigInt /\ BigInt
|
||||
data Ingredients = Ingredients (Array IdRange) (Array Id)
|
||||
derive instance Generic Ingredients _
|
||||
instance Show Ingredients where show = genericShow
|
||||
|
||||
inSpec :: Ingredients -> Array Id
|
||||
inSpec (Ingredients spec ids) =
|
||||
let
|
||||
within id (from /\ to) = id >= from && id <= to
|
||||
inSpec' id = any (within id) spec
|
||||
in
|
||||
filter inSpec' ids
|
||||
|
||||
legalCount :: Ingredients -> BigInt
|
||||
legalCount (Ingredients spec _) =
|
||||
let
|
||||
specNonOverlap =
|
||||
let
|
||||
hasOverlap spec' = flip any spec' <<< idRangesOverlap
|
||||
|
||||
withoutOverlap spec' =
|
||||
let
|
||||
f x spec'' _ =
|
||||
case join $ Array.index spec'' x of
|
||||
Just a ->
|
||||
flip map spec'' \b ->
|
||||
b >>= idRangesNonOverlapping a
|
||||
Nothing ->
|
||||
spec''
|
||||
in
|
||||
Array.nub $ Array.catMaybes $ foldlWithIndex f (Just <$> spec') spec'
|
||||
|
||||
go spec' =
|
||||
if any (hasOverlap spec') spec' then
|
||||
Loop $ withoutOverlap spec'
|
||||
else
|
||||
Done spec'
|
||||
in
|
||||
tailRec go spec
|
||||
in
|
||||
sum (idRangeSize <$> specNonOverlap)
|
||||
|
||||
parseIngredients :: String -> Either Parse.ParseError Ingredients
|
||||
parseIngredients = flip Parse.runParser parser
|
||||
|
||||
parser :: Parser String Ingredients
|
||||
parser =
|
||||
let
|
||||
id = Parse.bigint
|
||||
idRange = (/\) <$> (id <* Parse.string "-") <*> id
|
||||
ltoa = List.toUnfoldable
|
||||
in
|
||||
Ingredients
|
||||
<$> (ltoa <$> Parse.manyTill (idRange <* Parse.string "\n") (Parse.string "\n"))
|
||||
<*> (ltoa <$> Parse.sepBy id (Parse.string "\n"))
|
||||
|
||||
idRangeSize :: IdRange -> BigInt
|
||||
idRangeSize (from /\ to) = one + to - from
|
||||
|
||||
idRangesNonOverlapping :: IdRange -> IdRange -> Maybe IdRange
|
||||
idRangesNonOverlapping a@(aa /\ ab) b@(ba /\ bb)
|
||||
| aa == ba && ab == bb = Just a
|
||||
-- `a` fully contains `b`
|
||||
| ba >= aa && bb <= ab = Nothing
|
||||
-- `a` contains `b`s first endpoint
|
||||
| ba >= aa && ba <= ab = Just ((ab + one) /\ bb)
|
||||
-- `a` contains `b`s last endpoint
|
||||
| bb >= ab && bb <= ab = Just (ba /\ (aa - one))
|
||||
| otherwise = Just b
|
||||
|
||||
idRangesOverlap :: IdRange -> IdRange -> Boolean
|
||||
idRangesOverlap (aa /\ ab) (ba /\ bb) = (aa /= ba || ab /= bb) && ((ba >= aa && ba <= ab) || (bb >= aa && bb <= ab))
|
||||
|
||||
tap :: forall a. String -> a -> a
|
||||
tap m a = unsafePerformEffect do
|
||||
Console.log m
|
||||
pure a
|
||||
|
||||
idRangeString :: IdRange -> String
|
||||
idRangeString (a /\ b) = "[" <> BigInt.toString a <> ", " <> BigInt.toString b <> "]"
|
||||
@@ -6,6 +6,7 @@ import Day1 as Day1
|
||||
import Day2 as Day2
|
||||
import Day3 as Day3
|
||||
import Day4 as Day4
|
||||
import Day5 as Day5
|
||||
import Effect (Effect)
|
||||
|
||||
main :: Effect Unit
|
||||
@@ -14,3 +15,4 @@ main = do
|
||||
when false $ Day2.main
|
||||
when false $ Day3.main
|
||||
when false $ Day4.main
|
||||
when true $ Day5.main
|
||||
|
||||
26
src/Parsing.BigInt.purs
Normal file
26
src/Parsing.BigInt.purs
Normal file
@@ -0,0 +1,26 @@
|
||||
module Parsing.BigInt where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Alt ((<|>))
|
||||
import Data.BigInt (BigInt)
|
||||
import Data.BigInt as BigInt
|
||||
import Data.Either (either)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Parsing (fail) as Parse
|
||||
import Parsing (Parser)
|
||||
import Parsing.String (regex) as Parse
|
||||
import Partial.Unsafe (unsafeCrashWith)
|
||||
|
||||
bigintRegex :: Parser String String
|
||||
bigintRegex =
|
||||
either unsafeCrashWith identity $ Parse.regex pattern mempty
|
||||
where
|
||||
pattern = "[+-]?[0-9]+"
|
||||
|
||||
bigint :: Parser String BigInt
|
||||
bigint = do
|
||||
section <- bigintRegex <|> Parse.fail "Expected Int"
|
||||
case BigInt.fromString section of
|
||||
Nothing -> Parse.fail "Expected Int"
|
||||
Just x -> pure x
|
||||
Reference in New Issue
Block a user