Use custom prelude

This commit is contained in:
George Thomas 2025-12-08 12:48:49 +00:00
parent ef731df494
commit 371bddf748
9 changed files with 106 additions and 79 deletions

View File

@ -1,21 +1,15 @@
module Main (main) where
import Data.Bool
import Data.ByteString.Lazy qualified as BL
import Data.Functor
import Data.List.Extra
import Pre
import Data.Text.IO qualified as T
import Data.Text.Lazy.Encoding (encodeUtf8)
import Puzzle
import Data.Text.Lazy.Encoding qualified as TL
import Puzzles.Day1 qualified as Day1
import Puzzles.Day2 qualified as Day2
import Puzzles.Day3 qualified as Day3
import Puzzles.Day4 qualified as Day4
import Puzzles.Day5 qualified as Day5
import Test.Tasty
import Test.Tasty.Golden (goldenVsString)
import Test.Tasty.Ingredients.ConsoleReporter
import Text.Megaparsec hiding (Pos)
main :: IO ()
main =
@ -42,6 +36,6 @@ main =
testGroup pt $
( zip (map show [1 :: Int ..]) parts <&> \(n, pp) ->
goldenVsString n ("../outputs/" <> t <> "/" <> pt <> "/" <> n) $
encodeUtf8 . pp <$> input
TL.encodeUtf8 . pp <$> input
)
<> [testGroup "extra" $ extraTests isRealData ("../outputs/" <> t <> "/" <> pt <> "/extra/") input]

84
haskell/Pre.hs Normal file
View File

@ -0,0 +1,84 @@
{-# LANGUAGE PackageImports #-}
module Pre (
module BasePrelude,
module Control.Applicative,
module Control.Monad,
module Control.Monad.Loops,
module Control.Monad.State,
module Data.Bifunctor,
module Data.Bool,
module Data.Char,
module Data.Foldable,
module Data.Foldable1,
module Data.Functor,
module Data.List,
module Data.List.Extra,
module Data.List.NonEmpty,
module Data.Maybe,
module Data.Ord,
module Data.Sequence,
module Data.Stream.Infinite,
module Data.Text,
module Data.Text.Encoding,
module Data.Void,
module Data.Word,
module Linear,
module Test.Tasty,
module Test.Tasty.Golden,
module Test.Tasty.HUnit,
module Text.Megaparsec,
module Text.Megaparsec.Char,
module Text.Megaparsec.Char.Lexer,
Puzzle (..),
)
where
import "base" Prelude as BasePrelude hiding (
foldl1,
foldr1,
head,
init,
last,
maximum,
minimum,
tail,
unzip,
)
import Control.Applicative
import Control.Monad
import Control.Monad.Loops
import Control.Monad.State
import Data.Bifunctor
import Data.Bool
import Data.Char
import Data.Foldable hiding (foldl1, foldr1, maximum, maximumBy, minimum, minimumBy)
import Data.Foldable1
import Data.Functor
import Data.List (sortOn)
import Data.List.Extra (dropEnd, enumerate)
import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty, some1)
import Data.Maybe
import Data.Ord
import Data.Sequence (Seq)
import Data.Stream.Infinite (Stream ((:>)))
import Data.Text (Text)
import Data.Text.Encoding (encodeUtf8)
import Data.Text.Lazy qualified as TL
import Data.Void
import Data.Word
import Linear (V2 (..))
import Test.Tasty
import Test.Tasty.Golden hiding (Always)
import Test.Tasty.HUnit
import Text.Megaparsec hiding (Pos, State, Stream, many, some)
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer (decimal)
data Puzzle = forall input. Puzzle
{ number :: Word
, parser :: Parsec Void Text input
, parts :: [input -> TL.Text]
, extraTests :: Bool -> FilePath -> IO input -> [TestTree]
}

View File

@ -1,14 +0,0 @@
module Puzzle where
import Data.Text (Text)
import Data.Text.Lazy qualified as TL
import Data.Void
import Test.Tasty
import Text.Megaparsec
data Puzzle = forall input. Puzzle
{ number :: Word
, parser :: Parsec Void Text input
, parts :: [input -> TL.Text]
, extraTests :: Bool -> FilePath -> IO input -> [TestTree]
}

View File

@ -1,19 +1,14 @@
module Puzzles.Day1 (puzzle) where
import Control.Monad.State
import Data.Bifunctor
import Data.Functor
import Pre
import Data.Text.Lazy qualified as TL
import Puzzle
import Text.Megaparsec hiding (Pos)
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer qualified as Lex
puzzle :: Puzzle
puzzle =
Puzzle
{ number = 1
, parser = flip sepEndBy newline $ (,) <$> ((char 'L' $> L) <|> (char 'R' $> R)) <*> (Inc <$> Lex.decimal)
, parser = flip sepEndBy newline $ (,) <$> ((char 'L' $> L) <|> (char 'R' $> R)) <*> (Inc <$> decimal)
, parts =
[ TL.show
. sum

View File

@ -1,21 +1,15 @@
module Puzzles.Day2 (puzzle) where
import Control.Monad
import Data.Functor
import Data.Maybe
import Data.Text (Text)
import Pre
import Data.Text qualified as T
import Data.Text.Lazy qualified as TL
import Puzzle
import Text.Megaparsec
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer qualified as Lex
puzzle :: Puzzle
puzzle =
Puzzle
{ number = 2
, parser = (<* newline) $ flip sepBy (char ',') $ (,) <$> (Lex.decimal <* char '-') <*> Lex.decimal
, parser = (<* newline) $ flip sepBy (char ',') $ (,) <$> (decimal <* char '-') <*> decimal
, parts =
[ TL.show
. sum

View File

@ -1,17 +1,9 @@
module Puzzles.Day3 (puzzle) where
import Control.Monad.Loops (unfoldrM)
import Data.Char (digitToInt)
import Data.Foldable1
import Data.List.Extra (dropEnd)
import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty, some1)
import Pre
import Data.List.NonEmpty qualified as NE
import Data.Maybe
import Data.Text.Lazy qualified as TL
import Data.Word
import Puzzle
import Text.Megaparsec
import Text.Megaparsec.Char (digitChar, newline)
puzzle :: Puzzle
puzzle =
@ -38,7 +30,7 @@ newtype Battery = Battery Word8
-- maximal n-digit subsequence
-- returns `Nothing` if list isn't long enough (>= n)
maxBatteries :: Int -> Bank -> Maybe [Battery]
maxBatteries n0 (Bank bs0) = flip unfoldrM (n0, NE.toList bs0) \case
maxBatteries n0 (Bank bs0) = flip unfoldrM (n0, toList bs0) \case
(0, _) -> pure Nothing
(n, bs) -> do
(b, i) <- findMax <$> nonEmpty (dropEnd (n - 1) bs)

View File

@ -1,25 +1,12 @@
module Puzzles.Day4 (puzzle) where
import Control.Applicative
import Control.Monad
import Data.Bifunctor
import Data.Foldable
import Data.Functor
import Data.List.Extra
import Data.Sequence (Seq)
import Pre
import Data.Sequence qualified as Seq
import Data.Stream.Infinite (Stream ((:>)))
import Data.Stream.Infinite qualified as S
import Data.Text.Lazy qualified as TL
import Data.Text.Lazy.Encoding (encodeUtf8)
import Data.Text.Lazy.Encoding qualified as TL
import Data.Text.Lazy.IO qualified as TL
import Linear
import Puzzle
import Test.Tasty
import Test.Tasty.Golden
import Test.Tasty.HUnit
import Text.Megaparsec hiding (Stream, some)
import Text.Megaparsec.Char
puzzle :: Puzzle
puzzle =
@ -45,7 +32,7 @@ puzzle =
nFrames = if isRealData then 58 else 9
in ( [0 .. nFrames] <&> \n ->
goldenVsString (show n) (path <> "frames/" <> show n) $
encodeUtf8 . maybe "frame list too short!" drawGrid . Seq.lookup n <$> frames
TL.encodeUtf8 . maybe "frame list too short!" drawGrid . Seq.lookup n <$> frames
)
<> [ testCase "end" do
Just g <- Seq.lookup nFrames <$> frames

View File

@ -1,22 +1,17 @@
module Puzzles.Day5 (puzzle) where
import Control.Monad
import Data.List
import Data.Ord
import Pre
import Data.Text.Lazy qualified as TL
import Puzzle
import Text.Megaparsec hiding (some)
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer qualified as Lex
puzzle :: Puzzle
puzzle =
Puzzle
{ number = 5
, parser = do
ranges <- flip sepEndBy newline $ Range <$> Lex.decimal <* single '-' <*> Lex.decimal
ranges <- flip sepEndBy newline $ Range <$> decimal <* single '-' <*> decimal
void newline
vals <- sepEndBy Lex.decimal newline
vals <- sepEndBy decimal newline
pure (ranges, vals)
, parts =
[ \(ranges, vals) ->

View File

@ -9,7 +9,7 @@ executable aoc
main-is: Main.hs
hs-source-dirs: .
other-modules:
Puzzle
Pre
Puzzles.Day1
Puzzles.Day2
Puzzles.Day3