garnet/haskell/Pre.hs

159 lines
4.2 KiB
Haskell
Raw Normal View History

2025-12-08 12:48:49 +00:00
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-orphans #-}
2025-12-08 12:48:49 +00:00
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,
2025-12-08 22:48:29 +00:00
module Data.Function,
2025-12-08 12:48:49 +00:00
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,
2025-12-08 16:34:30 +00:00
module Data.Traversable,
2025-12-09 13:37:39 +00:00
module Data.Tuple.Extra,
2025-12-08 12:48:49 +00:00
module Data.Void,
module Data.Word,
module Linear,
2025-12-08 22:01:49 +00:00
module Safe,
module Test.Syd,
2025-12-08 12:48:49 +00:00
module Text.Megaparsec,
module Text.Megaparsec.Char,
module Text.Megaparsec.Char.Lexer,
Puzzle (..),
2025-12-08 23:38:48 +00:00
digit,
digitsToInt,
2025-12-09 00:02:54 +00:00
listIndex,
2025-12-09 10:47:32 +00:00
allUnorderedPairs,
2025-12-09 13:37:39 +00:00
adjacentPairs,
sortPair,
PuzzleParts,
applyPuzzleParts,
(/\),
(/\\),
nil,
2025-12-08 12:48:49 +00:00
)
where
import "base" Prelude as BasePrelude hiding (
foldl1,
foldr1,
head,
init,
last,
maximum,
minimum,
tail,
unzip,
2025-12-09 00:02:54 +00:00
(!!),
2025-12-08 12:48:49 +00:00
)
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
2025-12-08 22:48:29 +00:00
import Data.Function
2025-12-08 12:48:49 +00:00
import Data.Functor
import Data.Kind (Type)
import Data.List (List, sortOn, transpose)
2025-12-11 11:34:36 +00:00
import Data.List.Extra (dropEnd, enumerate, firstJust, notNull, splitOn)
2025-12-09 00:26:22 +00:00
import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty, some1, tail, tails)
2025-12-08 12:48:49 +00:00
import Data.Maybe
import Data.Ord
import Data.Sequence (Seq)
import Data.Stream.Infinite (Stream ((:>)))
import Data.Text (Text)
import Data.Text qualified as T
2025-12-08 12:48:49 +00:00
import Data.Text.Encoding (encodeUtf8)
2025-12-08 16:34:30 +00:00
import Data.Traversable
2025-12-09 13:37:39 +00:00
import Data.Tuple.Extra ((&&&))
2025-12-08 12:48:49 +00:00
import Data.Void
import Data.Word
import Linear (V2 (..))
2025-12-08 22:01:49 +00:00
import Safe
import Test.Syd
2025-12-08 12:48:49 +00:00
import Text.Megaparsec hiding (Pos, State, Stream, many, some)
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer (decimal)
data Puzzle = forall input outputs. Puzzle
2025-12-08 12:48:49 +00:00
{ number :: Word
, parser :: Bool -> Parsec Void Text input
, parts :: PuzzleParts input outputs
, extraTests :: Bool -> FilePath -> input -> HList outputs -> Spec
2025-12-08 12:48:49 +00:00
}
2025-12-08 23:38:48 +00:00
digit :: (Token s ~ Char, Num b, MonadParsec e s f) => f b
digit = fromIntegral . digitToInt <$> digitChar
digitsToInt :: (Integral a) => [a] -> Int
digitsToInt = foldl' (\acc d -> acc * 10 + fromIntegral d) 0
2025-12-09 00:02:54 +00:00
listIndex :: Int -> [a] -> Maybe a
listIndex n =
if n < 0
then const Nothing
else \case
[] -> Nothing
x : xs -> if n == 0 then Just x else listIndex (n - 1) xs
2025-12-09 10:47:32 +00:00
allUnorderedPairs :: Bool -> [a] -> [(a, a)]
allUnorderedPairs diagonals = concat . join (zipWith (flip $ map . (,)) . (bool tail toList diagonals) . tails)
2025-12-09 13:37:39 +00:00
adjacentPairs :: [b] -> [(b, b)]
adjacentPairs = \case
[] -> []
x : xs -> zip (x : xs) xs
sortPair :: (Ord a) => (a, a) -> (a, a)
sortPair (a, b) = if a <= b then (a, b) else (b, a)
2025-12-09 16:47:12 +00:00
infixr 9 /\\
(/\\) :: (input -> output, output -> Text) -> PuzzleParts input outputs -> PuzzleParts input (output : outputs)
(/\\) = uncurry PuzzlePartsCons
infixr 9 /\
(/\) :: (Show output) => (input -> output) -> PuzzleParts input outputs -> PuzzleParts input (output : outputs)
(/\) = flip PuzzlePartsCons T.show
nil :: PuzzleParts input '[]
nil = PuzzlePartsNil
data PuzzleParts (input :: Type) (outputs :: List Type) :: Type where
PuzzlePartsNil :: PuzzleParts input '[]
PuzzlePartsCons ::
(input -> output) ->
(output -> Text) ->
PuzzleParts input outputs ->
PuzzleParts input (output ': outputs)
applyPuzzleParts ::
forall input outputs.
input ->
PuzzleParts input outputs ->
(HList outputs, [Text])
applyPuzzleParts e = \case
PuzzlePartsNil -> (HNil, [])
PuzzlePartsCons f o ps -> let r = f e in bimap (HCons r) (o r :) $ applyPuzzleParts e ps
2026-01-01 13:24:49 +00:00
instance Semigroup (TestDefM a b ()) where
(<>) = (>>)
2026-01-01 13:24:49 +00:00
instance Monoid (TestDefM a b ()) where
mempty = pure ()