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

View File

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

View File

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

View File

@ -1,25 +1,12 @@
module Puzzles.Day4 (puzzle) where module Puzzles.Day4 (puzzle) where
import Control.Applicative import Pre
import Control.Monad
import Data.Bifunctor
import Data.Foldable
import Data.Functor
import Data.List.Extra
import Data.Sequence (Seq)
import Data.Sequence qualified as Seq import Data.Sequence qualified as Seq
import Data.Stream.Infinite (Stream ((:>)))
import Data.Stream.Infinite qualified as S import Data.Stream.Infinite qualified as S
import Data.Text.Lazy qualified as TL 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 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 :: Puzzle
puzzle = puzzle =
@ -45,7 +32,7 @@ puzzle =
nFrames = if isRealData then 58 else 9 nFrames = if isRealData then 58 else 9
in ( [0 .. nFrames] <&> \n -> in ( [0 .. nFrames] <&> \n ->
goldenVsString (show n) (path <> "frames/" <> show 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 <> [ testCase "end" do
Just g <- Seq.lookup nFrames <$> frames Just g <- Seq.lookup nFrames <$> frames

View File

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

View File

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