1
0
Fork 0

day 9 snake solution

main
Andrew Coleman 2022-12-09 14:40:25 -05:00
parent 996a1962a5
commit 34ab94f5f0
6 changed files with 2272 additions and 0 deletions

2000
2022/day9.txt Normal file

File diff suppressed because it is too large Load Diff

252
2022/src/days/day9.rs Normal file
View File

@ -0,0 +1,252 @@
use anyhow::{anyhow, Result};
use std::collections::{BTreeSet, VecDeque};
use std::fs;
#[derive(Debug)]
enum Dir {
L,
R,
U,
D,
}
type Moves = Vec<(Dir, usize)>;
type Position = (usize, usize);
pub fn run() -> Result<()> {
#[cfg(not(feature = "test_input"))]
let file_contents = fs::read_to_string("day9.txt")?;
#[cfg(feature = "test_input")]
let file_contents = fs::read_to_string("tests/day9-2.txt")?;
let mut moves: Moves = Vec::new();
for line in file_contents.lines() {
let mut parts = line.split_whitespace();
let d = match parts.next() {
Some("L") => Dir::L,
Some("R") => Dir::R,
Some("U") => Dir::U,
Some("D") => Dir::D,
_ => return Err(anyhow!("invalid direction")),
};
let c: usize = parts.next().unwrap().parse().unwrap();
moves.push((d, c));
}
#[cfg(feature = "test_input")]
println!("{:?}", moves);
part_one_moves(&moves);
part_two_moves(&moves);
Ok(())
}
fn part_one_moves(moves: &Moves) {
// HACK: I want to use usize, but puzzle input seems to move into negative coordinates
let mut cur: Position = (1000, 1000);
let mut tpos: VecDeque<Position> = VecDeque::new();
tpos.push_back(cur.clone());
for step in moves.iter() {
let (d, c) = step;
for _ in 1..=*c {
match d {
Dir::L => {
#[cfg(feature = "test_input")]
println!("left");
step_left(&mut cur);
}
Dir::R => {
#[cfg(feature = "test_input")]
println!("right");
step_right(&mut cur);
}
Dir::U => {
#[cfg(feature = "test_input")]
println!("up");
step_up(&mut cur);
}
Dir::D => {
#[cfg(feature = "test_input")]
println!("down");
step_down(&mut cur);
}
}
if let Some(tail) = find_next_tail_position(&cur, tpos.back().unwrap()) {
tpos.push_back(tail);
}
#[cfg(feature = "test_input")]
println!("{:?} {:?}", cur, tpos.back().unwrap());
}
}
#[cfg(feature = "test_input")]
println!("final position {:?}", cur);
let mut unique_tail_positions: BTreeSet<Position> = BTreeSet::new();
for x in tpos.iter() {
unique_tail_positions.insert(*x);
}
println!("part one: {}", unique_tail_positions.len());
}
fn step_left(cur: &mut Position) {
cur.0 -= 1;
}
fn step_right(cur: &mut Position) {
cur.0 += 1;
}
fn step_up(cur: &mut Position) {
cur.1 += 1;
}
fn step_down(cur: &mut Position) {
cur.1 -= 1;
}
fn find_next_tail_position(head: &Position, tail: &Position) -> Option<Position> {
// same col
if head.0 == tail.0 {
if head.1 > tail.1 + 1 {
#[cfg(feature = "test_input")]
println!("up col");
return Some((tail.0, tail.1 + 1));
} else if tail.1 > 1 && head.1 < tail.1 - 1 {
#[cfg(feature = "test_input")]
println!("down col");
return Some((tail.0, tail.1 - 1));
} else {
#[cfg(feature = "test_input")]
println!("not moving same col");
return None;
}
// same row
} else if head.1 == tail.1 {
if head.0 > tail.0 + 1 {
#[cfg(feature = "test_input")]
println!("right row");
return Some((tail.0 + 1, tail.1));
} else if tail.0 > 1 && head.0 < tail.0 - 1 {
#[cfg(feature = "test_input")]
println!("left row");
return Some((tail.0 - 1, tail.1));
} else {
#[cfg(feature = "test_input")]
println!("not moving same row");
return None;
}
// diagonal move
} else {
// left moves
if head.0 < tail.0 {
if tail.1 < head.1 {
if tail.0 - head.0 >= 2 || head.1 - tail.1 >= 2 {
// up-left
#[cfg(feature = "test_input")]
println!("up-left");
return Some((tail.0 - 1, tail.1 + 1));
} else {
#[cfg(feature = "test_input")]
println!("not moving left-up");
return None;
}
} else if tail.1 > head.1 {
if tail.0 - head.0 >= 2 || tail.1 - head.1 >= 2 {
// down-left
#[cfg(feature = "test_input")]
println!("down-left");
return Some((tail.0 - 1, tail.1 - 1));
} else {
#[cfg(feature = "test_input")]
println!("not moving left-down");
return None;
}
} else {
#[cfg(feature = "test_input")]
println!("not moving diagonal left");
return None;
}
// right moves
} else {
if tail.1 < head.1 {
if head.0 - tail.0 >= 2 || head.1 - tail.1 >= 2 {
// up-right
#[cfg(feature = "test_input")]
println!("up-right");
return Some((tail.0 + 1, tail.1 + 1));
} else {
#[cfg(feature = "test_input")]
println!("not moving right-up");
return None;
}
} else if tail.1 > head.1 {
if head.0 - tail.0 >= 2 || tail.1 - head.1 >= 2 {
// down-right
#[cfg(feature = "test_input")]
println!("down-right");
return Some((tail.0 + 1, tail.1 - 1));
} else {
#[cfg(feature = "test_input")]
println!("not moving right-down");
return None;
}
} else {
#[cfg(feature = "test_input")]
println!("not moving diagonal right");
return None;
}
}
//None
}
}
fn part_two_moves(moves: &Moves) {
// HACK: I want to use usize, but puzzle input seems to move into negative coordinates
let mut snake: [Position; 10] = [(1000, 1000); 10];
let mut tail: BTreeSet<Position> = BTreeSet::new();
tail.insert(snake[0]);
for step in moves.iter() {
let (d, c) = step;
for _ in 1..=*c {
match d {
Dir::L => {
#[cfg(feature = "test_input")]
println!("left");
step_left(&mut snake[0]);
}
Dir::R => {
#[cfg(feature = "test_input")]
println!("right");
step_right(&mut snake[0]);
}
Dir::U => {
#[cfg(feature = "test_input")]
println!("up");
step_up(&mut snake[0]);
}
Dir::D => {
#[cfg(feature = "test_input")]
println!("down");
step_down(&mut snake[0]);
}
}
for i in 1..10 {
if let Some(t) = find_next_tail_position(&snake[i - 1], &snake[i]) {
snake[i].0 = t.0;
snake[i].1 = t.1;
}
}
tail.insert(snake[9]);
}
}
println!("part two count: {}", tail.len());
}

View File

@ -6,3 +6,4 @@ pub mod day5;
pub mod day6;
pub mod day7;
pub mod day8;
pub mod day9;

View File

@ -36,6 +36,9 @@ fn run_day(number: i32) -> Result<()> {
8 => {
days::day8::run()?;
}
9 => {
days::day9::run()?;
}
_ => return Err(anyhow!("Invalid day provided")),
}
Ok(())

8
2022/tests/day9-2.txt Normal file
View File

@ -0,0 +1,8 @@
R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20

8
2022/tests/day9.txt Normal file
View File

@ -0,0 +1,8 @@
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2