add: files so far
This commit is contained in:
@@ -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
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
*.zip
|
||||||
Generated
+7
@@ -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"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "advent-of-code-2024"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Advent of code 2024
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
rustc dp1.rs
|
||||||
|
cat input.txt | dp1.rs
|
||||||
|
|
||||||
|
## Day
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
use std::collections::BinaryHeap;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut l1 = BinaryHeap::<u64>::new();
|
||||||
|
let mut l2 = BinaryHeap::<u64>::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(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
3 4
|
||||||
|
4 3
|
||||||
|
2 5
|
||||||
|
1 3
|
||||||
|
3 9
|
||||||
|
3 3
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut l1: Vec<u64> = vec!();
|
||||||
|
let mut l2: HashMap<u64, u64> = 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::<u64>().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(())
|
||||||
|
}
|
||||||
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut failed = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line.split_whitespace().map(|v| v.parse::<usize>().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<String> = input!("d2p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut fail_count = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|v| v.parse::<usize>().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<usize>> {
|
||||||
|
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<String> = input!("d2p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
use std::collections::BinaryHeap;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut l1 = BinaryHeap::<u64>::new();
|
||||||
|
let mut l2 = BinaryHeap::<u64>::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(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
3 4
|
||||||
|
4 3
|
||||||
|
2 5
|
||||||
|
1 3
|
||||||
|
3 9
|
||||||
|
3 3
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut l1: Vec<u64> = vec!();
|
||||||
|
let mut l2: HashMap<u64, u64> = 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::<u64>().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(())
|
||||||
|
}
|
||||||
+136
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut failed = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line.split_whitespace().map(|v| v.parse::<usize>().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<String>) -> SResult<usize> {
|
||||||
|
let mut fail_count = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|v| v.parse::<usize>().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)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
+58
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut failed = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line.split_whitespace().map(|v| v.parse::<usize>().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<String> = input!("d2p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
+80
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut fail_count = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|v| v.parse::<usize>().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<usize>> {
|
||||||
|
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<String> = input!("d2p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
(import (
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||||
|
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; }
|
||||||
|
) {
|
||||||
|
src = ./.;
|
||||||
|
}).defaultNix
|
||||||
Generated
+93
@@ -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
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
shopt -s extdebug
|
||||||
|
|
||||||
|
mkdir d$1
|
||||||
|
cp src/bin/d${1}* d$1
|
||||||
|
|
||||||
|
cat <<EOF > 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
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
(import (
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||||
|
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; }
|
||||||
|
) {
|
||||||
|
src = ./.;
|
||||||
|
}).shellNix
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
use std::collections::BinaryHeap;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut l1 = BinaryHeap::<u64>::new();
|
||||||
|
let mut l2 = BinaryHeap::<u64>::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(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
3 4
|
||||||
|
4 3
|
||||||
|
2 5
|
||||||
|
1 3
|
||||||
|
3 9
|
||||||
|
3 3
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut l1: Vec<u64> = vec!();
|
||||||
|
let mut l2: HashMap<u64, u64> = 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::<u64>().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(())
|
||||||
|
}
|
||||||
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut failed = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line.split_whitespace().map(|v| v.parse::<usize>().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<String> = input!("d2p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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<String>) -> SResult<usize> {
|
||||||
|
let mut fail_count = 0;
|
||||||
|
for line in lines.iter() {
|
||||||
|
let reports: Vec<usize> = line
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|v| v.parse::<usize>().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<usize>> {
|
||||||
|
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<String> = input!("d2p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! make_main {
|
||||||
|
() => {
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
use std::io;
|
||||||
|
let lines: Vec<String> = 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<T> = Result<T, Box<dyn std::error::Error>>;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user