From 81ee8fecdaaca01a8aeae275d5ea07da639d0941 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Tue, 28 Nov 2023 23:36:58 -0600 Subject: [PATCH] Maybe ready for 2023? --- 2023/fetch-input.sh | 30 +++++++++++ 2023/nim/.envrc | 1 + 2023/nim/.gitignore | 1 + 2023/nim/flake.lock | 27 ++++++++++ 2023/nim/flake.nix | 20 ++++++++ 2023/rust/.envrc | 1 + 2023/rust/.gitignore | 3 ++ 2023/rust/Cargo.lock | 7 +++ 2023/rust/Cargo.toml | 105 +++++++++++++++++++++++++++++++++++++++ 2023/rust/flake.lock | 27 ++++++++++ 2023/rust/flake.nix | 27 ++++++++++ 2023/rust/readme.md | 43 ++++++++++++++++ 2023/rust/src/day1.rs | 33 ++++++++++++ 2023/rust/src/prelude.rs | 69 +++++++++++++++++++++++++ 14 files changed, 394 insertions(+) create mode 100755 2023/fetch-input.sh create mode 100644 2023/nim/.envrc create mode 100644 2023/nim/.gitignore create mode 100644 2023/nim/flake.lock create mode 100644 2023/nim/flake.nix create mode 100644 2023/rust/.envrc create mode 100644 2023/rust/.gitignore create mode 100644 2023/rust/Cargo.lock create mode 100644 2023/rust/Cargo.toml create mode 100644 2023/rust/flake.lock create mode 100644 2023/rust/flake.nix create mode 100644 2023/rust/readme.md create mode 100644 2023/rust/src/day1.rs create mode 100644 2023/rust/src/prelude.rs diff --git a/2023/fetch-input.sh b/2023/fetch-input.sh new file mode 100755 index 0000000..7d62cab --- /dev/null +++ b/2023/fetch-input.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env sh + +AOC_YEAR="${AOC_YEAR:-2023}" +if [ "$#" -lt 1 ]; then + echo "Error: No day provided" + exit 1 +fi +DAY="$1" +f="$HOME/.cache/aoc$AOC_YEAR/$DAY.input" +if [ -f "$f" ]; then + echo "Skip: File already exists" + exit 0 +fi +url="https://adventofcode.com/$AOC_YEAR/day/$DAY/input" +cookie_file="$HOME/.advent-of-code-session-cookie" +if [[ ! -f "$cookie_file" ]]; then + echo "Cookie file not found: $cookie_file" + exit 1 +fi +cookie="$(cat "$cookie_file")" +mkdir -p "$(dirname "$f")" +if curl -s --fail-with-body -X GET "$url" -H "Cookie:$cookie" > "$f"; then + cat "$f" + echo "Downloaded $url to $f - contents have been output to this terminal as well" + exit 0 +else + echo "Error: curl failed (are you sure the input is available now?)" + rm -f "$f" + exit 1 +fi diff --git a/2023/nim/.envrc b/2023/nim/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/2023/nim/.envrc @@ -0,0 +1 @@ +use flake diff --git a/2023/nim/.gitignore b/2023/nim/.gitignore new file mode 100644 index 0000000..7ad6275 --- /dev/null +++ b/2023/nim/.gitignore @@ -0,0 +1 @@ +/.direnv diff --git a/2023/nim/flake.lock b/2023/nim/flake.lock new file mode 100644 index 0000000..c1065db --- /dev/null +++ b/2023/nim/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1700390070, + "narHash": "sha256-de9KYi8rSJpqvBfNwscWdalIJXPo8NjdIZcEJum1mH0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4ad989506ec7d71f7302cc3067abd82730a4beb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4ad989506ec7d71f7302cc3067abd82730a4beb", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/2023/nim/flake.nix b/2023/nim/flake.nix new file mode 100644 index 0000000..4926111 --- /dev/null +++ b/2023/nim/flake.nix @@ -0,0 +1,20 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs?rev=e4ad989506ec7d71f7302cc3067abd82730a4beb"; + outputs = { + self, + nixpkgs, + }: let + supportedSystems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"]; + forEachSupportedSystem = f: + nixpkgs.lib.genAttrs supportedSystems (system: + f { + pkgs = import nixpkgs {inherit system;}; + }); + in { + devShells = forEachSupportedSystem ({pkgs}: { + default = pkgs.mkShell { + buildInputs = with pkgs; [nim nimble-unwrapped nimlsp]; + }; + }); + }; +} diff --git a/2023/rust/.envrc b/2023/rust/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/2023/rust/.envrc @@ -0,0 +1 @@ +use flake diff --git a/2023/rust/.gitignore b/2023/rust/.gitignore new file mode 100644 index 0000000..1ddbf5b --- /dev/null +++ b/2023/rust/.gitignore @@ -0,0 +1,3 @@ +/target + +/.direnv diff --git a/2023/rust/Cargo.lock b/2023/rust/Cargo.lock new file mode 100644 index 0000000..6050022 --- /dev/null +++ b/2023/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aoc2023" +version = "1.0.0" diff --git a/2023/rust/Cargo.toml b/2023/rust/Cargo.toml new file mode 100644 index 0000000..744b15a --- /dev/null +++ b/2023/rust/Cargo.toml @@ -0,0 +1,105 @@ +[package] +name = "aoc2023" +version = "1.0.0" + +[[bin]] +name = "day1" +path = "src/day1.rs" + +[[bin]] +name = "day2" +path = "src/day2.rs" + +[[bin]] +name = "day3" +path = "src/day3.rs" + +[[bin]] +name = "day4" +path = "src/day4.rs" + +[[bin]] +name = "day5" +path = "src/day5.rs" + +[[bin]] +name = "day6" +path = "src/day6.rs" + +[[bin]] +name = "day7" +path = "src/day7.rs" + +[[bin]] +name = "day8" +path = "src/day8.rs" + +[[bin]] +name = "day9" +path = "src/day9.rs" + +[[bin]] +name = "day10" +path = "src/day10.rs" + +[[bin]] +name = "day11" +path = "src/day11.rs" + +[[bin]] +name = "day12" +path = "src/day12.rs" + +[[bin]] +name = "day13" +path = "src/day13.rs" + +[[bin]] +name = "day14" +path = "src/day14.rs" + +[[bin]] +name = "day15" +path = "src/day15.rs" + +[[bin]] +name = "day16" +path = "src/day16.rs" + +[[bin]] +name = "day17" +path = "src/day17.rs" + +[[bin]] +name = "day18" +path = "src/day18.rs" + +[[bin]] +name = "day19" +path = "src/day19.rs" + +[[bin]] +name = "day20" +path = "src/day20.rs" + +[[bin]] +name = "day21" +path = "src/day21.rs" + +[[bin]] +name = "day22" +path = "src/day22.rs" + +[[bin]] +name = "day23" +path = "src/day23.rs" + +[[bin]] +name = "day24" +path = "src/day24.rs" + +[[bin]] +name = "day25" +path = "src/day25.rs" + +[dependencies] diff --git a/2023/rust/flake.lock b/2023/rust/flake.lock new file mode 100644 index 0000000..c1065db --- /dev/null +++ b/2023/rust/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1700390070, + "narHash": "sha256-de9KYi8rSJpqvBfNwscWdalIJXPo8NjdIZcEJum1mH0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4ad989506ec7d71f7302cc3067abd82730a4beb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4ad989506ec7d71f7302cc3067abd82730a4beb", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/2023/rust/flake.nix b/2023/rust/flake.nix new file mode 100644 index 0000000..7455acc --- /dev/null +++ b/2023/rust/flake.nix @@ -0,0 +1,27 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs?rev=e4ad989506ec7d71f7302cc3067abd82730a4beb"; + outputs = { + self, + nixpkgs, + }: let + supportedSystems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"]; + forEachSupportedSystem = f: + nixpkgs.lib.genAttrs supportedSystems (system: + f { + pkgs = import nixpkgs {inherit system;}; + }); + in { + devShells = forEachSupportedSystem ({pkgs}: { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + cargo + rustc + rustfmt + rustPackages.clippy + rust-analyzer + curl + ]; + }; + }); + }; +} diff --git a/2023/rust/readme.md b/2023/rust/readme.md new file mode 100644 index 0000000..00f5c4a --- /dev/null +++ b/2023/rust/readme.md @@ -0,0 +1,43 @@ +# Rust Advent of Code 2023 Solutions + +## Competing + +I compete very lightly. I use [my `at` script][at] like `at 2022-12-02 && ../ +fetch-input.sh 2` to fetch input as soon as it's available and I use `watchexec +-e rs 'clear; cargo test --bin day2 && cargo run --bin day2'` to run my file(s) +as I edit them. + +## Running + +### Debug + +```bash +cargo run --bin day1 +``` + +### Tests + +```bash +cargo test --bin day1 +``` + +### Release Mode + +For speeeeeed! + +```bash +cargo build --release --bin day1 +time ./target/release/day1 +``` + +### Everything + +You can use this `fish` script to build all binaries in release mode and run/ +time them all: + +```fish +cargo build --release --bins +time for f in (fd 'day.' target/release/ --type executable --max-depth 1); echo $f; time $f; end +``` + +[at]: https://git.lyte.dev/lytedev/nix/src/branch/main/modules/home-manager/scripts/common/bin/at diff --git a/2023/rust/src/day1.rs b/2023/rust/src/day1.rs new file mode 100644 index 0000000..b06a581 --- /dev/null +++ b/2023/rust/src/day1.rs @@ -0,0 +1,33 @@ +use crate::prelude::*; + +mod prelude; + +fn main() { + Day1::show(day_input(1), day_input(1)) +} + +struct Day1 {} +impl AoCSolution for Day1 { + type Input = String; + type Solution = i128; + + fn part1(input: Self::Input) -> Self::Solution { + println!("{}", input); + return 1; + } + + fn part2(_input: Self::Input) -> Self::Solution { + return 0; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + assert_eq!(Day1::part1("asdf".into()), 1); + assert_eq!(Day1::part2("asdf".into()), 2); + } +} diff --git a/2023/rust/src/prelude.rs b/2023/rust/src/prelude.rs new file mode 100644 index 0000000..73f6745 --- /dev/null +++ b/2023/rust/src/prelude.rs @@ -0,0 +1,69 @@ +pub use std::fs::File; +pub use std::io::Read; + +use std::path::{Path, PathBuf}; +use std::{env, io}; + +pub type Reader = Box; + +#[derive(Debug)] +enum InputFileError { + VarError(env::VarError), + IoError(io::Error), +} + +/// Ensures that the input file exists +fn ensure_input_file(day: u8) -> Result { + let path = Path::new(&env::var("HOME").map_err(InputFileError::VarError)?) + .join(format!("./.cache/aoc2023/{0}.input", day)); + if !path.exists() { + eprintln!("Running input downloaded script with day arg {}...", day); + std::process::Command::new("sh") + .args(["../fetch-input.sh", &day.to_string()]) + .status() + .map_err(InputFileError::IoError)?; + } + Ok(path) +} + +/// Useful when you simply want the day's input as a String. +pub fn day_input(day: u8) -> String { + let mut buffer = String::new(); + day_input_file(day) + .read_to_string(&mut buffer) + .expect(&format!("invalid utf8 input for day {}", day)); + buffer +} + +/// Useful when you want the day's input for streaming for maximum performance nonsense +pub fn day_input_file(day: u8) -> File { + let f = ensure_input_file(day).expect(&format!("Failed to ensure input for day {}", day)); + File::open(&f).expect(format!("Failed to open file {}", f.display()).as_str()) +} + +pub trait AoCSolution { + type Input; + type Solution: std::fmt::Debug + std::cmp::PartialEq + std::fmt::Display; + + // Are part1 and part2 solutions _always_ the same? + fn part1(input: Self::Input) -> Self::Solution; + fn part2(input: Self::Input) -> Self::Solution; + + fn show(i1: Self::Input, i2: Self::Input) { + println!("Part 1: {}", Self::part1(i1)); + println!("Part 2: {}", Self::part2(i2)); + } +} + +#[cfg(test)] +pub trait AoCSolutionTest: AoCSolution { + const PART1_TEST_INPUT: Self::Input; + const PART2_TEST_INPUT: Self::Input; + const PART1_TEST_RESULT: Self::Solution; + const PART2_TEST_RESULT: Self::Solution; + + fn assert_valid() { + assert_eq!(Self::part1(Self::PART1_TEST_INPUT), Self::PART1_TEST_RESULT); + assert_eq!(Self::part2(Self::PART2_TEST_INPUT), Self::PART2_TEST_RESULT); + } +}