Metadata-Version: 2.4
Name: project-youler
Version: 0.1.0
Summary: A CLI tool for managing solutions to Project Euler problems.
Keywords: project-euler,euler
Author: Henry Swanson
Author-email: Henry Swanson <henryswanson94@gmail.com>
License-Expression: Unlicense
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: click>=8.3.1
Requires-Dist: requests>=2.32.5
Requires-Python: >=3.13
Project-URL: Repository, https://github.com/HenrySwanson/project-youler
Description-Content-Type: text/markdown

# project-youler

A command line tool for managing your [Project Euler](https://projecteuler.net/) solutions (if they're written in Python).

Features include:
- Stores all your confirmed answers in a local JSON file. If you refactor your solution, you can run the `check` command to make sure none of your solvers have broken.
- Fetches the problem description from the Project Euler website and creates a template file for you to fill in with your solution.
- Shows an overview of how many problems you've solved and/or attempted.
- Really basic timing info for profiling your solutions.

This package doesn't contain any solutions itself (that would be uncool).

## Setup

In the project where you've written your solutions, add this package as a dependency, and create an entry point for the `click` CLI returned by `make_cli`.

Example:
```python
# src/my_euler/__main__.py
from pathlib import Path

from youler import EulerConfig, make_cli

from . import bonus, problems

cli = make_cli(
    EulerConfig(
        root=Path(__file__).parents[2],
        problems=problems,
        bonus=bonus,
        answer_file="answers.json",
    )
)

if __name__ == "__main__":
    cli()
```

If you wire it up as a script, you can run `euler` from anywhere in the
project:

```toml
[project.scripts]
euler = "my_euler.__main__:cli"
```

Aside: `make_cli` returns an ordinary `click.Group`, so you can register extra commands of your own on it.

### Configuration

| field | meaning |
| --- | --- |
| `root` | Root of your repository; `answer_file` is resolved against it. |
| `problems` | The imported package holding your numbered solvers. |
| `bonus` | The imported package holding your bonus solvers. Optional. |
| `answer_file` | Where confirmed answers are saved. Defaults to `answers.json`. |

## Writing a solver

A solver is a module named `pNNNN.py` inside your problems package, exporting
`solve_problem()`:

```python
# src/my_euler/problems/p0001.py
"""
If we list all the natural numbers below 10 that are multiples of 3 or 5, we
get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.
"""


def solve_problem() -> int:
    return sum(n for n in range(1000) if n % 3 == 0 or n % 5 == 0)
```

(*okay, there's **one** solution in this package*)

`euler create 1` creates that file for you, with the problem statement fetched
from the Project Euler website and formatted into the docstring.

An answer may be an `int` or a `str`, as far as I know.

### Bonus problems

<details>
  <summary>Spoiler warning</summary>
  
  Project Euler has some mysterious bonus problems that unlock after unknown conditions. Personally, I've only seen two of them. I've managed to wedge them into this framework in a reasonably clean way, just specify an arbitrary string key and it'll create a bonus problem.

  For example, if you create a file `bonus/p18i.py`, you can run it with `euler run 18i` and it'll work like other problems.

  Details subject to change since I have no idea what other bonus problems lurk in the darkness.
</details>

## Commands

> [!NOTE]
> Most of these commands take arguments of the form `a-b`, meaning problems _a_
> to _b_ inclusive, the id of a bonus problem, and the special value `all`,
> which means slightly different things to different commands.
>
> You can always pass `--help` for more detail on a particular command.

- `create <n>`: Create `problems/pNNNN.py` for problem #n, prefilled with the problem statement from the Project Euler website.
- `run <n>`: Run the solver for problem #n. If there is already a saved answer, it'll be compared with it, if not, you'll be prompted whether you want to save it. (Submit it to PE first so you know it's right!)
- `check <n>`: Run the solver for problem #n and compare it against the saved answer, without prompting. `check all` covers everything you've written or saved, which is nice for validating a refactor.
- `time <n>`: Run one problem several times and report the average time taken.
- `status`: Show which problems have been downloaded, solved, or neither.
- `answers`: Subcommands for manipulating the answer save file.
  - `show <n>`: Show saved answers.
  - `delete <n>`: Delete saved answers.

## Development

I use `uv`, `mypy` and `pytest`, in a very typical setup.

