day 9 snake solution
parent
996a1962a5
commit
34ab94f5f0
File diff suppressed because it is too large
Load Diff
|
@ -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());
|
||||||
|
}
|
|
@ -6,3 +6,4 @@ pub mod day5;
|
||||||
pub mod day6;
|
pub mod day6;
|
||||||
pub mod day7;
|
pub mod day7;
|
||||||
pub mod day8;
|
pub mod day8;
|
||||||
|
pub mod day9;
|
||||||
|
|
|
@ -36,6 +36,9 @@ fn run_day(number: i32) -> Result<()> {
|
||||||
8 => {
|
8 => {
|
||||||
days::day8::run()?;
|
days::day8::run()?;
|
||||||
}
|
}
|
||||||
|
9 => {
|
||||||
|
days::day9::run()?;
|
||||||
|
}
|
||||||
_ => return Err(anyhow!("Invalid day provided")),
|
_ => return Err(anyhow!("Invalid day provided")),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
R 5
|
||||||
|
U 8
|
||||||
|
L 8
|
||||||
|
D 3
|
||||||
|
R 17
|
||||||
|
D 10
|
||||||
|
L 25
|
||||||
|
U 20
|
|
@ -0,0 +1,8 @@
|
||||||
|
R 4
|
||||||
|
U 4
|
||||||
|
L 3
|
||||||
|
D 1
|
||||||
|
R 4
|
||||||
|
D 1
|
||||||
|
L 5
|
||||||
|
R 2
|
Loading…
Reference in New Issue