Initial commit

This commit is contained in:
Alexander Kobjolke 2023-11-29 21:29:32 +01:00
commit cf2af11b6b
23 changed files with 3988 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.pre-commit-config.yaml
result
.direnv

3288
.hlint.yaml Normal file

File diff suppressed because it is too large Load diff

2
.hspec Normal file
View file

@ -0,0 +1,2 @@
--rerun
--rerun-all-on-success

136
aoc.cabal Normal file
View file

@ -0,0 +1,136 @@
cabal-version: 2.0
-- This file has been generated from package.yaml by hpack version 0.35.2.
--
-- see: https://github.com/sol/hpack
name: aoc
version: 0.0.1.0
description: Advent-Of-Code
author: Alexander Kobjolke
maintainer: alex@jakalx.net
copyright: Alexander Kobjolke 2023
license: MIT
build-type: Simple
extra-source-files:
README.org
library
exposed-modules:
AoC
AoC.Day
AoC.Riddle
AoC.Util
AoC.Year
other-modules:
Paths_aoc
autogen-modules:
Paths_aoc
hs-source-dirs:
src
default-extensions:
BlockArguments
OverloadedStrings
ImportQualifiedPost
DerivingStrategies
ghc-options: -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-missing-kind-signatures -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -fdefer-typed-holes -Wno-unused-packages
build-depends:
base
, containers
, megaparsec
, relude
, text
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
default-language: GHC2021
executable aoc
main-is: aoc.hs
other-modules:
Paths_aoc
autogen-modules:
Paths_aoc
hs-source-dirs:
app
default-extensions:
BlockArguments
OverloadedStrings
ImportQualifiedPost
DerivingStrategies
ghc-options: -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-missing-kind-signatures -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -fdefer-typed-holes -Wno-unused-packages
build-depends:
aoc
, base
, containers
, megaparsec
, relude
, text
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
default-language: GHC2021
test-suite doctest
type: exitcode-stdio-1.0
main-is: Doctest.hs
other-modules:
Paths_aoc
autogen-modules:
Paths_aoc
hs-source-dirs:
test/doctest
default-extensions:
BlockArguments
OverloadedStrings
ImportQualifiedPost
DerivingStrategies
ghc-options: -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-missing-kind-signatures -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -fdefer-typed-holes -Wno-unused-packages
build-tool-depends:
doctest:doctest
build-depends:
base
, containers
, megaparsec
, process
, relude
, text
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
default-language: Haskell2010
test-suite spec
type: exitcode-stdio-1.0
main-is: Spec.hs
other-modules:
AoCSpec.UtilSpec
SpecHook
Paths_aoc
autogen-modules:
Paths_aoc
hs-source-dirs:
test/spec
default-extensions:
BlockArguments
OverloadedStrings
ImportQualifiedPost
DerivingStrategies
ghc-options: -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-missing-kind-signatures -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -fdefer-typed-holes -Wno-unused-packages
cpp-options: -DTEST
build-tool-depends:
hspec-discover:hspec-discover
build-depends:
QuickCheck
, aoc
, base
, containers
, hspec
, megaparsec
, quickcheck-instances
, relude
, text
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
default-language: GHC2021

6
app/aoc.hs Normal file
View file

@ -0,0 +1,6 @@
module Main (main) where
import AoC qualified
main :: IO ()
main = AoC.defaultMain

171
flake.lock generated Normal file
View file

@ -0,0 +1,171 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1660459072,
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1701290038,
"narHash": "sha256-mcbPGHxG9c7Og+SkKYTAtOJwDERGx5kvTVH0BH1PNXE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "231ffe19425544deb8da37b1362b545ef90bcb40",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1685801374,
"narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c37ca420157f4abc31e26f436c1145f8951ff373",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_2",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1700922917,
"narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

76
flake.nix Normal file
View file

@ -0,0 +1,76 @@
{
description = "Advent-Of-Code";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix";
pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, flake-utils, pre-commit-hooks }:
flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
let
pkgs = nixpkgs.legacyPackages.${system};
overlay = final: prev: { aoc = final.callCabal2nix "aoc" ./. { }; };
haskellPackages = pkgs.haskell.packages.ghc942.extend overlay;
in {
packages.default = haskellPackages.aoc;
apps = {
# run with: nix run #.aoc
aoc = {
type = "app";
program = "${self.packages.${system}.default}/bin/aoc";
};
# run with: nix run
default = self.apps.${system}.aoc;
};
checks = {
pre-commit-check = pre-commit-hooks.lib.${system}.run {
src = ./.;
settings = { ormolu.defaultExtensions = [ "GHC2021" ]; };
tools.fourmolu = haskellPackages.fourmolu;
hooks = {
nixfmt.enable = true;
fourmolu.enable = true;
hpack.enable = true;
hlint.enable = true;
doctest = {
enable = false;
name = "Run documentation tests";
entry = "${haskellPackages.doctest}/bin/doctest src app";
files = "\\.l?hs$";
pass_filenames = false;
};
};
};
};
devShells.default = haskellPackages.shellFor {
inherit (self.checks.${system}.pre-commit-check) shellHook;
packages = p: [ p.aoc ];
withHoogle = true;
nativeBuildInputs = with pkgs; [
haskellPackages.haskell-language-server
haskellPackages.fourmolu
haskellPackages.hspec-discover
haskellPackages.doctest
cabal-install
ghcid
nixfmt
hpack
hlint
];
};
});
}

2
fourmolu.yaml Normal file
View file

@ -0,0 +1,2 @@
haddock-style: single-line
indentation: 2

39
gen.sh Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
Y="$1"; shift
if [ -z "$Y" ]; then
Y="$(date +%Y)"
fi
fday="$1"; shift
tday="$1"; shift
if [ -z "$fday" ]; then
fday=1
tday=25
fi
if [ -z "$tday" ]; then
tday="${fday}"
fi
days=($(seq $fday $tday))
if ! grep -q "Y${Y}" src/AoC/Year.hs; then
sed -i -e "s/\(\(\s\+\)= Y0000\)/\1\n\2| Y${Y}/" src/AoC/Year.hs
fi
mkdir -p "src/AoC/Y${Y}"
if ! test -f "src/AoC/Y${Y}.hs"; then
sed -e "s/Y0000/Y${Y}/g" template/Y0000.hs > "src/AoC/Y${Y}.hs"
fi
for d in "${days[@]}"; do
d=$(printf "%02d" "$d")
mkdir -p "data/Y${Y}/D${d}"
touch "data/Y${Y}/D${d}/riddle"
touch "data/Y${Y}/D${d}/result"
if ! test -f "src/AoC/Y${Y}/D${d}.hs"; then
sed -e "s/Y0000/Y${Y}/g" -e "s/D00/D${d}/g" template/D00.hs > "src/AoC/Y${Y}/D${d}.hs"
fi
done

80
package.yaml Normal file
View file

@ -0,0 +1,80 @@
name: aoc
version: 0.0.1.0
license: MIT
author: "Alexander Kobjolke"
maintainer: "alex@jakalx.net"
copyright: "Alexander Kobjolke 2023"
description: "Advent-Of-Code"
extra-source-files:
- README.org
dependencies:
- name: base
mixin:
- hiding (Prelude)
- name: relude
mixin:
- (Relude as Prelude)
- containers
- text
- megaparsec
ghc-options:
- -Weverything
- -Wno-implicit-prelude
- -Wno-missing-import-lists # Requires explicit imports of _every_ function (e.g. $); too strict
- -Wno-missing-kind-signatures
- -Wno-missed-specialisations # When GHC cant specialize a polymorphic function. No big deal and requires fixing underlying libraries to solve.
- -Wno-all-missed-specialisations # See missed-specialisations
- -Wno-unsafe # Dont use Safe Haskell warnings
- -Wno-safe # Dont use Safe Haskell warnings
- -Wno-missing-safe-haskell-mode # Dont use Safe Haskell warnings
- -Wno-missing-local-signatures # Warning for polymorphic local bindings; nothing wrong with those.
- -Wno-monomorphism-restriction # Dont warn if the monomorphism restriction is used
- -Wno-prepositive-qualified-module
- -fdefer-typed-holes
- -Wno-unused-packages
default-extensions:
- BlockArguments
- OverloadedStrings
- ImportQualifiedPost
- DerivingStrategies
library:
source-dirs: src
verbatim:
default-language: GHC2021
executables:
aoc:
source-dirs: app
main: aoc.hs
dependencies:
- aoc
verbatim:
default-language: GHC2021
tests:
spec:
cpp-options: -DTEST
main: Spec.hs
source-dirs:
- test/spec
dependencies:
- aoc
- hspec
- QuickCheck
- quickcheck-instances
build-tools: hspec-discover
verbatim:
default-language: GHC2021
doctest:
main: Doctest.hs
dependencies:
- process
source-dirs:
- test/doctest
build-tools: doctest

28
src/AoC.hs Normal file
View file

@ -0,0 +1,28 @@
{-# LANGUAGE OverloadedStrings #-}
module AoC (
defaultMain,
) where
import AoC.Day
import AoC.Riddle
import AoC.Year
import Control.Exception qualified as Exception
import System.IO (hPutStrLn)
import System.IO.Error qualified as IOError
-- import AoC.Y0000 qualified as Y0000
runAoC :: [String] -> IO ()
runAoC _args =
putStrLn "Hello"
handleError :: IOError.IOError -> IO ()
handleError e = do
hPutStrLn stderr $ "I ran into an issue: " <> show e
defaultMain :: IO ()
defaultMain = do
args <- getArgs
Exception.catch (runAoC args) handleError

29
src/AoC/Day.hs Normal file
View file

@ -0,0 +1,29 @@
module AoC.Day (Day (..)) where
data Day
= D01
| D02
| D03
| D04
| D05
| D06
| D07
| D08
| D09
| D10
| D11
| D12
| D13
| D14
| D15
| D16
| D17
| D18
| D19
| D20
| D21
| D22
| D23
| D24
| D25
deriving stock (Read, Show, Eq, Ord, Enum)

20
src/AoC/Riddle.hs Normal file
View file

@ -0,0 +1,20 @@
module AoC.Riddle (
Riddle (..),
Error (..),
Solution (..),
loadRiddle,
) where
import AoC.Util (readFileUtf8)
import AoC.Day
import AoC.Year
type Riddle = Text
type Error = Text
type Solution = [Integer]
loadRiddle :: (MonadIO m) => Year -> Day -> m Riddle
loadRiddle y d = readFileUtf8 inputFile
where
inputFile = intercalate "/" ["data", show y, show d, "riddle"]

11
src/AoC/Util.hs Normal file
View file

@ -0,0 +1,11 @@
-- | Internal module in order to facilitate testability.
module AoC.Util (solveRiddle, readFileUtf8) where
readFileUtf8 :: (MonadIO m) => FilePath -> m Text
readFileUtf8 = fmap (decodeUtf8With lenientDecode) . readFileBS
solveRiddle :: (MonadIO m) => FilePath -> (Text -> [Text]) -> m ()
solveRiddle file solver = do
results <- solver <$> readFileUtf8 file
forM_ (results `zip` [1 :: Int ..]) $ \(solution, part) ->
putTextLn $ " solution to part-" <> show part <> ": " <> solution

5
src/AoC/Year.hs Normal file
View file

@ -0,0 +1,5 @@
module AoC.Year (Year (..)) where
data Year
= Y0000
deriving stock (Read, Show, Eq, Ord, Enum)

6
template/D00.hs Normal file
View file

@ -0,0 +1,6 @@
module AoC.Y0000.D00 (solve) where
import AoC.Riddle
solve :: (MonadIO m) => Text -> m (Either Text Solution)
solve _ = pure $ Left "not yet implemented"

57
template/Y0000.hs Normal file
View file

@ -0,0 +1,57 @@
module AoC.Y0000 (solve) where
import AoC.Day
import AoC.Riddle
import AoC.Y0000.D01 qualified as D01
import AoC.Y0000.D02 qualified as D02
import AoC.Y0000.D03 qualified as D03
import AoC.Y0000.D04 qualified as D04
import AoC.Y0000.D05 qualified as D05
import AoC.Y0000.D06 qualified as D06
import AoC.Y0000.D07 qualified as D07
import AoC.Y0000.D08 qualified as D08
import AoC.Y0000.D09 qualified as D09
import AoC.Y0000.D10 qualified as D10
import AoC.Y0000.D11 qualified as D11
import AoC.Y0000.D12 qualified as D12
import AoC.Y0000.D13 qualified as D13
import AoC.Y0000.D14 qualified as D14
import AoC.Y0000.D15 qualified as D15
import AoC.Y0000.D16 qualified as D16
import AoC.Y0000.D17 qualified as D17
import AoC.Y0000.D18 qualified as D18
import AoC.Y0000.D19 qualified as D19
import AoC.Y0000.D20 qualified as D20
import AoC.Y0000.D21 qualified as D21
import AoC.Y0000.D22 qualified as D22
import AoC.Y0000.D23 qualified as D23
import AoC.Y0000.D24 qualified as D24
import AoC.Y0000.D25 qualified as D25
solve :: (MonadIO m) => Day -> Text -> m (Either Error Solution)
solve D01 = D01.solve
solve D02 = D02.solve
solve D03 = D03.solve
solve D04 = D04.solve
solve D05 = D05.solve
solve D06 = D06.solve
solve D07 = D07.solve
solve D08 = D08.solve
solve D09 = D09.solve
solve D10 = D10.solve
solve D11 = D11.solve
solve D12 = D12.solve
solve D13 = D13.solve
solve D14 = D14.solve
solve D15 = D15.solve
solve D16 = D16.solve
solve D17 = D17.solve
solve D18 = D18.solve
solve D19 = D19.solve
solve D20 = D20.solve
solve D21 = D21.solve
solve D22 = D22.solve
solve D23 = D23.solve
solve D24 = D24.solve
solve D25 = D25.solve

0
test/data/foo.txt Normal file
View file

10
test/doctest/Doctest.hs Normal file
View file

@ -0,0 +1,10 @@
-- | Rn the doctest executable
module Main (main) where
import System.Process (callProcess)
doctest :: [String] -> IO ()
doctest = callProcess "doctest"
main :: IO ()
main = doctest ["--fast", "src"]

View file

@ -0,0 +1,11 @@
module AoCSpec.UtilSpec (spec) where
import AoC.Util
import Test.Hspec
spec :: Spec
spec = do
describe "solveRiddle" do
it "runs the given solver" do
solveRiddle "test/data/foo.txt" pure `shouldReturn` ()

1
test/spec/Spec.hs Normal file
View file

@ -0,0 +1 @@
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

6
test/spec/SpecHook.hs Normal file
View file

@ -0,0 +1,6 @@
module SpecHook (hook) where
import Test.Hspec
hook :: Spec -> Spec
hook = parallel