Add solution for 2022 day 09 part 1
This commit is contained in:
parent
4eb67b02d0
commit
7b2dc1d04c
4
2022/Cargo.lock
generated
4
2022/Cargo.lock
generated
@ -40,6 +40,10 @@ 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,6 +8,7 @@ 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 | | | |
|
| 09 | ✓ | | [Rust] |
|
||||||
| 10 | | | |
|
| 10 | | | |
|
||||||
| 11 | | | |
|
| 11 | | | |
|
||||||
| 12 | | | |
|
| 12 | | | |
|
||||||
|
12
2022/day-09/Cargo.toml
Normal file
12
2022/day-09/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "aoc-2022-09"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
5
2022/day-09/Justfile
Normal file
5
2022/day-09/Justfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@part PART INPUT_FILE="inputs/puzzle.txt":
|
||||||
|
cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
cargo clean
|
2000
2022/day-09/inputs/puzzle.txt
Normal file
2000
2022/day-09/inputs/puzzle.txt
Normal file
File diff suppressed because it is too large
Load Diff
8
2022/day-09/inputs/test.txt
Normal file
8
2022/day-09/inputs/test.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
R 4
|
||||||
|
U 4
|
||||||
|
L 3
|
||||||
|
D 1
|
||||||
|
R 4
|
||||||
|
D 1
|
||||||
|
L 5
|
||||||
|
R 2
|
95
2022/day-09/src/bin/part_one.rs
Normal file
95
2022/day-09/src/bin/part_one.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
use std::{env, io};
|
||||||
|
|
||||||
|
use aoc_2022_09::{parse_input, Instruction, Position, VisitedMap};
|
||||||
|
|
||||||
|
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 head_pos = Position(0, 0);
|
||||||
|
let mut tail_pos = Position(0, 0);
|
||||||
|
let mut tail_visited = VisitedMap::new();
|
||||||
|
|
||||||
|
tail_visited.insert(tail_pos.clone(), 1);
|
||||||
|
|
||||||
|
for instruction in instructions {
|
||||||
|
(head_pos, tail_pos) =
|
||||||
|
apply_instruction(&instruction, &head_pos, &tail_pos, &mut tail_visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(tail_visited.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_instruction(
|
||||||
|
instruction: &Instruction,
|
||||||
|
head_pos: &Position,
|
||||||
|
tail_pos: &Position,
|
||||||
|
tail_visited: &mut VisitedMap,
|
||||||
|
) -> (Position, Position) {
|
||||||
|
let mut tmp_head_pos = head_pos.clone();
|
||||||
|
let mut tmp_tail_pos = tail_pos.clone();
|
||||||
|
|
||||||
|
let (change, amount) = match *instruction {
|
||||||
|
Instruction::Up(dist) => (Position(1, 0), dist),
|
||||||
|
Instruction::Right(dist) => (Position(0, 1), dist),
|
||||||
|
Instruction::Left(dist) => (Position(0, -1), dist),
|
||||||
|
Instruction::Down(dist) => (Position(-1, 0), dist),
|
||||||
|
};
|
||||||
|
|
||||||
|
for _ in 1..=amount {
|
||||||
|
tmp_head_pos += change.clone();
|
||||||
|
|
||||||
|
let dx = tmp_head_pos.0 - tmp_tail_pos.0;
|
||||||
|
let dxa = dx.abs();
|
||||||
|
let dy = tmp_head_pos.1 - tmp_tail_pos.1;
|
||||||
|
let dya = dy.abs();
|
||||||
|
let same_row = tmp_head_pos.0 == tmp_tail_pos.0;
|
||||||
|
let same_col = tmp_head_pos.1 == tmp_tail_pos.1;
|
||||||
|
let mut head_changed = false;
|
||||||
|
|
||||||
|
if (!same_row && !same_col) && (dxa > 1 || dya > 1) {
|
||||||
|
let x = if dx.is_negative() { -1 } else { 1 };
|
||||||
|
let y = if dy.is_negative() { -1 } else { 1 };
|
||||||
|
tmp_tail_pos += Position(x, y);
|
||||||
|
head_changed = true;
|
||||||
|
} else if dxa > 1 || dya > 1 {
|
||||||
|
tmp_tail_pos += change.clone();
|
||||||
|
head_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if head_changed {
|
||||||
|
tail_visited
|
||||||
|
.entry(tmp_tail_pos.clone())
|
||||||
|
.and_modify(|v| *v += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(tmp_head_pos, tmp_tail_pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
}
|
||||||
|
}
|
73
2022/day-09/src/lib.rs
Normal file
73
2022/day-09/src/lib.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs::File,
|
||||||
|
io::{self, BufRead, BufReader},
|
||||||
|
ops::{Add, AddAssign},
|
||||||
|
path::Path,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct Position(pub isize, pub isize);
|
||||||
|
|
||||||
|
impl Add for Position {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 + rhs.0, self.1 + rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Position {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.0 += rhs.0;
|
||||||
|
self.1 += rhs.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type VisitedMap = HashMap<Position, u32>;
|
||||||
|
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) (32% completed)
|
- [2022](2022/README.md) (34% completed)
|
||||||
|
Loading…
Reference in New Issue
Block a user