broken implementation of day 9
This commit is contained in:
parent
2e2d668269
commit
9236e70abe
@ -39,6 +39,10 @@ path = "src/day7.rs"
|
||||
name = "day8"
|
||||
path = "src/day8.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "day9"
|
||||
path = "src/day9.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
@ -8,7 +8,7 @@ const DATA: &'static str = include_str!("../data/day8.txt");
|
||||
// ";
|
||||
|
||||
|
||||
// O(N * (2 * sqrt(N) - 1)), so roughly N^1.5? Where N is number of elements in the grid
|
||||
// O(N * (2 * (sqrt(N) - 1))), so roughly N^1.5? Where N is number of elements in the grid
|
||||
fn is_visible(grid: &Vec<Vec<usize>>, x: usize, y: usize) -> bool {
|
||||
let height = grid[y][x];
|
||||
let rows = grid.len();
|
||||
|
140
2022/src/day9.rs
Normal file
140
2022/src/day9.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Direction {
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
impl FromStr for Direction {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s {
|
||||
"L" => Ok(Direction::Left),
|
||||
"R" => Ok(Direction::Right),
|
||||
"U" => Ok(Direction::Up),
|
||||
"D" => Ok(Direction::Down),
|
||||
_ => Err(format!("Not a valid direction: {s}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
struct Pos {
|
||||
x: isize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Rope<const L: usize> {
|
||||
knots: [Pos; L],
|
||||
tail_visited: HashSet<Pos>
|
||||
}
|
||||
|
||||
impl<const L: usize> Rope<L> {
|
||||
fn new() -> Self {
|
||||
Rope {
|
||||
knots: [Pos {x: 0, y: 0}; L],
|
||||
tail_visited: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_move(&mut self, dir: Direction, count: isize) {
|
||||
for _ in 0..count {
|
||||
let head = &mut self.knots[0];
|
||||
match dir {
|
||||
Direction::Left => head.x -= 1,
|
||||
Direction::Right => head.x += 1,
|
||||
Direction::Up => head.y += 1,
|
||||
Direction::Down => head.y -= 1,
|
||||
}
|
||||
|
||||
for i in 1..(self.knots.len()) {
|
||||
self.move_follower(i);
|
||||
}
|
||||
|
||||
self.tail_visited.insert(*self.knots.last().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
fn move_follower(&mut self, i: usize) {
|
||||
let leader = self.knots[i - 1];
|
||||
let follower = &mut self.knots[i];
|
||||
|
||||
let dx = leader.x - follower.x;
|
||||
let dy = leader.y - follower.y;
|
||||
|
||||
// check to make sure that we didn't do anything wrong previously
|
||||
if dx.abs() + dy.abs() > 3
|
||||
|| dx.abs() == 0 && dy.abs() == 3
|
||||
|| dx.abs() == 3 && dy.abs() == 0
|
||||
{
|
||||
panic!("Invalid head and tail positions: {dx}, {dy}");
|
||||
}
|
||||
|
||||
// head and tail are in line vertically
|
||||
if dx == 0 && dy.abs() == 2 {
|
||||
follower.y += dy / 2; // use integer division to keep the sign of dy
|
||||
}
|
||||
// in line horizontally
|
||||
if dy == 0 && dx.abs() == 2 {
|
||||
follower.x += dx / 2; // similarly
|
||||
}
|
||||
|
||||
// head and tail are offset by 1 horizontaly and 2 vertically
|
||||
if dx.abs() == 1 && dy.abs() == 2 {
|
||||
follower.x += dx;
|
||||
follower.y += dy / 2;
|
||||
}
|
||||
// offset by 1 vertically and 2 horizontally
|
||||
if dy.abs() == 1 && dx.abs() == 2 {
|
||||
follower.y += dy;
|
||||
follower.x += dx / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let instructions = DATA.trim()
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let mut splat = line.split(' ');
|
||||
match (splat.next(), splat.next()) {
|
||||
(Some(dir), Some(dist)) => {
|
||||
let dist = dist.parse().map_err(|_e| format!("Not an integer: {dist}"));
|
||||
Ok((dir.parse()?, dist?))
|
||||
},
|
||||
_ => Err(format!("Could not parse move instruction from line: {line}"))
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<(Direction, isize)>, String>>()?;
|
||||
|
||||
let mut rope = Rope::<10>::new();
|
||||
for (dir, dist) in instructions {
|
||||
rope.do_move(dir, dist)
|
||||
}
|
||||
println!("{}", rope.tail_visited.len());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// const DATA: &'static str = include_str!("../data/day9.txt");
|
||||
const DATA: &'static str = "
|
||||
R 5
|
||||
U 8
|
||||
L 8
|
||||
D 3
|
||||
R 17
|
||||
D 10
|
||||
L 25
|
||||
U 20
|
||||
";
|
@ -0,0 +1,67 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
|
||||
struct Grid<T> {
|
||||
rows: Vec<Vec<T>>
|
||||
}
|
||||
|
||||
|
||||
impl<T> Grid<T> {
|
||||
fn new() -> Self {
|
||||
Grid { rows: vec![] }
|
||||
}
|
||||
|
||||
fn with_default_values<D>(width: usize, height: usize) -> Self
|
||||
where T: Default + Clone
|
||||
{
|
||||
let rows = (0..height)
|
||||
.map(|_i| vec![Default::default(); width])
|
||||
.collect();
|
||||
|
||||
Grid { rows }
|
||||
}
|
||||
|
||||
fn from_rows<I>(rows: I) -> Self
|
||||
where I: Iterator<Item = Vec<T>>
|
||||
{
|
||||
Grid { rows: rows.collect() }
|
||||
}
|
||||
|
||||
fn from_chars<F, E>(src: &str, conv: F) -> Result<Self, E>
|
||||
where F: Fn(char) -> Result<T, E>
|
||||
{
|
||||
let rows: Result<Vec<Vec<T>>, E> = src.lines()
|
||||
.map(|line| {
|
||||
line.chars()
|
||||
.map(|c| conv(c))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Grid { rows: rows? })
|
||||
}
|
||||
|
||||
fn iter_rows(&self) -> impl Iterator<Item = &Vec<T>> {
|
||||
self.rows.iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> Index<[usize; 2]> for Grid<T> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, idx: [usize; 2]) -> &T {
|
||||
let [x, y] = idx;
|
||||
&self.rows[y][x]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> IndexMut<[usize; 2]> for Grid<T> {
|
||||
fn index_mut(&mut self, idx: [usize; 2]) -> &mut T {
|
||||
let [x, y] = idx;
|
||||
&mut self.rows[y][x]
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user