Compare commits
No commits in common. "ed18a04dae8bcc9be14bd62df3b5c86542e0006a" and "4eb67b02d0d2da06f027d17ccf5561e3a05c37c5" have entirely different histories.
ed18a04dae
...
4eb67b02d0
4
2022/Cargo.lock
generated
4
2022/Cargo.lock
generated
@ -40,10 +40,6 @@ version = "0.1.0"
|
|||||||
name = "aoc-2022-08"
|
name = "aoc-2022-08"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aoc-2022-09"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -8,7 +8,6 @@ members = [
|
|||||||
"./day-06",
|
"./day-06",
|
||||||
"./day-07",
|
"./day-07",
|
||||||
"./day-08",
|
"./day-08",
|
||||||
"./day-09",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
| 06 | ✓ | ✓ | [Rust] |
|
| 06 | ✓ | ✓ | [Rust] |
|
||||||
| 07 | ✓ | ✓ | [Rust] |
|
| 07 | ✓ | ✓ | [Rust] |
|
||||||
| 08 | ✓ | ✓ | [Rust] |
|
| 08 | ✓ | ✓ | [Rust] |
|
||||||
| 09 | ✓ | ✓ | [Rust] |
|
| 09 | | | |
|
||||||
| 10 | | | |
|
| 10 | | | |
|
||||||
| 11 | | | |
|
| 11 | | | |
|
||||||
| 12 | | | |
|
| 12 | | | |
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "aoc-2022-09"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
test = false
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
|
@ -1,5 +0,0 @@
|
|||||||
@part PART INPUT_FILE="inputs/puzzle.txt":
|
|
||||||
cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}}
|
|
||||||
|
|
||||||
clean:
|
|
||||||
cargo clean
|
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +0,0 @@
|
|||||||
R 4
|
|
||||||
U 4
|
|
||||||
L 3
|
|
||||||
D 1
|
|
||||||
R 4
|
|
||||||
D 1
|
|
||||||
L 5
|
|
||||||
R 2
|
|
@ -1,8 +0,0 @@
|
|||||||
R 5
|
|
||||||
U 8
|
|
||||||
L 8
|
|
||||||
D 3
|
|
||||||
R 17
|
|
||||||
D 10
|
|
||||||
L 25
|
|
||||||
U 20
|
|
@ -1,44 +0,0 @@
|
|||||||
use std::{env, io};
|
|
||||||
|
|
||||||
use aoc_2022_09::{parse_input, Rope, Visited};
|
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
|
||||||
let infile_path = env::args().nth(1).expect("input file");
|
|
||||||
|
|
||||||
let result = solve(&infile_path)?;
|
|
||||||
|
|
||||||
println!("{result}");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve(path: &str) -> io::Result<usize> {
|
|
||||||
let instructions = parse_input(path)?;
|
|
||||||
let mut rope = Rope::new(2);
|
|
||||||
let mut tail_visited = Visited::new();
|
|
||||||
|
|
||||||
tail_visited.insert(rope.tail().unwrap().clone());
|
|
||||||
|
|
||||||
for instruction in instructions {
|
|
||||||
instruction.apply_to_rope(&mut rope, &mut tail_visited);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(tail_visited.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sample() {
|
|
||||||
let result = solve("inputs/test.txt").unwrap();
|
|
||||||
assert_eq!(13, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn puzzle() {
|
|
||||||
let result = solve("inputs/puzzle.txt").unwrap();
|
|
||||||
assert_eq!(6026, result);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
use std::{env, io};
|
|
||||||
|
|
||||||
use aoc_2022_09::{parse_input, Rope, Visited};
|
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
|
||||||
let infile_path = env::args().nth(1).expect("input file");
|
|
||||||
|
|
||||||
let result = solve(&infile_path)?;
|
|
||||||
|
|
||||||
println!("{result}");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve(path: &str) -> io::Result<usize> {
|
|
||||||
let instructions = parse_input(path)?;
|
|
||||||
let mut rope = Rope::new(10);
|
|
||||||
let mut tail_visited = Visited::new();
|
|
||||||
|
|
||||||
tail_visited.insert(rope.tail().unwrap().clone());
|
|
||||||
|
|
||||||
for instruction in instructions {
|
|
||||||
instruction.apply_to_rope(&mut rope, &mut tail_visited);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(tail_visited.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sample() {
|
|
||||||
let result = solve("inputs/test.txt").unwrap();
|
|
||||||
assert_eq!(1, result);
|
|
||||||
|
|
||||||
let result = solve("inputs/test2.txt").unwrap();
|
|
||||||
assert_eq!(36, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn puzzle() {
|
|
||||||
let result = solve("inputs/puzzle.txt").unwrap();
|
|
||||||
assert_eq!(2273, result);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
use std::{
|
|
||||||
collections::HashSet,
|
|
||||||
fs::File,
|
|
||||||
io::{self, BufRead, BufReader},
|
|
||||||
path::Path,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub type Visited = HashSet<Knot>;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Rope(Vec<Knot>);
|
|
||||||
|
|
||||||
impl Rope {
|
|
||||||
pub fn new(len: usize) -> Self {
|
|
||||||
Self(vec![Knot::default(); len])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn move_head(&mut self, change: (isize, isize)) {
|
|
||||||
let mut knots = self.0.iter_mut();
|
|
||||||
|
|
||||||
let mut next_a = knots.next();
|
|
||||||
|
|
||||||
next_a.as_mut().map(|head_knot| {
|
|
||||||
head_knot.0 += change.0;
|
|
||||||
head_knot.1 += change.1;
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut next_b = knots.next();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if next_a.is_some() && next_b.is_some() {
|
|
||||||
next_a.as_mut().map(|knot_a| {
|
|
||||||
next_b.as_mut().map(|knot_b| {
|
|
||||||
knot_b.follow(&knot_a);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
next_a = next_b;
|
|
||||||
next_b = knots.next();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tail(&self) -> Option<&Knot> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Knot(isize, isize);
|
|
||||||
|
|
||||||
impl Knot {
|
|
||||||
pub fn follow(&mut self, other: &Self) {
|
|
||||||
let dx = other.0 - self.0;
|
|
||||||
let dxa = dx.abs();
|
|
||||||
let dy = other.1 - self.1;
|
|
||||||
let dya = dy.abs();
|
|
||||||
let same_row = self.0 == other.0;
|
|
||||||
let same_col = self.1 == other.1;
|
|
||||||
|
|
||||||
let x = if dx.is_negative() { -1 } else { 1 };
|
|
||||||
let y = if dy.is_negative() { -1 } else { 1 };
|
|
||||||
|
|
||||||
if (!same_row && !same_col) && (dxa > 1 || dya > 1) {
|
|
||||||
self.0 += x;
|
|
||||||
self.1 += y;
|
|
||||||
} else if dxa > 1 {
|
|
||||||
self.0 += x;
|
|
||||||
} else if dya > 1 {
|
|
||||||
self.1 += y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Instruction {
|
|
||||||
Up(isize),
|
|
||||||
Right(isize),
|
|
||||||
Left(isize),
|
|
||||||
Down(isize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Instruction {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(val: &str) -> Result<Self, Self::Err> {
|
|
||||||
let parts = val.split_whitespace().collect::<Vec<&str>>();
|
|
||||||
let [direction, distance, ..] = parts[..] else {
|
|
||||||
return Err("Invalid instruction".to_string());
|
|
||||||
};
|
|
||||||
let distance = distance
|
|
||||||
.parse()
|
|
||||||
.map_err(|_| "Invalid distance value".to_string())?;
|
|
||||||
|
|
||||||
let result = match direction {
|
|
||||||
"U" => Self::Up(distance),
|
|
||||||
"R" => Self::Right(distance),
|
|
||||||
"L" => Self::Left(distance),
|
|
||||||
"D" => Self::Down(distance),
|
|
||||||
_ => return Err("Invalid direction value".to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instruction {
|
|
||||||
pub fn apply_to_rope(&self, rope: &mut Rope, tail_visited: &mut Visited) {
|
|
||||||
let (change, amount) = match *self {
|
|
||||||
Instruction::Up(dist) => ((1, 0), dist),
|
|
||||||
Instruction::Right(dist) => ((0, 1), dist),
|
|
||||||
Instruction::Left(dist) => ((0, -1), dist),
|
|
||||||
Instruction::Down(dist) => ((-1, 0), dist),
|
|
||||||
};
|
|
||||||
|
|
||||||
for _ in 0..amount {
|
|
||||||
let old_tail = rope.tail().unwrap().clone();
|
|
||||||
|
|
||||||
rope.move_head(change);
|
|
||||||
|
|
||||||
let new_tail = rope.tail().unwrap();
|
|
||||||
|
|
||||||
if old_tail != *new_tail {
|
|
||||||
tail_visited.insert(new_tail.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_input<P>(path: P) -> io::Result<Vec<Instruction>>
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
let file = File::open(path)?;
|
|
||||||
let instructions = BufReader::new(file)
|
|
||||||
.lines()
|
|
||||||
.map(|line| line.unwrap().parse().unwrap())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(instructions)
|
|
||||||
}
|
|
@ -9,4 +9,4 @@
|
|||||||
- [2019](2019/README.md) (0% completed)
|
- [2019](2019/README.md) (0% completed)
|
||||||
- [2020](2020/README.md) (20% completed)
|
- [2020](2020/README.md) (20% completed)
|
||||||
- [2021](2021/README.md) (68% completed)
|
- [2021](2021/README.md) (68% completed)
|
||||||
- [2022](2022/README.md) (36% completed)
|
- [2022](2022/README.md) (32% completed)
|
||||||
|
Loading…
Reference in New Issue
Block a user