Infra
This commit is contained in:
4
.formatter.exs
Normal file
4
.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
aoc2023-*.tar
|
||||
|
||||
# Temporary files, for example, from tests.
|
||||
/tmp/
|
||||
.direnv
|
||||
/.nix-mix
|
||||
/.nix-hex
|
||||
|
||||
/inputs
|
||||
session
|
||||
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Aoc2023
|
||||
|
||||
**TODO: Add description**
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `aoc2023` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:aoc2023, "~> 0.1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||
be found at <https://hexdocs.pm/aoc2023>.
|
||||
|
||||
39
flake.lock
generated
Normal file
39
flake.lock
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1700794826,
|
||||
"narHash": "sha256-RyJTnTNKhO0yqRpDISk03I/4A67/dp96YRxc86YOPgU=",
|
||||
"path": "/nix/store/6h04ab83y72nm16hh9g3llgg0s296ynl-source",
|
||||
"rev": "5a09cb4b393d58f9ed0d9ca1555016a8543c2ac8",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "systems",
|
||||
"type": "indirect"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
7
flake.nix
Normal file
7
flake.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
outputs = { self, nixpkgs, systems }: {
|
||||
devShells = nixpkgs.lib.genAttrs (import systems) (system: {
|
||||
default = nixpkgs.legacyPackages.${system}.beam.packages.erlang_26.callPackage ./shell.nix {};
|
||||
});
|
||||
};
|
||||
}
|
||||
13
lib/aoc2023.ex
Normal file
13
lib/aoc2023.ex
Normal file
@@ -0,0 +1,13 @@
|
||||
defmodule Aoc2023 do
|
||||
defmacro __using__([]) do
|
||||
quote do
|
||||
import Aoc2023.Common
|
||||
|
||||
def main(input) do
|
||||
parsed = parse(input)
|
||||
IO.puts("Part 1: #{part1(parsed)}")
|
||||
IO.puts("Part 2: #{part2(parsed)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
2
lib/common.ex
Normal file
2
lib/common.ex
Normal file
@@ -0,0 +1,2 @@
|
||||
defmodule Aoc2023.Common do
|
||||
end
|
||||
15
lib/day1.ex
Normal file
15
lib/day1.ex
Normal file
@@ -0,0 +1,15 @@
|
||||
defmodule Aoc2023.Day1 do
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
nil
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
nil
|
||||
end
|
||||
end
|
||||
155
lib/mix_tasks.ex
Normal file
155
lib/mix_tasks.ex
Normal file
@@ -0,0 +1,155 @@
|
||||
defmodule Mix.Tasks.Aoc do
|
||||
use Mix.Task
|
||||
|
||||
defp module(1), do: Aoc2023.Day1
|
||||
# [MODULE INSERTION POINT]
|
||||
|
||||
defp base_dir(), do: System.get_env("AOC_BASE")
|
||||
|
||||
defp tests(day) do
|
||||
File.ls!(tests_dir(day)) |> Enum.filter(&(not String.contains?(&1, ".")))
|
||||
end
|
||||
|
||||
defp read(path) do
|
||||
f = File.open!(path, [:utf8])
|
||||
contents = IO.read(f, :eof)
|
||||
:ok = File.close(f)
|
||||
contents
|
||||
end
|
||||
|
||||
defp test(day, test) do
|
||||
f = "#{tests_dir(day)}#{test}"
|
||||
|
||||
{
|
||||
test,
|
||||
read(f),
|
||||
if File.exists?(f <> ".1") do
|
||||
read(f <> ".1")
|
||||
else
|
||||
nil
|
||||
end,
|
||||
if File.exists?(f <> ".2") do
|
||||
read(f <> ".2")
|
||||
else
|
||||
nil
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
defp tests_dir(day), do: "#{base_dir()}/tests/day#{day}/"
|
||||
|
||||
defp create_file(path, contents) do
|
||||
File.mkdir_p!(Path.dirname(path))
|
||||
f = File.open!(path, [:exclusive, :utf8])
|
||||
IO.write(f, contents)
|
||||
:ok = File.close(f)
|
||||
end
|
||||
|
||||
def run(params) do
|
||||
{opts, params} = params |> OptionParser.parse!(strict: [day: :integer])
|
||||
day = opts |> Keyword.get(:day, Date.utc_today().day)
|
||||
run(day, params)
|
||||
end
|
||||
|
||||
defp run(day, ["new"]) do
|
||||
create_file("#{base_dir()}/lib/day#{day}.ex", """
|
||||
defmodule Aoc2023.Day#{day} do
|
||||
use Aoc2023
|
||||
def parse(input) do
|
||||
input
|
||||
end
|
||||
def part1(input) do
|
||||
input
|
||||
end
|
||||
def part2(input) do
|
||||
input
|
||||
end
|
||||
end
|
||||
""")
|
||||
|
||||
this_file = "#{base_dir()}/lib/mix_tasks.ex"
|
||||
|
||||
contents =
|
||||
read(this_file)
|
||||
|> String.replace(
|
||||
"\n # [MODULE INSERTION POINT]",
|
||||
"\n defp module(#{day}), do: Aoc2023.Day#{day}\n # [MODULE INSERTION POINT]"
|
||||
)
|
||||
|
||||
f = File.open!(this_file, [:write, :utf8])
|
||||
IO.write(f, contents)
|
||||
:ok = File.close(f)
|
||||
end
|
||||
|
||||
defp run(day, ["test", "new"]) do
|
||||
last = tests(day) |> Enum.map(&String.to_integer(&1)) |> Enum.max(empty_fallback: fn -> 1 end)
|
||||
create_file("#{tests_dir(day)}#{last + 1}", IO.read(:stdio, :eof))
|
||||
end
|
||||
|
||||
defp run(day, ["test", "expected", test, part]) do
|
||||
create_file("#{tests_dir(day)}#{test}.#{part}", IO.read(:stdio, :eof))
|
||||
end
|
||||
|
||||
defp run(day, ["test"]) do
|
||||
mod = module(day)
|
||||
tests = tests(day)
|
||||
|
||||
tests
|
||||
|> Enum.map(&test(day, &1))
|
||||
|> Enum.map(fn {test, input, p1e, p2e} ->
|
||||
parsed = mod.parse(input)
|
||||
p1 = mod.part1(parsed)
|
||||
|
||||
if p1e do
|
||||
if to_string(p1) != p1e do
|
||||
IO.puts("Failed at #{test}.1: expected #{p1e}, got:")
|
||||
dbg(p1)
|
||||
end
|
||||
else
|
||||
IO.puts("Test #{test}.1")
|
||||
dbg(p1)
|
||||
end
|
||||
|
||||
p2 = mod.part2(parsed)
|
||||
|
||||
if p2e do
|
||||
if to_string(p2) != p2e do
|
||||
IO.puts("Failed at #{test}.2: expected #{p2e}, got:")
|
||||
dbg(p2)
|
||||
end
|
||||
else
|
||||
IO.puts("Test #{test}.2")
|
||||
dbg(p2)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp run(day, ["run"]) do
|
||||
run(day, ["fetch"])
|
||||
run_file(day, "#{base_dir()}/inputs/day#{day}")
|
||||
end
|
||||
|
||||
defp run(day, ["run", "-"]) do
|
||||
run_file(day)
|
||||
end
|
||||
|
||||
defp run(day, ["fetch"]) do
|
||||
file = "#{base_dir()}/inputs/day#{day}"
|
||||
|
||||
if not File.exists?(file) do
|
||||
HTTPoison.start()
|
||||
|
||||
resp =
|
||||
HTTPoison.get!("https://adventofcode.com/2023/day/#{day}/input",
|
||||
"user-agent": "aoc-ex by ben@soroos.net",
|
||||
cookie: "session=#{System.get_env("AOC_SESSION")}"
|
||||
)
|
||||
|
||||
create_file(file, resp.body)
|
||||
end
|
||||
end
|
||||
|
||||
defp run_file(day, file \\ nil) do
|
||||
module(day).main(if file, do: read(file), else: IO.read(:stdio, :eof))
|
||||
end
|
||||
end
|
||||
25
mix.exs
Normal file
25
mix.exs
Normal file
@@ -0,0 +1,25 @@
|
||||
defmodule Aoc2023.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :aoc2023,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.15",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
defp deps do
|
||||
[
|
||||
{:httpoison, "~> 2.0"}
|
||||
]
|
||||
end
|
||||
end
|
||||
11
mix.lock
Normal file
11
mix.lock
Normal file
@@ -0,0 +1,11 @@
|
||||
%{
|
||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
||||
"httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
}
|
||||
24
shell.nix
Normal file
24
shell.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
mkShell,
|
||||
elixir,
|
||||
elixir-ls,
|
||||
inotify-tools,
|
||||
}:
|
||||
mkShell {
|
||||
packages =
|
||||
[elixir elixir-ls]
|
||||
++ lib.lists.optional (pkgs.system == "x86_64-linux") inotify-tools
|
||||
++ lib.lists.optionals (pkgs.system == "aarch64-darwin") (with pkgs.darwin.apple_sdk.frameworks; [
|
||||
CoreFoundation
|
||||
CoreServices
|
||||
]);
|
||||
shellHook = ''
|
||||
mkdir -p .nix-mix
|
||||
mkdir -p .nix-hex
|
||||
export MIX_HOME=$PWD/.nix-mix
|
||||
export HEX_HOME=$PWD/.nix-hex
|
||||
export AOC_BASE=$PWD
|
||||
'';
|
||||
}
|
||||
Reference in New Issue
Block a user