Fork of github.com/TomPlanche/aoc-cli-v2
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2025-12-08 10:10:31 +01:00
src [16] (feat on main) Add point3d struct 2025-12-08 09:45:35 +01:00
templates [17] (chore on main) Clippy for point3d 2025-12-08 10:10:31 +01:00
.gitignore [1] (feat on main) Initial commit 2025-11-10 00:51:26 +01:00
Cargo.lock [14] (feat on main) time command now works in a day folder 2025-12-05 11:22:23 +01:00
Cargo.toml [14] (feat on main) time command now works in a day folder 2025-12-05 11:22:23 +01:00
README.md [14] (feat on main) time command now works in a day folder 2025-12-05 11:22:23 +01:00

AOC CLI

A command-line interface tool for scaffolding Advent of Code projects in Rust. Designed to eliminate boilerplate and accelerate daily challenge setup through workspace-based project generation with shared utilities.

Overview

AOC CLI streamlines your Advent of Code workflow by generating consistent, well-structured Rust projects. Each project includes a shared utilities crate with common helpers for grid navigation, point mathematics, and a standardized solution trait pattern.

Why This Tool?

Advent of Code challenges often require similar utilities: grid traversal, coordinate systems, and consistent input parsing. This CLI eliminates the repetitive setup by:

  • Pre-packaging proven patterns from previous years
  • Enforcing separation between parsing and solving logic
  • Providing battle-tested coordinate and direction utilities
  • Letting you focus on the puzzle, not the boilerplate

Key Features

  • Workspace Generation: Creates cargo workspaces with shared utilities and individual day crates
  • Zero Boilerplate: Pre-configured templates with parsing separation and type-safe patterns
  • Precise Timing: Built-in timing for individual parts or complete solutions with microsecond accuracy
  • Easy Updates: Update existing projects to the latest utilities with a single command
  • Coordinate System: Comprehensive (x, y) coordinate utilities with 8-directional movement
  • Generic Point Types: Flexible point implementation supporting all numeric types
  • Solution Trait Pattern: Structured approach separating input parsing from solving logic
  • Single Binary Distribution: Templates embedded at compile-time for zero dependencies

Installation

From Source

git clone https://github.com/TomPlanche/aoc-cli-v2.git
cd aoc-cli-v2
cargo build --release

The compiled binary will be available at ./target/release/aoc-cli-v2.

Add to PATH

For convenient access from anywhere:

# Linux/macOS
cp ./target/release/aoc-cli-v2 ~/.local/bin/aoc-cli

# Or create an alias
alias aoc='/path/to/aoc-cli-v2/target/release/aoc-cli-v2'

Quick Start

Initialize a New Project

aoc-cli-v2 init aoc2025
cd aoc2025

This creates a workspace with:

  • Root Cargo.toml configured for workspace members
  • utils/ crate containing Direction, Point, and Solution trait
  • Ready for day crate additions

Add Daily Challenges

# Add day 1
aoc-cli-v2 add 1

# Add day 15
aoc-cli-v2 add 15

Each day includes:

  • Pre-configured Cargo.toml with utils dependency
  • main.rs implementing the Solution trait pattern
  • Empty input.txt for challenge input

Solve a Challenge

// day01/src/main.rs
use utils::{run_solution, Solution};

struct Day01;

impl Solution for Day01 {
    type Input = Vec<i32>;
    type Output = i32;

    fn parse_input(&self, input: &str) -> Self::Input {
        input
            .lines()
            .filter_map(|line| line.parse().ok())
            .collect()
    }

    fn part1(&self, data: &Self::Input) -> Self::Output {
        data.iter().sum()
    }

    fn part2(&self, data: &Self::Input) -> Self::Output {
        data.iter().product()
    }
}

fn main() {
    run_solution!(Day01);
}

Run your solution:

cd day01
# Add your puzzle input to input.txt
cargo run

Timing Solutions

Precisely measure performance of your solutions:

# Time both parts of day 5 (from workspace root)
aoc-cli-v2 time 5

# Time from within a day folder (auto-detects day number)
cd day05
aoc-cli-v2 time

# Time only part 1
aoc-cli-v2 time 5 --part1
# Or from within day folder
cd day05 && aoc-cli-v2 time --part1

# Time only part 2
aoc-cli-v2 time 5 --part2

# Run analytics on all completed days
aoc-cli-v2 analytics

The time command works from both the workspace root and within day folders. When run from a day folder, it automatically detects the day number. All timing runs use --release mode for accurate performance measurements with microsecond precision.

Updating Existing Projects

Keep your utilities up to date with the latest features:

# From your workspace root
aoc-cli-v2 update utils

# Rebuild to apply changes
cargo build --release

This updates all utility files (Solution trait, Direction, Point) to the latest template versions.

Commands Reference

init <name>

Initialize a new AOC project workspace.

aoc-cli-v2 init aoc2025

add <day>

Add a new day crate (1-25) to the workspace.

aoc-cli-v2 add 1

time [day] [--part1|--part2]

Time a specific day's solution with release optimizations. Day number is optional when run from within a day folder.

# From workspace root
aoc-cli-v2 time 5          # Time both parts of day 5
aoc-cli-v2 time 5 --part1  # Time only part 1 of day 5
aoc-cli-v2 time 5 --part2  # Time only part 2 of day 5

# From within a day folder (auto-detects day number)
cd day05
aoc-cli-v2 time            # Time both parts (auto-detects day 5)
aoc-cli-v2 time --part1    # Time only part 1
aoc-cli-v2 time --part2    # Time only part 2

analytics [file_path]

Run all day crates and generate timing table (default: analytics.md).

aoc-cli-v2 analytics
aoc-cli-v2 analytics results.md

update <component>

Update workspace components to latest template version.

aoc-cli-v2 update utils

Project Architecture

Template System

Templates are embedded at compile-time using include_str!(), ensuring:

  • Single binary distribution without external dependencies
  • Immutable templates requiring recompilation for changes
  • Type-safe template loading

Source Structure

src/
├── main.rs                    # CLI parsing and command dispatch
├── templates.rs               # Embedded template constants
└── commands/
    ├── mod.rs                # Module exports
    ├── init.rs               # Workspace initialization
    ├── add.rs                # Day scaffolding
    ├── time.rs               # Precise timing for individual days
    ├── analytics.rs          # Batch timing across all days
    └── update.rs             # Update utilities to latest version

Generated Project Structure

aoc2025/
├── Cargo.toml                 # Workspace configuration
├── utils/                     # Shared utilities crate
│   ├── Cargo.toml
│   └── src/
│       ├── lib.rs            # Solution trait and macros
│       ├── directions.rs     # 8-directional movement
│       └── points.rs         # Generic Point<T> implementation
├── day01/
│   ├── Cargo.toml
│   ├── src/
│   │   └── main.rs
│   └── input.txt
├── day02/
│   └── ...

Utilities Reference

Solution Trait

Provides structured approach to daily challenges:

pub trait Solution {
    type Input;
    type Output: Display;

    fn parse_input(&self, input: &str) -> Self::Input;
    fn part1(&self, input: &Self::Input) -> Self::Output;
    fn part2(&self, input: &Self::Input) -> Self::Output;

    // Built-in timing methods (provided by trait)
    fn solve(&self, input: &str);
    fn solve_timed(&self, input: &str) -> (Duration, Duration);
    fn solve_part1_timed(&self, input: &str) -> Duration;
    fn solve_part2_timed(&self, input: &str) -> Duration;
}

Benefits:

  • Parsing separated from solving logic
  • Input parsed once, used for both parts
  • Generic types for any input/output structure
  • Automatic file reading via run_solution! macro
  • Built-in timing with microsecond precision

Direction Enum

8-directional movement with (x, y) coordinate system:

pub enum Direction {
    Up, Down, Left, Right,
    UpLeft, UpRight, DownLeft, DownRight,
}

// Convert to deltas
let (dx, dy): (isize, isize) = Direction::Up.into();  // (0, -1)

// Add to positions
let new_pos = (5, 10) + Direction::Right;  // (6, 10)

// Utility methods
direction.x_delta();           // Get x component
direction.y_delta();           // Get y component
direction.turn_clockwise();    // Rotate 90° CW

Point Type

Generic point implementation supporting all numeric types:

let p1 = Point::new(10, 20);
let p2 = Point::new(15, 25);

// Arithmetic operations
let sum = p1 + p2;
let diff = p2 - p1;

// Manhattan distance
let dist = p1.manhattan_distance(&p2);  // 10

// Type flexibility
let point_i32: Point<i32> = Point::new(5, 10);
let point_f64: Point<f64> = Point::new(5.5, 10.5);

Development

Building

cargo build --release

Code Quality

Run quality checks before committing:

cargo clippy --workspace --release --all-targets --all-features -- \
  --deny warnings -D warnings \
  -W clippy::correctness \
  -W clippy::suspicious \
  -W clippy::complexity \
  -W clippy::perf \
  -W clippy::style \
  -W clippy::pedantic

cargo fmt --all -- --check

Modifying Templates

  1. Edit template files in templates/ directory
  2. Rebuild with cargo build --release (templates are embedded at compile-time)
  3. Test by creating a new project
  4. Verify generated workspace builds: cd test-project && cargo check

Design Decisions

Coordinate System Convention

All utilities use (x, y) coordinates, not (row, col) or (y, x). This affects:

  • Direction enum conversions to (dx, dy) tuples
  • Point struct field ordering (.x, .y)
  • Tuple operation ordering in Add implementations
  • Direction delta methods (x_delta(), y_delta())

When modifying direction or point logic, maintain (x, y) ordering consistently.

Template Placeholders

The {DAY} placeholder is replaced during day creation:

  • In Cargo.toml: Package name becomes dayXX (e.g., "day01", "day15")
  • In main.rs: Struct name becomes DayXX (e.g., "Day01", "Day15")
  • Uses zero-padded format via format!("{day:02}")

Contributing

Contributions are welcome! Please ensure all code passes clippy and formatting checks before submitting.

License

This project is open source. See LICENSE file for details.

Support

For issues, questions, or feature requests, please open an issue on the GitHub repository.