broken implementation of day 9
This commit is contained in:
		@@ -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]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user