add: files so far
This commit is contained in:
+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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user