README.md

# Advent Of Code



This is a small collection of command line tools to help with [Advent of
Code](https://adventofcode.com/) by managing inputs, tests and boilerplate code
while you focus on problem solving!

- [Quickstart Guide](#quickstart-guide)
  - [Install the library](#install-the-library)
  - [Configuration](#configuration)
  - [Install your cookie](#install-your-cookie)
  - [Are you trying this library before December 1st ?](#are-you-trying-this-library-before-december-1st-)
  - [Let's write some code!](#lets-write-some-code)
  - [Call your solution module manually](#call-your-solution-module-manually)
  - [TL; DR](#tl-dr)
- [Available Commands](#available-commands)
  - [mix.aoc.open](#mixaocopen)
  - [mix.aoc.create](#mixaoccreate)
  - [mix.aoc.test](#mixaoctest)
  - [mix.aoc.run](#mixaocrun)
  - [mix.aoc.fetch](#mixaocfetch)
  - [mix.aoc.url](#mixaocurl)
  - [Custom default values for commands](#custom-default-values-for-commands)
- [Upgrading to `0.12`](#upgrading-to-012)

## Quickstart Guide

Follow these steps to get started on your first AoC puzzle today!

In a Hurry? Just go to the "TL; DR" section.

### Install the library

This framework is distributed as a library as it consists mostly of mix tasks.
You may add the dependency to your project, or add it to a new project created
with `mix new my_app`.

<!-- block:as_dep -->
```elixir
defp deps do
  [
    {:aoc, "~> 0.13"},
  ]
end
```
<!-- endblock:as_dep -->

Then call `mix deps.get` before following the rest of this guide.

### Configuration

If it does not exist, create a configuration file in your application:

```
mkdir -p config
touch config/config.exs
```

Then add the configuration for the module prefix. This is the namespace of all
solution modules generated by `aoc`. It must start with your app name.

```elixir
# config/config.exs

import Config

config :aoc,
  # The prefix is used when creating solutions and test modules with
  # `mix aoc.create`.
  prefix: MyApp.Solutions,

  # Optional

  # Include help comments when generating modules and tests.
  generate_comments: false
```

**Tip**: The configuration can be defined in `config/runtime.exs` instead.

In order to run the `aoc.test` command described later in this document, you
need to declare that command as a test environment command.

In your`mix.exs` file, declare the following function:

```elixir
# mix.exs
def cli do
  [
    preferred_envs: ["aoc.test": :test]
  ]
end
```

### Install your cookie

The cookie is used to authenticate with the AoC website. This library will only
use it to fetch your inputs and save them locally.

Retrieve your cookie from the AoC website (with you browser developer tools) and
write the session ID in `$HOME/.adventofcode.session`. It should be a long hex
number like `53616c7415146f5f1d5792d97e...`


### Are you trying this library before December 1st ?

The `aoc` commands use dynamic default values: they will always default to the
current year and day, as they are intended to be used during the event.

If you want to try this library right now and be ready for day one, why not try a simple puzzle from a previous year?

Just chose a year and a day, for instance 2023 Dec. 1st, and set that as your
new default values:

```bash
mix aoc.set --year 2023 --day 1

# short version
mix aoc.set -y 2023 -d
```

This is also useful if you need to focus on a puzzle for more than one year.

Remember to call `mix aoc.set --reset` when you want to use the dynamic default
values.


### Let's write some code!

> Note that this guide uses 2023 day 1 for its examples.
>
> Also ... this tools gives a strong importance to testing and TDD practice.  If
> you are playing the race game, it may not be worth it, but you can still use
> all the file generation part.

Alright, now that you are set up, you can automatically download the input and
generate the files to work on your solution.

#### Generate the files

Call `mix aoc.create` to do just that.

The generated module will look like that:

```elixir
defmodule MyApp.Solutions.Y23.Day01 do
  alias AoC.Input

  def parse(input, _part) do
    Input.read!(input)
  end

  def part_one(problem) do
    problem
  end

  # def part_two(problem) do
  #   problem
  # end
end
```

Alright, I lied, the module is also full of comments to help you understand what
you can do in there. See the configuration section to disable those.

There are three functions in there.

* The `parse/2` function should be focused on transforming the input text into a
  data structure of your design. Imagine a good model for your data and the
  algorithms will be simpler to write.
* The `part_one/1` function receives the output of `parse/2`. It is separated so
  you can test to call it with made up data, and focus on the problem. Of
  course, you can just return the input as-is from `parse/2` and do everything
  in `part_one/2`.
* Uncomment the `part_two/1` function when you have done part 1.

There is also a generated test in your `test` directory. Inside, you can find the following test:

```elixir
  test "part one example" do
    input = ~S"""
    This is an
    example input.
    replace with
    an example from
    the AoC website.
    """

    assert CHANGE_ME == solve(input, :part_one)
  end
```

Finally, give a look at your input downloaded in `priv/input/2023/day-01.inp`,
this may give you a hint about what to do before writing the tests. Or you can
just try to solve the example before, your choice!

#### Solve the example

It's time to read the puzzle if you haven't already. You can call `mix aoc.open` as a shortcut.

After having carefully read the the puzzle description, copy it's first example
and paste it in lieu of the current placeholder. The puzzle also gives the
answer for that example: `142`. This is what we are going to use for the assertion.

In the end, we should have this:

```elixir
  test "part one example" do
    input = ~S"""
    1abc2
    pqr3stu8vwx
    a1b2c3d4e5f
    treb7uchet
    """

    assert 142 == solve(input, :part_one)
  end
```

You may then use `mix aoc.test` to test your implementation with that example.

Or you can just call `mix test` or `mix test test/2023/day_01.exs`. After all,
this test is nothing special to the `aoc` library, you can do whatever you want
in there:

* Add more example tests.
* Customize the `solve/2` function to your liking, maybe with some `dbg()` or
  `IO.inspect/2` calls.
* Use your own ExUnit case template.

#### Solve the puzzle

Finally, once your tests seem correct, you can use `mix aoc.run` to run your
solution with the actual input.

And it's time to submit your first answer to the AoC website. Hopefully, it will be right!

Happy coding :)


### Call your solution module manually

If you want to call your module directly from custom tests or from a runner of
your own, just pass the path of your input and `:part_one | :part_two` to the
`parse/2` function, and pipe that to the `part_one/1` or `part_two/1` function:

```elixir
solution_for_p1 =
  "path/to/input/file"
  |> MyApp.Y23.Day1.parse(:part_one)
  |> MyApp.Y23.Day1.part_one()
```

### TL; DR

1. **Installation**: Add the dependency and fetch it.
   ```elixir
   # mix.exs
   defp deps do
     [
       {:aoc, "~> 0.11"},
     ]
   end

   def cli do
     [
       preferred_envs: ["aoc.test": :test]
     ]
   end

   # Run in terminal
   mix deps.get
   ```

2. **Configuration**: Set up your configuration and environment.
   ```elixir
   # config/config.exs
   import Config
   config :aoc, prefix: MyApp.Solutions
   ```

3. **Authentication**: Save your AoC session cookie value in
   `$HOME/.adventofcode.session`.

4. **Before the event**: Set default values for previous days.
   ```bash
   # Force defaults to 2023 day 1
   mix aoc.set -y 2023 -d 1
   # Reset on December 1st
   mix aoc.set --reset
   ```

5. **Generate the files**:
   ```elixir
   # Generate solution files
   mix aoc.create
   ```

6. **Import the example**:
   ```elixir
   # Copy input and expected result from the example in
   # the generated test.
   test "part one example" do
     input = ~S"""
     1abc2
     pqr3stu8vwx
     a1b2c3d4e5f
     treb7uchet
     """

     assert 142 == solve(input, :part_one)
   end
   ```

7. **Implement** `parse/2` and `part_one/1` in your module. Use the tests to verify with the example:

   ```bash
   # Run tests
   mix aoc.test
   # Or
   mix test
   ```

8. **Run your solution**:
   ```bash
   # Run the solution
   mix aoc.run
   ```

9. **Manual Execution**: Directly call solution functions if needed.
   ```elixir
   # Manual call
   solution_for_p1 =
     "path/to/input/file"
     |> MyApp.Solutions.Y23.Day1.parse(:part_one)
     |> MyApp.Solutions.Y23.Day1.part_one()
   ```



## Available Commands

The following commands will use default `year` and `day` based on the current
date.

It is possible to override the defaults with the `mix aoc.set` command, or
provide the `--year` and `--day` options to any of them.

The following docs are generated from the tasks modules documentation. You can
get any of them using `mix help <command>`, for instance `mix help aoc.create`.

You may also get a quick summary of options by calling those commands with the
`--help` flag, as in `mix aoc.create --help`.

---


<!-- block:mix.aoc.open -->
### mix.aoc.open

Opens the puzzle page with your defined browser on on adventofcode.com.

The command to call with the URL will be defined in the following order:

* Using the `AOC_BROWSER` environment variable.
* Using the `BROWSER` environment variable.
* Fallback to `xdg-open`.

#### Usage

```shell
mix aoc.open [options]
```

#### Options

* `-y, --year <integer>` - Year of the puzzle. Defaults to today's year or custom default.
* `-d, --day <integer>` - Day of the puzzle. Defaults to today's day or custom default.
* `--help` - Displays this help.


<!-- endblock:mix.aoc.open -->

---


<!-- block:mix.aoc.create -->
### mix.aoc.create

This task will execute the following operations:

* Download the input from Advent of Code website into the `priv/inputs`
  directory.
* Create the solution module.
* Create a test module.

Existing files will not be overwritten. It is safe to call the command again
if you need to regenerate a deleted file.

The generated files will contain some comment blocks to help you get
accustomed to using this library. This can be annoying after some time. You
may disable generating those comments by setting the appropriate configuration
option:

    config :aoc, generate_comments: false

#### Usage

```shell
mix aoc.create [options]
```

#### Options

* `-y, --year <integer>` - Year of the puzzle. Defaults to today's year or custom default.
* `-d, --day <integer>` - Day of the puzzle. Defaults to today's day or custom default.
* `--help` - Displays this help.


<!-- endblock:mix.aoc.create -->

---


<!-- block:mix.aoc.test -->
### mix.aoc.test

Runs your test file for the Advent of Code puzzle.

Note that test files generated by the `mix aoc.create` command are regular
ExUnit tests.

You can always run `mix test` or a test specified by a file and an optional
line number like this:

```shell
mix test test/2023/day01_test.exs:123
```

In order to use this command, you should define it as a test environment
command in your `mix.exs` file by defining a `cli/0` function:

```elixir
def cli do
  [
    preferred_envs: ["aoc.test": :test]
  ]
end
```

#### Usage

```shell
mix aoc.test [options]
```

#### Options

* `-y, --year <integer>` - Year of the puzzle. Defaults to today's year or custom default.
* `-d, --day <integer>` - Day of the puzzle. Defaults to today's day or custom default.
* `--trace` - forward option to `mix test`.
* `--stale` - forward option to `mix test`.
* `--failed` - forward option to `mix test`.
* `--seed <integer>` - forward option to `mix test`.
* `--max-failures <integer>` - forward option to `mix test`.
* `--help` - Displays this help.


<!-- endblock:mix.aoc.test -->

---


<!-- block:mix.aoc.run -->
### mix.aoc.run

Runs your solution with the corresponding year/day input from `priv/inputs`.

#### Usage

```shell
mix aoc.run [options]
```

#### Options

* `-y, --year <integer>` - Year of the puzzle. Defaults to today's year or custom default.
* `-d, --day <integer>` - Day of the puzzle. Defaults to today's day or custom default.
* `-p, --part <integer>` - Part of the puzzle. Defaults to both parts.
* `-b, --benchmark` - Runs the solution repeatedly for 5 seconds to print statistics about execution time. Defaults to `false`.
* `--help` - Displays this help.


<!-- endblock:mix.aoc.run -->

---


<!-- block:mix.aoc.fetch -->
### mix.aoc.fetch

This task will fetch the puzzle into `priv/inputs`.

It will not overwrite an existing input file.

#### Usage

```shell
mix aoc.fetch [options]
```

#### Options

* `-y, --year <integer>` - Year of the puzzle. Defaults to today's year or custom default.
* `-d, --day <integer>` - Day of the puzzle. Defaults to today's day or custom default.
* `--help` - Displays this help.


<!-- endblock:mix.aoc.fetch -->

---


<!-- block:mix.aoc.url -->
### mix.aoc.url

Outputs the on adventofcode.com URL for a puzzle.

Useful to use in custom shell commands.

Note that due to Elixir compilation outputs you may need to grep for the URL.
For instance:

```shell
xdg-open $(mix aoc.url | grep 'https')
```

#### Usage

```shell
mix aoc.url [options]
```

#### Options

* `-y, --year <integer>` - Year of the puzzle. Defaults to today's year or custom default.
* `-d, --day <integer>` - Day of the puzzle. Defaults to today's day or custom default.
* `--help` - Displays this help.


<!-- endblock:mix.aoc.url -->

---

### Custom default values for commands

The `mix aoc.set` command allows to set the default year and day. Those values
are used by default when other commands are not called with `--year` or `--day`
options.

This is useful when working on a problem from a previous year, or when you
finish the last days after December 25th, so your CLI history or bash scripts
can just call `mix aoc.test` or `mix aoc.run` without options.

* `mix aoc.set --year 2022` – Set the default year to 2022.
* `mix aoc.set --day 12` – Set the default day.
* `mix aoc.set --year 2022 --day 12` – Set both defaults.
* `mix aoc.set --reset --day 12` – Set the default day and delete other default values.
* `mix aoc.set --reset` – Delete every default values.


## Upgrading to `0.12`

If you have been using this library in the past, there have been quite some
changes in the way the generated files are located.

You will need to rename your modules for days 1 to 9 with a leading `0`, for instance day 1:

```
find lib  -type f -exec sed -i -e 's/.Day1\b/.Day01\b/' {} \;
find test -type f -exec sed -i -e 's/.Day1\b/.Day01\b/' {} \;
find test -type f -exec sed -i 's/.Day1Test/.Day01Test/' {} \;
```

Do this for all 9 days, then call `mix deps.get` and `mix mod.relocate -i` to
move your old modules.

Sorry for the inconvenience. That change was necessary to have a clean ordering
of files in the solutions directories and to allow everyone to generate the
modules in a directory according to their prefix.