#![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 { 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; fn from_str(s: &str) -> Result { 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); 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 = 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()); } }