initial commit

This commit is contained in:
fuckwit 2023-11-15 18:38:04 +01:00
commit 0684289592
13 changed files with 543 additions and 0 deletions

2
.cargo/config Normal file
View File

@ -0,0 +1,2 @@
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Ctarget-cpu=native"]

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target/

7
Cargo.lock generated Normal file
View 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
View File

@ -0,0 +1,4 @@
[package]
name = "aoc"
version = "0.0.1"
edition = "2021"

130
flake.lock generated Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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())
}