initial commit
This commit is contained in:
commit
0684289592
2
.cargo/config
Normal file
2
.cargo/config
Normal file
@ -0,0 +1,2 @@
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-Ctarget-cpu=native"]
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target/
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aoc"
|
||||
version = "0.0.1"
|
4
Cargo.toml
Normal file
4
Cargo.toml
Normal file
@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "aoc"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
130
flake.lock
generated
Normal file
130
flake.lock
generated
Normal file
@ -0,0 +1,130 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1699099776,
|
||||
"narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681358109,
|
||||
"narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699236891,
|
||||
"narHash": "sha256-J0uhoYlufJncIFbM/pAoggzHK/qERB9KfQRkmYD56yo=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "a7f9bf91dc5065d470cd57169a9f2ebdbdfe1f24",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
30
flake.nix
Normal file
30
flake.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
description = "req-limit";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShells.default = mkShell {
|
||||
buildInputs = [
|
||||
(rust-bin.stable.latest.default .override {
|
||||
extensions = [ "rust-src" "rust-analyzer" ];
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
1
input/year2016/day01.txt
Normal file
1
input/year2016/day01.txt
Normal file
@ -0,0 +1 @@
|
||||
R3, L5, R2, L2, R1, L3, R1, R3, L4, R3, L1, L1, R1, L3, R2, L3, L2, R1, R1, L1, R4, L1, L4, R3, L2, L2, R1, L1, R5, R4, R2, L5, L2, R5, R5, L2, R3, R1, R1, L3, R1, L4, L4, L190, L5, L2, R4, L5, R4, R5, L4, R1, R2, L5, R50, L2, R1, R73, R1, L2, R191, R2, L4, R1, L5, L5, R5, L3, L5, L4, R4, R5, L4, R4, R4, R5, L2, L5, R3, L4, L4, L5, R2, R2, R2, R4, L3, R4, R5, L3, R5, L2, R3, L1, R2, R2, L3, L1, R5, L3, L5, R2, R4, R1, L1, L5, R3, R2, L3, L4, L5, L1, R3, L5, L2, R2, L3, L4, L1, R1, R4, R2, R2, R4, R2, R2, L3, L3, L4, R4, L4, L4, R1, L4, L4, R1, L2, R5, R2, R3, R3, L2, L5, R3, L3, R5, L2, R3, R2, L4, L3, L1, R2, L2, L3, L5, R3, L1, L3, L4, L3
|
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())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user