169 lines
3.7 KiB
Rust
169 lines
3.7 KiB
Rust
#![feature(iterator_try_collect)]
|
|
|
|
use std::fs;
|
|
use std::collections::HashSet;
|
|
use std::str;
|
|
use std::error::Error;
|
|
use std::str::FromStr;
|
|
use std::io::{self, BufRead};
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
enum Direction {
|
|
Right,
|
|
Left,
|
|
Up,
|
|
Down,
|
|
}
|
|
|
|
impl FromStr for Direction {
|
|
type Err = &'static str;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"R" => Ok(Direction::Right),
|
|
"L" => Ok(Direction::Left),
|
|
"U" => Ok(Direction::Up),
|
|
"D" => Ok(Direction::Down),
|
|
_ => Err("Can't parse into a direction"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
struct MoveDirective {
|
|
direction: Direction,
|
|
amount: i32,
|
|
}
|
|
|
|
impl FromStr for MoveDirective {
|
|
type Err = Box<dyn Error>;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s.len() {
|
|
x if x >= 3 => {
|
|
Ok(MoveDirective {
|
|
direction: s[0..1].parse()?,
|
|
amount: s[2..].parse()?,
|
|
})
|
|
},
|
|
_ => Err("Can't parse.".into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
trait Movable {
|
|
fn do_move(&mut self, direction: &Direction);
|
|
}
|
|
|
|
type Pos = (i32, i32);
|
|
|
|
impl Movable for Pos {
|
|
fn do_move(&mut self, direction: &Direction) {
|
|
match direction {
|
|
Direction::Left => self.0 -= 1,
|
|
Direction::Right => self.0 += 1,
|
|
Direction::Up => self.1 -= 1,
|
|
Direction::Down => self.1 += 1,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
struct Rope {
|
|
front: Pos,
|
|
end: Pos,
|
|
}
|
|
|
|
impl Movable for Rope {
|
|
fn do_move(&mut self, direction: &Direction) {
|
|
self.front.do_move(direction);
|
|
self.update();
|
|
}
|
|
}
|
|
|
|
impl Rope {
|
|
fn new() -> Rope {
|
|
Rope{
|
|
front: (0, 0),
|
|
end: (0, 0),
|
|
}
|
|
}
|
|
|
|
fn update(&mut self) {
|
|
fn process(f: i32, e: i32, f2: i32, e2: i32) -> Pos {
|
|
// Check difference, clamp if abs greater than 1
|
|
// Then add the clamped difference to the front.
|
|
// E F
|
|
let d = e - f;
|
|
if d == 0 {
|
|
return (f, e2);
|
|
}
|
|
|
|
let abs = d.abs();
|
|
let endpos = f + d.signum();
|
|
(endpos, match abs {
|
|
x if x > 1 => f2,
|
|
_ => e2,
|
|
})
|
|
}
|
|
|
|
(self.end.0, self.end.1) = process(self.front.0, self.end.0, self.front.1, self.end.1);
|
|
(self.end.1, self.end.0) = process(self.front.1, self.end.1, self.front.0, self.end.0);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct EtchASketch(HashSet<Pos>);
|
|
|
|
impl EtchASketch {
|
|
fn new() -> EtchASketch {
|
|
EtchASketch(HashSet::new())
|
|
}
|
|
|
|
fn visit(&mut self, pos: Pos) {
|
|
self.0.insert(pos);
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let filename = "etc/p09.txt";
|
|
let file = fs::File::open(filename).expect("Can't open file");
|
|
let reader = io::BufReader::new(file);
|
|
|
|
let directives: Vec<MoveDirective> = reader.lines().flatten().flat_map(|l| l.parse()).collect();
|
|
let mut etch = EtchASketch::new();
|
|
|
|
let mut rope = Rope::new();
|
|
etch.visit(rope.end);
|
|
for directive in directives {
|
|
dbg!(&directive);
|
|
for _ in 0..directive.amount {
|
|
rope.do_move(&directive.direction);
|
|
etch.visit(rope.end);
|
|
}
|
|
dbg!(&rope);
|
|
}
|
|
|
|
//dbg!(rope, &etch);
|
|
|
|
println!("PART ONE ---------------");
|
|
dbg!(etch.0.len());
|
|
part1();
|
|
println!("\nPART TWO ---------------");
|
|
part2();
|
|
}
|
|
|
|
fn part1() {}
|
|
|
|
fn part2() {}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_input() {
|
|
assert_eq!(MoveDirective{ direction: Direction::Down, amount: 42 }, "D 42".parse().unwrap());
|
|
}
|
|
}
|