Initial commit
commit
513641d092
@ -0,0 +1,2 @@
|
||||
SESSION=YOUR_SESSION_COOKIE
|
||||
YEAR=2022
|
@ -0,0 +1,4 @@
|
||||
dist*
|
||||
.env
|
||||
.inputs/
|
||||
data/
|
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2022, IndecisionTree
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,95 @@
|
||||
cabal-version: 3.0
|
||||
name: advent-of-haskell
|
||||
version: 0.1.0.0
|
||||
synopsis: Framework for AoC
|
||||
description: Run, submit, test, and benchmark Advent of Code solutions.
|
||||
license: BSD-3-Clause
|
||||
license-file: LICENSE
|
||||
author: IndecisionTree
|
||||
build-type: Simple
|
||||
|
||||
common common
|
||||
default-language: GHC2021
|
||||
ghc-options: -Wall
|
||||
default-extensions: RecordWildCards
|
||||
|
||||
executable runner
|
||||
import: common
|
||||
main-is: Main.hs
|
||||
build-depends:
|
||||
, aoc
|
||||
, base ^>=4.16.3.0
|
||||
, containers ^>=0.6.5
|
||||
, directory ^>=1.3.6
|
||||
, dotenv ^>=0.9.0
|
||||
, filepath ^>=1.4.2
|
||||
, megaparsec ^>=9.3.0
|
||||
, optparse-applicative ^>=0.17.0
|
||||
, solutions
|
||||
, tasty ^>=1.4.2
|
||||
, tasty-bench ^>=0.3.2
|
||||
, tasty-hunit ^>=0.10.0
|
||||
, text ^>=2.0
|
||||
|
||||
other-modules: Tests
|
||||
hs-source-dirs: runner
|
||||
|
||||
library aoc
|
||||
import: common
|
||||
exposed-modules: AOC
|
||||
other-modules:
|
||||
AOC.API
|
||||
AOC.Types
|
||||
|
||||
build-depends:
|
||||
, base ^>=4.16.3.0
|
||||
, bytestring ^>=0.11.3
|
||||
, http-api-data ^>=0.5
|
||||
, http-client ^>=0.7.13
|
||||
, http-client-tls ^>=0.3.6
|
||||
, http-media ^>=0.8.0
|
||||
, servant ^>=0.19.1
|
||||
, servant-client ^>=0.19
|
||||
, text ^>=2.0
|
||||
, time ^>=1.11.1
|
||||
|
||||
hs-source-dirs: aoc
|
||||
|
||||
library solutions
|
||||
import: common
|
||||
|
||||
-- cabal-fmt: expand solutions
|
||||
exposed-modules:
|
||||
Days.Day01
|
||||
Days.Day02
|
||||
Days.Day03
|
||||
Days.Day04
|
||||
Days.Day05
|
||||
Days.Day06
|
||||
Days.Day07
|
||||
Days.Day08
|
||||
Days.Day09
|
||||
Days.Day10
|
||||
Days.Day11
|
||||
Days.Day12
|
||||
Days.Day13
|
||||
Days.Day14
|
||||
Days.Day15
|
||||
Days.Day16
|
||||
Days.Day17
|
||||
Days.Day18
|
||||
Days.Day19
|
||||
Days.Day20
|
||||
Days.Day21
|
||||
Days.Day22
|
||||
Days.Day23
|
||||
Days.Day24
|
||||
Solutions
|
||||
|
||||
build-depends:
|
||||
, aoc
|
||||
, base ^>=4.16.3.0
|
||||
, containers ^>=0.6.5
|
||||
, text ^>=2.0
|
||||
|
||||
hs-source-dirs: solutions
|
@ -0,0 +1,7 @@
|
||||
module AOC (
|
||||
module AOC.Types,
|
||||
mkAocClient
|
||||
) where
|
||||
|
||||
import AOC.Types
|
||||
import AOC.API
|
@ -0,0 +1,101 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
module AOC.API (
|
||||
mkAocClient,
|
||||
) where
|
||||
|
||||
import AOC.Types
|
||||
import Control.Monad ((>=>))
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.Proxy (Proxy (..))
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.Encoding qualified as T
|
||||
import Data.Time.Clock (addUTCTime, getCurrentTime)
|
||||
import GHC.Conc (atomically, newTVar)
|
||||
import Network.HTTP.Client (Cookie (..), createCookieJar)
|
||||
import Network.HTTP.Client.TLS (newTlsManager)
|
||||
import Network.HTTP.Media ((//), (/:))
|
||||
import Servant.API
|
||||
import Servant.Client hiding ((//), (/:))
|
||||
|
||||
mkAocClient :: String -> Int -> Int -> IO (IO T.Text, Submission -> IO Answer)
|
||||
mkAocClient session year day = do
|
||||
env <- mkAocEnv session
|
||||
let aocInput :<|> aocSubmit = aocClient year day
|
||||
f = flip runClientM env >=> pure . either (error . show) id
|
||||
aocInput' = f aocInput
|
||||
aocSubmit' = f . aocSubmit
|
||||
return (aocInput', aocSubmit')
|
||||
|
||||
mkAocEnv :: String -> IO ClientEnv
|
||||
mkAocEnv session = do
|
||||
current <- getCurrentTime
|
||||
manager <- newTlsManager
|
||||
let
|
||||
base = BaseUrl Https "adventofcode.com" 443 ""
|
||||
env = mkClientEnv manager base
|
||||
year = 60 * 60 * 24 * 365
|
||||
expiry = addUTCTime year current
|
||||
cookie =
|
||||
Cookie
|
||||
{ cookie_name = "session",
|
||||
cookie_value = T.encodeUtf8 . T.pack $ session,
|
||||
cookie_expiry_time = expiry,
|
||||
cookie_domain = T.encodeUtf8 . T.pack $ baseUrlHost base,
|
||||
cookie_path = "/",
|
||||
cookie_creation_time = current,
|
||||
cookie_last_access_time = current,
|
||||
cookie_persistent = True,
|
||||
cookie_host_only = True,
|
||||
cookie_secure_only = True,
|
||||
cookie_http_only = True
|
||||
}
|
||||
cookies <- atomically $ newTVar (createCookieJar [cookie])
|
||||
return $ env {cookieJar = Just cookies}
|
||||
|
||||
aocClient :: Int -> Int -> (ClientM T.Text :<|> (Submission -> ClientM Answer))
|
||||
aocClient = client (Proxy @API)
|
||||
|
||||
type API =
|
||||
Capture "year" Int :>
|
||||
("day" :> Capture "day" Int :>
|
||||
(
|
||||
-- GET /:year/day/:day/input
|
||||
("input" :> Get '[RawPlainText] T.Text) :<|>
|
||||
-- POST /:year/day/:day/answer level=<1|2>&answer=_
|
||||
("answer" :> ReqBody '[FormUrlEncoded] Submission :> Post '[HTML] Answer)
|
||||
)
|
||||
)
|
||||
|
||||
-- This is silly: https://github.com/haskell-servant/servant/issues/1002
|
||||
data RawPlainText
|
||||
|
||||
instance Accept RawPlainText where
|
||||
contentType _ = "text" // "plain"
|
||||
|
||||
instance MimeUnrender RawPlainText T.Text where
|
||||
mimeUnrender _ = Right . T.decodeUtf8 . BS.toStrict
|
||||
|
||||
-- TODO implement marshalling from HTML to 'Day', 'Year', and 'Answer'
|
||||
-- types which extracts yearly calendars, day prompts, and
|
||||
-- pre-existing correct answer submissions via scraping the received
|
||||
-- HTML.
|
||||
|
||||
data HTML
|
||||
|
||||
instance Accept HTML where
|
||||
contentType _ = "text" // "html" /: ("charset", "utf-8")
|
||||
|
||||
data Answer = Correct | Low | High | Empty
|
||||
|
||||
instance MimeUnrender HTML Answer where
|
||||
mimeUnrender _ bs
|
||||
| "correct" `BS.isInfixOf` bs' = Right Correct
|
||||
| "low" `BS.isInfixOf` bs' = Right Low
|
||||
| "high" `BS.isInfixOf` bs' = Right High
|
||||
| "provide an answer" `BS.isInfixOf` bs' = Right Empty
|
||||
| otherwise = Left "Unknown answer response"
|
||||
where
|
||||
bs' = BS.toStrict bs
|
@ -0,0 +1,19 @@
|
||||
{-# language GADTs #-}
|
||||
module AOC.Types (
|
||||
Solution (..),
|
||||
Submission (..)
|
||||
) where
|
||||
|
||||
import Data.Text (Text)
|
||||
import GHC.Generics (Generic)
|
||||
import Web.Internal.FormUrlEncoded (ToForm)
|
||||
|
||||
data Solution where
|
||||
Solution :: Show b => (Text -> a) -> (a -> b) -> (a -> b) -> Solution
|
||||
|
||||
data Submission = Submission {
|
||||
part :: Int,
|
||||
answer :: String
|
||||
} deriving (Generic)
|
||||
|
||||
instance ToForm Submission
|
@ -0,0 +1,3 @@
|
||||
with-compiler: ghc-9.2.4
|
||||
|
||||
packages: .
|
@ -0,0 +1,112 @@
|
||||
module Main where
|
||||
|
||||
import AOC (Solution (..), mkAocClient)
|
||||
import Configuration.Dotenv (defaultConfig, loadFile)
|
||||
import Control.Exception (IOException, catch)
|
||||
import Control.Monad (when)
|
||||
import Data.Functor (void)
|
||||
import Data.IntMap.Strict qualified as M
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.IO qualified as T
|
||||
import Options.Applicative
|
||||
import Solutions (solutions)
|
||||
import System.Directory (createDirectoryIfMissing)
|
||||
import System.Environment (getEnv)
|
||||
import Tests (test)
|
||||
import Text.Printf (printf)
|
||||
|
||||
-- | CLI Options
|
||||
data Options = Option
|
||||
{ _command :: Action,
|
||||
_day :: Int,
|
||||
_part :: Maybe Int
|
||||
}
|
||||
|
||||
-- | CLI Commands
|
||||
data Action = Run | Test | Bench | Submit
|
||||
deriving (Show)
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
void $ loadFile defaultConfig
|
||||
|
||||
session <- getEnv "SESSION"
|
||||
year <- read <$> getEnv "YEAR"
|
||||
|
||||
Option {..} <- customExecParser (prefs showHelpOnEmpty) opts
|
||||
|
||||
when (_day < 1 || _day > 24) $ do
|
||||
fail $ printf "Day '%d' is out of range (1-24)" _day
|
||||
|
||||
(aocInput, aocSubmit) <- mkAocClient session year _day
|
||||
|
||||
input <- getPuzzleInput _day aocInput
|
||||
let day = solutions M.! _day
|
||||
|
||||
case _command of
|
||||
Run -> putStr $ run day _part input
|
||||
Test -> test day _day _part
|
||||
a -> fail $ "Unimplemented: " ++ show a
|
||||
|
||||
-- | Retrieve puzzle input for a given day from a file. If no file is
|
||||
-- found, hit the api.
|
||||
getPuzzleInput :: Int -> IO T.Text -> IO T.Text
|
||||
getPuzzleInput day aocInput =
|
||||
T.readFile fp `catch` \(_ :: IOException) -> fetchInput
|
||||
where
|
||||
fp = printf ".inputs/%d.txt" day
|
||||
|
||||
fetchInput = do
|
||||
input <- aocInput
|
||||
createDirectoryIfMissing True ".inputs"
|
||||
T.writeFile fp input
|
||||
return input
|
||||
|
||||
-- | Run solution (optionally just part) on input and return the
|
||||
-- result as a string ready for submission
|
||||
run :: Solution -> Maybe Int -> T.Text -> String
|
||||
run (Solution pInput part1 part2) part input =
|
||||
case part of
|
||||
Nothing -> printf "Part 1: %s\nPart 2: %s\n" part1' part2'
|
||||
Just n -> printf "Part %d: %s\n" n $ if n == 1 then part1' else part2'
|
||||
where
|
||||
parsed = pInput input
|
||||
part1' = show $ part1 parsed
|
||||
part2' = show $ part2 parsed
|
||||
|
||||
-- | CLI parser
|
||||
opts :: ParserInfo Options
|
||||
opts =
|
||||
info
|
||||
(commands <**> helper)
|
||||
( fullDesc
|
||||
<> progDesc "Run, benchmark, test, or submit an AOC day"
|
||||
<> header "runner - an AOC solution runner"
|
||||
)
|
||||
where
|
||||
commands = subparser $ runCmd <> testCmd <> benchCmd <> submitCmd
|
||||
runCmd =
|
||||
mkCmd
|
||||
"run"
|
||||
(Option Run <$> day <*> optional part)
|
||||
"Run a given day, optionally specifying which part"
|
||||
testCmd =
|
||||
mkCmd
|
||||
"test"
|
||||
(Option Test <$> day <*> optional part)
|
||||
"Test a given day, optionally specifying which part"
|
||||
benchCmd =
|
||||
mkCmd
|
||||
"bench"
|
||||
(Option Bench <$> day <*> optional part)
|
||||
"Benchmark a given day, optionally specifying which part"
|
||||
submitCmd =
|
||||
mkCmd
|
||||
"submit"
|
||||
(Option Submit <$> day <*> (Just <$> part))
|
||||
"Run and submit the answer to a given day and part"
|
||||
|
||||
day = argument auto (metavar "DAY")
|
||||
part = argument auto (metavar "PART")
|
||||
|
||||
mkCmd cmd f desc = command cmd (info f (progDesc desc))
|
@ -0,0 +1,77 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Tests (test) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.IO qualified as T
|
||||
import Data.Void (Void)
|
||||
import System.FilePath ((<.>), (</>))
|
||||
import Test.Tasty (TestTree, testGroup)
|
||||
import Test.Tasty.HUnit (testCase, (@=?))
|
||||
import Test.Tasty.Ingredients (tryIngredients)
|
||||
import Test.Tasty.Ingredients.Basic (consoleTestReporter)
|
||||
import Text.Megaparsec
|
||||
import Text.Megaparsec.Char (newline, space)
|
||||
import Text.Megaparsec.Char.Lexer qualified as L
|
||||
|
||||
data TestInput = TestInput
|
||||
{ _testName :: T.Text,
|
||||
_testInput :: T.Text,
|
||||
_testExpected :: T.Text
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
type Parser = Parsec Void T.Text
|
||||
|
||||
-- | Test solution via tests in 'data/examples/(Day #)/part{1,2}.txt'
|
||||
test :: Solution -> Int -> Maybe Int -> IO ()
|
||||
test (Solution pInput part1 part2) day part = do
|
||||
p1 <- T.readFile $ "data" </> "examples" </> show day </> "part1" <.> "txt"
|
||||
p2 <- T.readFile $ "data" </> "examples" </> show day </> "part2" <.> "txt"
|
||||
|
||||
let p1Tests =
|
||||
testGroup "Part 1"
|
||||
. fmap (mkTest pInput part1)
|
||||
. either (error . errorBundlePretty) id
|
||||
. parse pTests "part1.txt"
|
||||
$ p1
|
||||
p2Tests =
|
||||
testGroup "Part 2"
|
||||
. fmap (mkTest pInput part2)
|
||||
. either (error . errorBundlePretty) id
|
||||
. parse pTests "part2.txt"
|
||||
$ p2
|
||||
tests = testGroup ("Day " ++ show day) $ case part of
|
||||
Nothing -> [p1Tests, p2Tests]
|
||||
Just 1 -> [p1Tests]
|
||||
_ -> [p2Tests]
|
||||
|
||||
case tryIngredients [consoleTestReporter] mempty tests of
|
||||
Nothing -> error $ "Error running tests for day " ++ show day
|
||||
Just act -> do
|
||||
res <- act
|
||||
putStrLn $ if res then "Success" else "Failure"
|
||||
|
||||
-- | Given an input parser, part1 or part2 function, and a test input,
|
||||
-- generate an HUnit test.
|
||||
mkTest :: Show b => (T.Text -> a) -> (a -> b) -> TestInput -> TestTree
|
||||
mkTest pInput part TestInput {..} =
|
||||
testCase (T.unpack _testName) $ T.unpack _testExpected @=? result
|
||||
where
|
||||
result = show . part $ pInput _testInput
|
||||
|
||||
-- | Parse test files into TestInput's
|
||||
pTests :: Parser [TestInput]
|
||||
pTests = many pTest <* eof
|
||||
where
|
||||
pTest = TestInput <$> pName <*> pInput <*> pExpected <?> "Test"
|
||||
pName = T.pack <$> (symbol "-" *> lexeme (some (anySingleBut '\n'))) <?> "Test Name"
|
||||
pInput = T.pack <$> someTill anySingle (symbol "==") <?> "Input Lines"
|
||||
pExpected = T.pack <$> many (anySingleBut '\n') <* newline <?> "Expected Output"
|
||||
|
||||
lexeme :: Parser a -> Parser a
|
||||
lexeme = L.lexeme space
|
||||
|
||||
symbol :: T.Text -> Parser T.Text
|
||||
symbol = L.symbol space
|
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
solutions="solutions/Days"
|
||||
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
mkdir "$solutions"
|
||||
|
||||
for i in $(printf "%02i " {1..24})
|
||||
do
|
||||
cat << EOF > "$solutions/Day$i.hs"
|
||||
module Days.Day$i (day$i) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day$i :: Solution
|
||||
day$i = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day $i"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day $i"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day $i"
|
||||
EOF
|
||||
done
|
@ -0,0 +1,16 @@
|
||||
module Days.Day01 (day01) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day01 :: Solution
|
||||
day01 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 01"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 01"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 01"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day02 (day02) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day02 :: Solution
|
||||
day02 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 02"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 02"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 02"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day03 (day03) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day03 :: Solution
|
||||
day03 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 03"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 03"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 03"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day04 (day04) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day04 :: Solution
|
||||
day04 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 04"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 04"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 04"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day05 (day05) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day05 :: Solution
|
||||
day05 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 05"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 05"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 05"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day06 (day06) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day06 :: Solution
|
||||
day06 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 06"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 06"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 06"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day07 (day07) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day07 :: Solution
|
||||
day07 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 07"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 07"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 07"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day08 (day08) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day08 :: Solution
|
||||
day08 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 08"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 08"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 08"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day09 (day09) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day09 :: Solution
|
||||
day09 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 09"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 09"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 09"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day10 (day10) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day10 :: Solution
|
||||
day10 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 10"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 10"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 10"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day11 (day11) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day11 :: Solution
|
||||
day11 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 11"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 11"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 11"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day12 (day12) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day12 :: Solution
|
||||
day12 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 12"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 12"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 12"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day13 (day13) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day13 :: Solution
|
||||
day13 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 13"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 13"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 13"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day14 (day14) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day14 :: Solution
|
||||
day14 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 14"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 14"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 14"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day15 (day15) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day15 :: Solution
|
||||
day15 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 15"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 15"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 15"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day16 (day16) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day16 :: Solution
|
||||
day16 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 16"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 16"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 16"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day17 (day17) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day17 :: Solution
|
||||
day17 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 17"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 17"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 17"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day18 (day18) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day18 :: Solution
|
||||
day18 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 18"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 18"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 18"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day19 (day19) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day19 :: Solution
|
||||
day19 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 19"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 19"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 19"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day20 (day20) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day20 :: Solution
|
||||
day20 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 20"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 20"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 20"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day21 (day21) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day21 :: Solution
|
||||
day21 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 21"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 21"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 21"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day22 (day22) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day22 :: Solution
|
||||
day22 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 22"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 22"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 22"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day23 (day23) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day23 :: Solution
|
||||
day23 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 23"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 23"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 23"
|
@ -0,0 +1,16 @@
|
||||
module Days.Day24 (day24) where
|
||||
|
||||
import AOC (Solution (..))
|
||||
import qualified Data.Text as T
|
||||
|
||||
day24 :: Solution
|
||||
day24 = Solution parseInput part1 part2
|
||||
|
||||
parseInput :: T.Text -> a
|
||||
parseInput = error "parseInput not defined for day 24"
|
||||
|
||||
part1 :: a -> Int
|
||||
part1 = error "part1 not defined for day 24"
|
||||
|
||||
part2 :: a -> Int
|
||||
part2 = error "part2 not defined for day 24"
|
@ -0,0 +1,56 @@
|
||||
module Solutions (solutions) where
|
||||
|
||||
import qualified Data.IntMap.Strict as M
|
||||
import AOC (Solution)
|
||||
|
||||
import Days.Day01 (day01)
|
||||
import Days.Day02 (day02)
|
||||
import Days.Day03 (day03)
|
||||
import Days.Day04 (day04)
|
||||
import Days.Day05 (day05)
|
||||
import Days.Day06 (day06)
|
||||
import Days.Day07 (day07)
|
||||
import Days.Day08 (day08)
|
||||
import Days.Day09 (day09)
|
||||
import Days.Day10 (day10)
|
||||
import Days.Day11 (day11)
|
||||
import Days.Day12 (day12)
|
||||
import Days.Day13 (day13)
|
||||
import Days.Day14 (day14)
|
||||
import Days.Day15 (day15)
|
||||
import Days.Day16 (day16)
|
||||
import Days.Day17 (day17)
|
||||
import Days.Day18 (day18)
|
||||
import Days.Day19 (day19)
|
||||
import Days.Day20 (day20)
|
||||
import Days.Day21 (day21)
|
||||
import Days.Day22 (day22)
|
||||
import Days.Day23 (day23)
|
||||
import Days.Day24 (day24)
|
||||
|
||||
solutions :: M.IntMap Solution
|
||||
solutions = M.fromList [
|
||||
(1, day01),
|
||||
(2, day02),
|
||||
(3, day03),
|
||||
(4, day04),
|
||||
(5, day05),
|
||||
(6, day06),
|
||||
(7, day07),
|
||||
(8, day08),
|
||||
(9, day09),
|
||||
(10, day10),
|
||||
(11, day11),
|
||||
(12, day12),
|
||||
(13, day13),
|
||||
(14, day14),
|
||||
(15, day15),
|
||||
(16, day16),
|
||||
(17, day17),
|
||||
(18, day18),
|
||||
(19, day19),
|
||||
(20, day20),
|
||||
(21, day21),
|
||||
(22, day22),
|
||||
(23, day23),
|
||||
(24, day24) ]
|
Loading…
Reference in New Issue