initial commit
This commit is contained in:
9
src/lib.rs
Normal file
9
src/lib.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
pub mod util {
|
||||
pub mod grid;
|
||||
pub mod index;
|
||||
pub mod parse;
|
||||
}
|
||||
|
||||
pub mod year2016 {
|
||||
pub mod day01;
|
||||
}
|
69
src/main.rs
Normal file
69
src/main.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use aoc::util::parse::ParseExt;
|
||||
|
||||
struct Solution {
|
||||
year: u32,
|
||||
day: u32,
|
||||
input: &'static str,
|
||||
run: fn(&str) -> (String, String),
|
||||
}
|
||||
|
||||
macro_rules! solution {
|
||||
($year:tt, $day:tt) => {
|
||||
Solution {
|
||||
year: (&stringify!($year)).parse_u32(),
|
||||
day: (&stringify!($day)).parse_u32(),
|
||||
input: include_str!(concat![
|
||||
"../input/",
|
||||
stringify!($year),
|
||||
"/",
|
||||
stringify!($day),
|
||||
".txt"
|
||||
]),
|
||||
run: |input: &str| {
|
||||
use aoc::$year::$day::*;
|
||||
let part1 = part1(&input).to_string();
|
||||
let part2 = part2(&input).to_string();
|
||||
(part1, part2)
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (year, day) = match std::env::args().nth(1) {
|
||||
Some(arg) => {
|
||||
let mut split = arg.split("::").map(|s| s.parse_u32());
|
||||
(split.next(), split.next())
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
let solutions: Vec<_> = solutions()
|
||||
.filter(|s| year == Some(s.year) || year.is_none())
|
||||
.filter(|s| day == Some(s.day) || day.is_none())
|
||||
.collect();
|
||||
|
||||
for Solution {
|
||||
year,
|
||||
day,
|
||||
input,
|
||||
run,
|
||||
} in solutions
|
||||
{
|
||||
let start = Instant::now();
|
||||
let (aw1, aw2) = (run)(input);
|
||||
let elapsed = start.elapsed();
|
||||
println!("{year} Day {day:02} ({})", elapsed.as_micros());
|
||||
println!(" Part 1: {aw1}");
|
||||
println!(" Part 2: {aw2}");
|
||||
}
|
||||
}
|
||||
|
||||
fn solutions() -> impl Iterator<Item = Solution> {
|
||||
std::iter::empty().chain(year2016())
|
||||
}
|
||||
|
||||
fn year2016() -> Vec<Solution> {
|
||||
vec![solution!(year2016, day01)]
|
||||
}
|
29
src/util/grid.rs
Normal file
29
src/util/grid.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
pub struct Grid<Dim, T> {
|
||||
data: HashMap<Dim, T>,
|
||||
}
|
||||
|
||||
impl<Dim, T> Grid<Dim, T>
|
||||
where
|
||||
Dim: Eq + PartialEq + Hash,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: impl Into<Dim>) -> Option<&T> {
|
||||
self.data.get(&idx.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Dim, T> Default for Grid<Dim, T>
|
||||
where
|
||||
Dim: Eq + PartialEq + Hash,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
144
src/util/index.rs
Normal file
144
src/util/index.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Hash, Clone, Copy)]
|
||||
pub struct Dim<I: ?Sized>(pub I);
|
||||
|
||||
pub type Ix = i64;
|
||||
|
||||
macro_rules! impl_ix {
|
||||
($($t:ident: $n:literal),+) => {
|
||||
$(
|
||||
pub type $t = Dim<[Ix; $n]>;
|
||||
|
||||
impl From<[Ix; $n]> for $t {
|
||||
fn from(value: [Ix; $n]) -> Self {
|
||||
Dim(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $t() -> Dim<[Ix; $n]> { Dim([0; $n]) }
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
impl_ix!(
|
||||
Ix2: 2,
|
||||
Ix3: 3
|
||||
);
|
||||
|
||||
impl Ix2 {
|
||||
pub const ORIGIN: Ix2 = Dim([0, 0]);
|
||||
pub const UP: Ix2 = Dim([0, 1]);
|
||||
pub const DOWN: Ix2 = Dim([0, -1]);
|
||||
pub const LEFT: Ix2 = Dim([-1, 0]);
|
||||
pub const RIGHT: Ix2 = Dim([1, 0]);
|
||||
|
||||
#[inline]
|
||||
pub fn clockwise(self) -> Self {
|
||||
Dim([-self.0[1], self.0[0]])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn counter_clockwise(self) -> Self {
|
||||
Dim([self.0[1], -self.0[0]])
|
||||
}
|
||||
|
||||
pub fn manhatten(&self, other: Ix2) -> i64 {
|
||||
(self.0[0] - other.0[0]).abs() + (self.0[1] - other.0[1]).abs()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Ix2 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Dim([self.0[0] + rhs.0[0], self.0[1] + rhs.0[1]])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for Ix2 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0[0] += rhs.0[0];
|
||||
self.0[1] += rhs.0[1];
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Ix2 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Dim([self.0[0] - rhs.0[0], self.0[1] - rhs.0[1]])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for Ix2 {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.0[0] -= rhs.0[0];
|
||||
self.0[1] -= rhs.0[1];
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul for Ix2 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Dim([self.0[0] * rhs.0[0], self.0[1] * rhs.0[1]])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul<i64> for Ix2 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, rhs: i64) -> Self::Output {
|
||||
Dim([self.0[0] * rhs, self.0[1] * rhs])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Ix3 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Dim([
|
||||
self.0[0] + rhs.0[0],
|
||||
self.0[1] + rhs.0[1],
|
||||
self.0[2] + rhs.0[2],
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for Ix3 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0[0] += rhs.0[0];
|
||||
self.0[1] += rhs.0[1];
|
||||
self.0[2] += rhs.0[2];
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Ix3 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Dim([
|
||||
self.0[0] - rhs.0[0],
|
||||
self.0[1] - rhs.0[1],
|
||||
self.0[2] - rhs.0[2],
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for Ix3 {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.0[0] -= rhs.0[0];
|
||||
self.0[1] -= rhs.0[1];
|
||||
self.0[2] -= rhs.0[2];
|
||||
}
|
||||
}
|
58
src/util/parse.rs
Normal file
58
src/util/parse.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use std::str::Bytes;
|
||||
|
||||
pub struct U32s<'a> {
|
||||
bytes: Bytes<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for U32s<'a> {
|
||||
type Item = u32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
try_parse_u32(&mut self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseExt {
|
||||
fn parse_u32(&self) -> u32;
|
||||
|
||||
fn u32s(&self) -> U32s<'_>;
|
||||
}
|
||||
|
||||
impl ParseExt for &str {
|
||||
fn parse_u32(&self) -> u32 {
|
||||
match try_parse_u32(&mut self.bytes()) {
|
||||
Some(num) => num,
|
||||
None => panic!("unable to parse u32: {self}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn u32s(&self) -> U32s<'_> {
|
||||
U32s {
|
||||
bytes: self.bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_parse_u32(bytes: &mut Bytes<'_>) -> Option<u32> {
|
||||
let mut n = loop {
|
||||
let byte = bytes.next()?;
|
||||
let digit = byte.wrapping_sub(b'0');
|
||||
|
||||
if digit < 10 {
|
||||
break digit as u32;
|
||||
}
|
||||
};
|
||||
|
||||
loop {
|
||||
let Some(byte) = bytes.next() else {
|
||||
break Some(n);
|
||||
};
|
||||
let digit = byte.wrapping_sub(b'0');
|
||||
|
||||
if digit < 10 {
|
||||
n = 10 * n + digit as u32;
|
||||
} else {
|
||||
break Some(n);
|
||||
}
|
||||
}
|
||||
}
|
59
src/year2016/day01.rs
Normal file
59
src/year2016/day01.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::util::{index::*, parse::ParseExt};
|
||||
|
||||
fn parse(input: &str) -> Vec<(u8, u32)> {
|
||||
let dirs = input.bytes().filter(u8::is_ascii_uppercase);
|
||||
let steps = input.u32s();
|
||||
|
||||
dirs.zip(steps).collect()
|
||||
}
|
||||
|
||||
pub fn part1(input: &str) -> impl std::fmt::Display {
|
||||
let mut pos = Ix2::ORIGIN;
|
||||
let mut dir = Ix2::UP;
|
||||
|
||||
for (d, s) in parse(input) {
|
||||
dir = if d == b'R' {
|
||||
dir.clockwise()
|
||||
} else {
|
||||
dir.counter_clockwise()
|
||||
};
|
||||
|
||||
pos += dir * (s as i64);
|
||||
}
|
||||
|
||||
pos.manhatten(Ix2::ORIGIN)
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> impl std::fmt::Display {
|
||||
let mut pos = Ix2::ORIGIN;
|
||||
let mut dir = Ix2::UP;
|
||||
let mut set = HashSet::new();
|
||||
|
||||
for (d, s) in parse(input) {
|
||||
dir = if d == b'R' {
|
||||
dir.clockwise()
|
||||
} else {
|
||||
dir.counter_clockwise()
|
||||
};
|
||||
|
||||
for _ in 0..s {
|
||||
pos += dir;
|
||||
if !set.insert(pos) {
|
||||
return pos.manhatten(Ix2::ORIGIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
assert_eq!("12", part1("R5, L5, R5, R3").to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
assert_eq!("4", part2("R8, R4, R4, R8").to_string())
|
||||
}
|
Reference in New Issue
Block a user