This crate contains some helper methods that I regularly use in my Advent of Code solutions.
args::get_args
Reads the command line arguments and checks whether the correct number of arguments are present.
```rust use rdclaochelpers::args::get_args;
fn example1() {
let args = get_args(&["", "
fn example2() {
let args = getargsrepeating(&["", "
error::WithOrExit
This trait adds a or_exit_with
method.
The purpose of this method, is to allow you to easily let your program terminate with a specific exit code.
It has been implemented for [Result] and [Option].
The implementation for [Result] requires that the associated error type implements [fmt::Debug].
```rust use rdclaochelpers::error::WithOrExit;
fn main() { someoperationthatreturnsaresult() .orexit_with(25); } ```
error::ParseError
A generic error containing just a message. It implements [fmt::Display] and [fmt::Debug], and it can be converted from [io::Error] and [num::ParseIntError].
```rust use rdclaochelpers::parseerror; use rdclaoc_helpers::error::ParseError;
fn examplewithparams(param: u8) -> Result<(), ParseError> { if process(param) { Ok(()) } else { Err(parse_error!("Failed to process param: {}", param)) } }
fn examplewithoutparams() -> Result<(), ParseError> { if process() { Ok(()) } else { Err(parse_error!("Failed to process")) } } ```
input::MultilineFromStr
This trait is inspired by the [str::FromStr] trait, and allows you to parse input where data might span several lines.
```rust use rdclaochelpers::error::ParseError; use rdclaochelpers::input::MultilineFromStr;
pub struct Record {
items: Vec
impl MultilineFromStr for Record { type Err = ParseError;
fn new() -> Self {
Record {
items: Vec::new(),
}
}
fn indicates_new_record(&self, line: &str) -> bool {
line.is_empty()
}
fn parse(&mut self, line: &str) -> Result<(), Self::Err> {
if !line.is_empty() {
self.items.push(line.parse::<u8>()?);
}
Ok(())
}
} ```
input::WithReadLines
This trait adds a read_lines
method.
The purpose of this method is to read the lines from some source (e.g. a file), and then convert each line to a specific type.
As an argument, this method takes an exit code that should be used if processing the source fails, and it returns an iterator.
This trait has been implemented for [fs::File].
```rust use rdclaochelpers::input::WithReadLines;
fn main() {
for item in File::open("./my-file.txt").read_lines::
input::WithReadMultiLines
This trait adds a read_multi_lines
method.
It's the equivalent of input::WithReadLines
, but rather than depending on [str::FromStr], it depends on input::MultilineFromStr
.
```rust use rdclaochelpers::input::WithReadMultiLines;
fn main() {
for record in File::open("./my-file.txt").readmultilines::
struct Record { /* ... / } impl MultilineFromStr for Record { / ... */ } ```
input::WithAsRecords
& input::WithAsMultilineRecords
These traits allow you to easily convert an object to a vec of items of the required type.
```rust
mod tests { use rdclaochelpers::input::WithAsRecords; use rdclaochelpers::input::WithAsMultilineRecords;
use super::*;
#[test]
fn test_simple() {
let input = vec!["1", "2", "3", "4", "5"]
.as_records::<u8>()
.unwrap();
assert_eq!(input, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_multiline() {
let input = vec!["1", "2", "", "3", "4", "", "5"]
.as_multiline_records::<Record>()
.unwrap();
assert_eq!(
input,
vec![
Record { items: vec![1, 2] },
Record { items: vec![3, 4] },
Record { items: vec![5] },
]
);
}
} ```
This module provides a machine that can process assembly-like instructions.
A machine consist of three parts:
* Instructions (must implement MachineInstruction
)
* A register (must implement MachineRegister
)
* An output receiver (must implement OutputReceiver
)
When the machine is run, it will start executing the instructions one by one.
Each instruction specifies what the next instruction is (usually the next line, but you can also jump to some other spot).
As soon as the program counter reaches a non-existent instruction, the machine will halt.
Instructions may use the register to keep track of values, and may use the output receiver to send output to some (imaginary) output device, such as an antenna.
When running the machine, you also get to specify a pre-execute hook (PreExecuteHook
).
For each instructions, the machine will call this hook before actually executing it.
This allows you to manipulate the normal flow of the program.
For example:
* Apply optimizations
* Detect loops
To more easily parse instructions from your input file, this library provides:
* machine::instruction::Value
- Represents either a raw value or a reference to a register.
* machine::instruction::ParsedMachineInstruction
- Represents a single parsed line. Allows you to easily access to command (.get_command()
) or specific arguments, which will be parsed to the correct type (.get_argument::<T>(idx)
).
```rust use rdclaochelpers::error::ParseError; use rdclaochelpers::machine::hook::NoopHook; use rdclaochelpers::machine::instruction::{MachineInstruction, ParsedMachineInstruction, Value}; use rdclaochelpers::machine::outputreceiver::OutputReceiver; use rdclaochelpers::machine::register::MachineRegister; use rdclaoc_helpers::machine::Machine;
fn main() { let instructions = parseinput().unwrap(); let mut machine = Machine::newsimple_machine(&instructions); machine.run(&mut NoopHook::default());
println!("Final register state: {}", machine.register);
}
fn parse_input() -> Result
enum Instruction { Add(Value, Value, char), Jump(i64), }
impl MachineInstruction for Instruction {
fn execute
fn from_parsed_machine_instruction(
parsed: &ParsedMachineInstruction,
) -> Result<Self, ParseError> {
match parsed.get_command() {
"add" => Ok(Instruction::Add(
parsed.get_argument(0)?,
parsed.get_argument(1)?,
parsed.get_argument(2)?
)),
"jmp" => Ok(Instruction::Jump(
parsed.get_argument(0)?
)),
_ => Err(ParseError(format!("Unknown command: {}", parsed))),
}
}
}
impl FromStr for Instruction { type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
<Self as MachineInstruction>::from_str(s)
}
} ```
math::abs_diff
& math::taxi_cab_*d
The function abs_diff
computes the absolute difference between two points.
The functions taxi_cab_*d
(implemented for 2D, 3D and 4D) computes the taxi cab distance between two points.
```rust use rdclaochelpers::math::{absdiff, taxicab2d, taxicab3d, taxicab_4d};
fn main() { println!("|1 - 5| = {}", absdiff(1, 5)); println!("|(1, 10) - (5, 3)| = {}", taxicab2d((1, 10), (5, 3))); println!("|(1, 10, 2) - (5, 3, 4)| = {}", taxicab3d((1, 10, 2), (5, 3, 4))); println!("|(1, 10, 2, 7) - (5, 3, 4, 2)| = {}", taxicab_4d((1, 10, 2, 7), (5, 3, 4, 2))); } ```
math::gcd
Computes the greatest common divisor of two numbers.
```rust use rdclaochelpers::math::gcd;
fn main() { let a = 35; let b = 49; println!("gcd({}, {}) = {}", a, b, gcd(a, b)); } ```
math::lcm
Computes the least common multiple of two numbers.
```rust use rdclaochelpers::math::lcm;
fn main() { let a = 35; let b = 49; println!("lcm({}, {}) = {}", a, b, lcm(a, b)); } ```
math::solve_crt
Solve the chinese remainder theorem for (n1, a1) and (n2, a2). We assume that: * n1 and n2 are coprime * n1 and n2 are no more than 63 bits (as they are converted to i64)
```rust use rdclaochelpers::math::solve_crt;
fn main() { println!("solvecrt((3, 1), (5, 4)) = {}", solvecrt((3, 1), (5, 4))); } ```
math::bezout_coefficients
Find t and s, such that ta + sb = gcd(p, q).
```rust use rdclaochelpers::math::bezout_coefficients;
fn main() { println!("bezoutcoefficients(3, 4) = {}", bezoutcoefficients(3, 4)); } ```
math::polynomial::Polynomial
Allows you to work with polynomials. Currently supported:
* Creating new polynomials (let y = Polynomial::new(&[1, -25, 5])
).
* Formatting a polynomial in a human readable way (format!("{}", y)
).
* Adding two polynomials together.
* Evaluating a polynomial at a point x
(y.at(x)
).
* Finding all roots of a polynomial (y.find_roots()
).
To do:
* Implement more arithmetic operations (e.g. multiplication).
* Implement Fn(i64) -> i64
for polynomials, so you can call them (y(x)
, rather than y.at(x)
).
* Either implement FromStr
, or create a macro to more easily create polynomials (e.g. polynomial![x^2 - 25x + 5]
).
```rust use rdclaochelpers::math::polynomial::Polynomial;
fn main() { let y1 = Polynomial::new(&[1, -25, 5]); println!("Solving {} = 0", y1); for x in y1.find_roots() { println!("For x = {}, y = {}.", x, y1.at(x)); } let y2 = Polynomial::new(&[25, -5]); println!("({}) + ({}) = {}", y1, y2, y1 + y2); } ```
part::Part
This enum is useful if you need to explicitly refer to a part. It implements [str::FromStr] and [fmt::Display], so you can easily convert to and from a string.
```rust use rdclaochelpers::part::Part;
fn main() {
let part = "part 1".parse::
let part = Part::Two;
println!("[{}] ...", part); // outputs "[part 2] ..."
} ```
search::Navigable
Implement this trait to be able to use [A*] to find the shortest path between two points.