broken implementation of day 9

This commit is contained in:
Joseph Montanaro 2022-12-09 17:49:56 -08:00
parent 2e2d668269
commit 9236e70abe
4 changed files with 212 additions and 1 deletions

View File

@ -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]

View File

@ -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
View 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
";

View File

@ -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]
}
}