commit 79d1618ede076e2a299fc0f20e370f2436b5f9ba Author: Charles Date: Mon Dec 2 23:04:39 2024 -0800 add: files so far diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml new file mode 100644 index 0000000..87d2eba --- /dev/null +++ b/.github/workflows/build_nix.yml @@ -0,0 +1,13 @@ +name: "Build legacy Nix package on Ubuntu" + +on: + push: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: cachix/install-nix-action@v26 + - name: Building package + run: nix build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddf97f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +*.zip diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..bbedd73 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "advent-of-code-2024" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6cdd29c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "advent-of-code-2024" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/d/README.md b/d/README.md new file mode 100644 index 0000000..ee303f5 --- /dev/null +++ b/d/README.md @@ -0,0 +1,9 @@ +# Advent of code 2024 + +Usage: + + rustc dp1.rs + cat input.txt | dp1.rs + +## Day + diff --git a/d/d1p1.rs b/d/d1p1.rs new file mode 100644 index 0000000..fdb696a --- /dev/null +++ b/d/d1p1.rs @@ -0,0 +1,22 @@ +use std::collections::BinaryHeap; +use std::io; + +fn main() -> io::Result<()> { + let mut l1 = BinaryHeap::::new(); + let mut l2 = BinaryHeap::::new(); + for line in io::stdin().lines() { + let line = line?; + let parts: Vec<&str> = line.trim().split_whitespace().collect(); + let (n1, n2) = (parts[0], parts[1]); + l1.push(n1.parse().unwrap()); + l2.push(n2.parse().unwrap()); + } + let l1 = l1.into_sorted_vec(); + let l2 = l2.into_sorted_vec(); + let mut sum = 0; + for (n1, n2) in l1.into_iter().zip(l2.into_iter()) { + sum += n1.abs_diff(n2); + } + println!("{}", sum); + Ok(()) +} diff --git a/d/d1p1.txt b/d/d1p1.txt new file mode 100644 index 0000000..dfca0b1 --- /dev/null +++ b/d/d1p1.txt @@ -0,0 +1,6 @@ +3 4 +4 3 +2 5 +1 3 +3 9 +3 3 \ No newline at end of file diff --git a/d/d1p2.rs b/d/d1p2.rs new file mode 100644 index 0000000..0c7f9e2 --- /dev/null +++ b/d/d1p2.rs @@ -0,0 +1,21 @@ +use std::collections::HashMap; +use std::io; + +fn main() -> io::Result<()> { + let mut l1: Vec = vec!(); + let mut l2: HashMap = HashMap::default(); + for line in io::stdin().lines() { + let line = line?; + let parts: Vec<&str> = line.trim().split_whitespace().collect(); + let (n1, n2) = (parts[0], parts[1]); + l1.push(n1.parse().unwrap()); + let v = l2.entry(n2.parse::().unwrap()).or_insert(0); + *v += 1; + } + let mut sum = 0; + for n1 in l1.into_iter() { + sum += n1*l2.get(&n1).unwrap_or(&0); + } + println!("{}", sum); + Ok(()) +} diff --git a/d/d2p1.rs b/d/d2p1.rs new file mode 100644 index 0000000..627f603 --- /dev/null +++ b/d/d2p1.rs @@ -0,0 +1,58 @@ +use advent_of_code_2024::{make_main, SResult}; + +make_main!(); + +// CODE + +#[derive(PartialEq)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} + +fn solve(lines: Vec) -> SResult { + let mut failed = 0; + for line in lines.iter() { + let reports: Vec = line.split_whitespace().map(|v| v.parse::().unwrap()).collect(); + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i+1]); + if delta < 1 || delta > 3 { + failed += 1; + break; + } + if direction != Direction::from(reports[i], reports[i+1]) { + failed += 1; + break; + } + i += 1; + } + } + Ok(lines.len() - failed) +} + +// CODE + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn sample_input() { + let strings: Vec = input!("d2p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, 2); + } +} \ No newline at end of file diff --git a/d/d2p1.txt b/d/d2p1.txt new file mode 100644 index 0000000..82cd679 --- /dev/null +++ b/d/d2p1.txt @@ -0,0 +1,6 @@ +7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9 \ No newline at end of file diff --git a/d/d2p2.rs b/d/d2p2.rs new file mode 100644 index 0000000..9962ddf --- /dev/null +++ b/d/d2p2.rs @@ -0,0 +1,78 @@ +use advent_of_code_2024::{make_main, SResult}; + +make_main!(); + +#[derive(PartialEq, Clone, Copy)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} + +fn solve(lines: Vec) -> SResult { + let mut fail_count = 0; + for line in lines.iter() { + let reports: Vec = line + .split_whitespace() + .map(|v| v.parse::().unwrap()) + .collect(); + let problems = match test(&reports) { + // Cool, nothing to see here + Ok(_) => continue, + Err(e) => e, + }; + let mut pass = false; + for problem in problems { + let mut l1 = reports.clone(); + l1.remove(problem); + if test(&l1).is_ok() { + pass = true; + break; + } + } + if !pass { + fail_count += 1; + } + } + Ok(lines.len() - fail_count) +} + +// Tests the report, and returns indexes around where a failure is detected. +fn test(reports: &[usize]) -> Result<(), Vec> { + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i + 1]); + if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) { + let mut errs = vec![i, i + 1]; + if i > 0 { + errs.push(i - 1); + } + return Err(errs); + } + i += 1; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn sample_input() { + let strings: Vec = input!("d2p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, 4); + } +} diff --git a/d1/README.md b/d1/README.md new file mode 100644 index 0000000..853343b --- /dev/null +++ b/d1/README.md @@ -0,0 +1,24 @@ +Advent of code 2024 + +Day 1 + +Usage: + + rustc d1p1.rs + cat input.txt | ./d1p1 + +Part 1: + +Parse each line into a pair of ints; store them in a pair of heaps. +Convert heaps into sorted lists. Iterate through them together +and find the absolute difference between each pair of numbers. + +Part 2: + +Parse each line into a pair of ints; store the first in an array, +place the second into a map that accumulate the number of times +a value is seen. + +Iterate through the array, adding the number times the number of +times it was seen in the map. + diff --git a/d1/d1p1.rs b/d1/d1p1.rs new file mode 100644 index 0000000..fdb696a --- /dev/null +++ b/d1/d1p1.rs @@ -0,0 +1,22 @@ +use std::collections::BinaryHeap; +use std::io; + +fn main() -> io::Result<()> { + let mut l1 = BinaryHeap::::new(); + let mut l2 = BinaryHeap::::new(); + for line in io::stdin().lines() { + let line = line?; + let parts: Vec<&str> = line.trim().split_whitespace().collect(); + let (n1, n2) = (parts[0], parts[1]); + l1.push(n1.parse().unwrap()); + l2.push(n2.parse().unwrap()); + } + let l1 = l1.into_sorted_vec(); + let l2 = l2.into_sorted_vec(); + let mut sum = 0; + for (n1, n2) in l1.into_iter().zip(l2.into_iter()) { + sum += n1.abs_diff(n2); + } + println!("{}", sum); + Ok(()) +} diff --git a/d1/d1p1.txt b/d1/d1p1.txt new file mode 100644 index 0000000..dfca0b1 --- /dev/null +++ b/d1/d1p1.txt @@ -0,0 +1,6 @@ +3 4 +4 3 +2 5 +1 3 +3 9 +3 3 \ No newline at end of file diff --git a/d1/d1p2.rs b/d1/d1p2.rs new file mode 100644 index 0000000..0c7f9e2 --- /dev/null +++ b/d1/d1p2.rs @@ -0,0 +1,21 @@ +use std::collections::HashMap; +use std::io; + +fn main() -> io::Result<()> { + let mut l1: Vec = vec!(); + let mut l2: HashMap = HashMap::default(); + for line in io::stdin().lines() { + let line = line?; + let parts: Vec<&str> = line.trim().split_whitespace().collect(); + let (n1, n2) = (parts[0], parts[1]); + l1.push(n1.parse().unwrap()); + let v = l2.entry(n2.parse::().unwrap()).or_insert(0); + *v += 1; + } + let mut sum = 0; + for n1 in l1.into_iter() { + sum += n1*l2.get(&n1).unwrap_or(&0); + } + println!("{}", sum); + Ok(()) +} diff --git a/d1p1 b/d1p1 new file mode 100755 index 0000000..0110f93 Binary files /dev/null and b/d1p1 differ diff --git a/d2/README.md b/d2/README.md new file mode 100644 index 0000000..63a63b8 --- /dev/null +++ b/d2/README.md @@ -0,0 +1,136 @@ +# Advent of code 2024 + +Write up for day 2. The below snippets exclude some boilerplate +related to reading the input, and the test cases are excluded. + +The gist of both of todays problems is that you want to apply some +rules to a sequence of numbers. There are 2 types of rules. + +Rules that apply to 'pairs' of numbers (adjacent numbers in +the sequence). These rules are: + +- abs(a-b) >= 1 +- abs(a-b) <= 3 + +Rules that apply to the sequence as a whole. The rules are: + +- All numbers are 'going to the same direction' (up or down) + +The second part made this a little bit more complicated by saying "allow 1 +failure". + +### d2p1.rs + +First, we created a trivial helper to us track up/down and allow comparing directions: + +```rust + +#[derive(PartialEq)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} +``` + +Then the core of the problem. We iterate through each line, convert it to a vector +of numbers. + +This helper is responsible for checking the results of a single set of samples. +Rather than using a fancy `for in` loop, I chose to iterate using a while loop. +In each iteration, I validate the rules against `report[i]` and `report[i+1]`. + +```rust +// Tests the report, and returns indexes around where a failure is detected. +fn test(reports: &[usize]) -> Result<(), ()> { + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i + 1]); + if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) { + return Err(()) + } + i += 1; + } + Ok(()) +} +``` + +```rust + +fn solve(lines: Vec) -> SResult { + let mut failed = 0; + for line in lines.iter() { + let reports: Vec = line.split_whitespace().map(|v| v.parse::().unwrap()).collect(); + match test(&reports) { + Ok(_) => (), + Err(_) => failed += 1, + }; + } + Ok(lines.len() - failed) +} + +``` +### d2p2.rs + +We enhance the helper above to return impacted indexes rather than nothing +if something fails: + +```rust +// fn test + if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) { + let mut errs = vec![i, i + 1]; + if i > 0 { + errs.push(i - 1); + } + return Err(errs); + } +``` + +Next, we iterate through all the lines and check if they pass + +```rust + +fn solve(lines: Vec) -> SResult { + let mut fail_count = 0; + for line in lines.iter() { + let reports: Vec = line + .split_whitespace() + .map(|v| v.parse::().unwrap()) + .collect(); + let problems = match test(&reports) { + // Cool, nothing to see here + Ok(_) => continue, + Err(e) => e, + }; +``` + +If they don't pass, we try removing one of the elements and see what happens. + +```rust + let mut pass = false; + for problem in problems { + let mut l1 = reports.clone(); + l1.remove(problem); + if test(&l1).is_ok() { + pass = true; + break; + } + } + if !pass { + fail_count += 1; + } + } + Ok(lines.len() - fail_count) +} + +``` diff --git a/d2/d2p1.rs b/d2/d2p1.rs new file mode 100644 index 0000000..627f603 --- /dev/null +++ b/d2/d2p1.rs @@ -0,0 +1,58 @@ +use advent_of_code_2024::{make_main, SResult}; + +make_main!(); + +// CODE + +#[derive(PartialEq)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} + +fn solve(lines: Vec) -> SResult { + let mut failed = 0; + for line in lines.iter() { + let reports: Vec = line.split_whitespace().map(|v| v.parse::().unwrap()).collect(); + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i+1]); + if delta < 1 || delta > 3 { + failed += 1; + break; + } + if direction != Direction::from(reports[i], reports[i+1]) { + failed += 1; + break; + } + i += 1; + } + } + Ok(lines.len() - failed) +} + +// CODE + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn sample_input() { + let strings: Vec = input!("d2p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, 2); + } +} \ No newline at end of file diff --git a/d2/d2p1.txt b/d2/d2p1.txt new file mode 100644 index 0000000..82cd679 --- /dev/null +++ b/d2/d2p1.txt @@ -0,0 +1,6 @@ +7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9 \ No newline at end of file diff --git a/d2/d2p2.rs b/d2/d2p2.rs new file mode 100644 index 0000000..1ba8b43 --- /dev/null +++ b/d2/d2p2.rs @@ -0,0 +1,80 @@ +use advent_of_code_2024::{make_main, SResult}; + +make_main!(); + +// CODE +#[derive(PartialEq, Clone, Copy)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} + +fn solve(lines: Vec) -> SResult { + let mut fail_count = 0; + for line in lines.iter() { + let reports: Vec = line + .split_whitespace() + .map(|v| v.parse::().unwrap()) + .collect(); + let problems = match test(&reports) { + // Cool, nothing to see here + Ok(_) => continue, + Err(e) => e, + }; + let mut pass = false; + for problem in problems { + let mut l1 = reports.clone(); + l1.remove(problem); + if test(&l1).is_ok() { + pass = true; + break; + } + } + if !pass { + fail_count += 1; + } + } + Ok(lines.len() - fail_count) +} + +// Tests the report, and returns indexes around where a failure is detected. +fn test(reports: &[usize]) -> Result<(), Vec> { + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i + 1]); + if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) { + let mut errs = vec![i, i + 1]; + if i > 0 { + errs.push(i - 1); + } + return Err(errs); + } + i += 1; + } + Ok(()) +} +// CODE + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn sample_input() { + let strings: Vec = input!("d2p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, 4); + } +} diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..39bacff --- /dev/null +++ b/default.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } +) { + src = ./.; +}).defaultNix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..304fadb --- /dev/null +++ b/flake.lock @@ -0,0 +1,93 @@ +{ + "nodes": { + "naersk": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1721727458, + "narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=", + "owner": "nix-community", + "repo": "naersk", + "rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "master", + "repo": "naersk", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 0, + "narHash": "sha256-df3dJApLPhd11AlueuoN0Q4fHo/hagP75LlM5K1sz9g=", + "path": "/nix/store/ly4s3hw35dd1c2vsd694y2715pc1d2c1-source", + "type": "path" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1733024928, + "narHash": "sha256-n/DOfpKH1vkukuBnach91QBQId2dr5tkE7/7UrkV2zw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2c27ab2e60502d1ebb7cf38909de38663f762a79", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "naersk": "naersk", + "nixpkgs": "nixpkgs_2", + "utils": "utils" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..2149150 --- /dev/null +++ b/flake.nix @@ -0,0 +1,22 @@ +{ + inputs = { + naersk.url = "github:nix-community/naersk/master"; + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, utils, naersk }: + utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + naersk-lib = pkgs.callPackage naersk { }; + in + { + defaultPackage = naersk-lib.buildPackage ./.; + devShell = with pkgs; mkShell { + buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy zip bash ]; + RUST_SRC_PATH = rustPlatform.rustLibSrc; + }; + } + ); +} diff --git a/gen_writeup.sh b/gen_writeup.sh new file mode 100755 index 0000000..ab765b1 --- /dev/null +++ b/gen_writeup.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +shopt -s extdebug + +mkdir d$1 +cp src/bin/d${1}* d$1 + +cat < d$1/README.md +# Advent of code 2024 + +Write up for day ${1}. The below snippets exclude some boilerplate +related to reading the input, and the test cases are excluded. + +EOF + +for file in $(ls src/bin/d${1}p*.rs); do + echo -e "### $(basename $file)" >> d${1}/README.md + echo -e '\n```rust' >> d${1}/README.md + awk '$0=="// CODE"{cnt+=1;next}cnt%2' $file >> d${1}/README.md + echo '```' >> d${1}/README.md +done \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..77db547 --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } +) { + src = ./.; +}).shellNix diff --git a/src/bin/d1p1.rs b/src/bin/d1p1.rs new file mode 100644 index 0000000..fdb696a --- /dev/null +++ b/src/bin/d1p1.rs @@ -0,0 +1,22 @@ +use std::collections::BinaryHeap; +use std::io; + +fn main() -> io::Result<()> { + let mut l1 = BinaryHeap::::new(); + let mut l2 = BinaryHeap::::new(); + for line in io::stdin().lines() { + let line = line?; + let parts: Vec<&str> = line.trim().split_whitespace().collect(); + let (n1, n2) = (parts[0], parts[1]); + l1.push(n1.parse().unwrap()); + l2.push(n2.parse().unwrap()); + } + let l1 = l1.into_sorted_vec(); + let l2 = l2.into_sorted_vec(); + let mut sum = 0; + for (n1, n2) in l1.into_iter().zip(l2.into_iter()) { + sum += n1.abs_diff(n2); + } + println!("{}", sum); + Ok(()) +} diff --git a/src/bin/d1p1.txt b/src/bin/d1p1.txt new file mode 100644 index 0000000..dfca0b1 --- /dev/null +++ b/src/bin/d1p1.txt @@ -0,0 +1,6 @@ +3 4 +4 3 +2 5 +1 3 +3 9 +3 3 \ No newline at end of file diff --git a/src/bin/d1p2.rs b/src/bin/d1p2.rs new file mode 100644 index 0000000..0c7f9e2 --- /dev/null +++ b/src/bin/d1p2.rs @@ -0,0 +1,21 @@ +use std::collections::HashMap; +use std::io; + +fn main() -> io::Result<()> { + let mut l1: Vec = vec!(); + let mut l2: HashMap = HashMap::default(); + for line in io::stdin().lines() { + let line = line?; + let parts: Vec<&str> = line.trim().split_whitespace().collect(); + let (n1, n2) = (parts[0], parts[1]); + l1.push(n1.parse().unwrap()); + let v = l2.entry(n2.parse::().unwrap()).or_insert(0); + *v += 1; + } + let mut sum = 0; + for n1 in l1.into_iter() { + sum += n1*l2.get(&n1).unwrap_or(&0); + } + println!("{}", sum); + Ok(()) +} diff --git a/src/bin/d2p1.rs b/src/bin/d2p1.rs new file mode 100644 index 0000000..75fff7f --- /dev/null +++ b/src/bin/d2p1.rs @@ -0,0 +1,62 @@ +use advent_of_code_2024::{make_main, SResult}; + +make_main!(); + +// CODE + +#[derive(PartialEq)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} + +fn solve(lines: Vec) -> SResult { + let mut failed = 0; + for line in lines.iter() { + let reports: Vec = line.split_whitespace().map(|v| v.parse::().unwrap()).collect(); + match test(&reports) { + Ok(_) => (), + Err(_) => failed += 1, + }; + } + Ok(lines.len() - failed) +} + +// Tests the report, and returns indexes around where a failure is detected. +fn test(reports: &[usize]) -> Result<(), ()> { + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i + 1]); + if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) { + return Err(()); + } + i += 1; + } + Ok(()) +} + +// CODE + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn sample_input() { + let strings: Vec = input!("d2p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, 2); + } +} \ No newline at end of file diff --git a/src/bin/d2p1.txt b/src/bin/d2p1.txt new file mode 100644 index 0000000..82cd679 --- /dev/null +++ b/src/bin/d2p1.txt @@ -0,0 +1,6 @@ +7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9 \ No newline at end of file diff --git a/src/bin/d2p2.rs b/src/bin/d2p2.rs new file mode 100644 index 0000000..3c2cac9 --- /dev/null +++ b/src/bin/d2p2.rs @@ -0,0 +1,80 @@ +use advent_of_code_2024::{make_main, SResult}; + +make_main!(); + +// CODE +#[derive(PartialEq)] +enum Direction { + Up, + Down, +} + +impl Direction { + fn from(a: usize, b: usize) -> Self { + if a > b { + Direction::Down + } else { + Direction::Up + } + } +} + +fn solve(lines: Vec) -> SResult { + let mut fail_count = 0; + for line in lines.iter() { + let reports: Vec = line + .split_whitespace() + .map(|v| v.parse::().unwrap()) + .collect(); + let problems = match test(&reports) { + // Cool, nothing to see here + Ok(_) => continue, + Err(e) => e, + }; + let mut pass = false; + for problem in problems { + let mut l1 = reports.clone(); + l1.remove(problem); + if test(&l1).is_ok() { + pass = true; + break; + } + } + if !pass { + fail_count += 1; + } + } + Ok(lines.len() - fail_count) +} + +// Tests the report, and returns indexes around where a failure is detected. +fn test(reports: &[usize]) -> Result<(), Vec> { + let mut i = 0; + let direction = Direction::from(reports[0], reports[1]); + while i + 1 < reports.len() { + let delta = reports[i].abs_diff(reports[i + 1]); + if delta < 1 || delta > 3 || direction != Direction::from(reports[i], reports[i + 1]) { + let mut errs = vec![i, i + 1]; + if i > 0 { + errs.push(i - 1); + } + return Err(errs); + } + i += 1; + } + Ok(()) +} +// CODE + +#[cfg(test)] +mod tests { + use advent_of_code_2024::input; + + use super::*; + #[test] + fn sample_input() { + let strings: Vec = input!("d2p1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, 4); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5d615af --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,21 @@ +#[macro_export] +macro_rules! make_main { + () => { + fn main() -> Result<(), Box> { + use std::io; + let lines: Vec = io::stdin().lines().map(|s| s.unwrap()).collect(); + let res = solve(lines)?; + println!("{}", res); + Ok(()) + } + }; +} + +#[macro_export] +macro_rules! input { + ($x:expr) => { + include_str!($x).split_terminator('\n').map(|v| String::from(v)).collect() + }; +} + +pub type SResult = Result>; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}