diff --git a/src/day_three.rs b/src/day_three.rs index 5b13a59..25e7544 100644 --- a/src/day_three.rs +++ b/src/day_three.rs @@ -1,50 +1,60 @@ +use std::cmp::Ordering; use std::collections::BTreeSet; use std::io; use std::iter::{repeat, successors}; -fn next(c: (i32, i32), direction: &str) -> (i32, i32) { +#[derive(Copy, Clone, Eq, Debug)] +struct Coord(usize, (i32, i32)); + +impl PartialEq for Coord { + fn eq(&self, other: &Self) -> bool { + self.1 == other.1 + } +} + +impl Ord for Coord { + fn cmp(&self, other: &Self) -> Ordering { + (self.1).cmp(&(other.1)) + } +} + +impl PartialOrd for Coord { + fn partial_cmp(&self, other: &Self) -> Option { + self.1.partial_cmp(&other.1) + } +} + +fn next(c: (i32, i32), direction: char) -> (i32, i32) { match direction { - "R" => (c.0 + 1, c.1), - "L" => (c.0 - 1, c.1), - "U" => (c.0, c.1 + 1), - "D" => (c.0, c.1 - 1), + 'R' => (c.0 + 1, c.1), + 'L' => (c.0 - 1, c.1), + 'U' => (c.0, c.1 + 1), + 'D' => (c.0, c.1 - 1), _ => panic!("Wrong direction format!"), } } -fn direction_length(entry: String) -> (String, usize) { - ( - entry.chars().nth(0).unwrap().to_string(), - entry[1..].parse().unwrap(), - ) -} - -fn to_coordinates(entries: Vec) -> BTreeSet<(i32, i32)> { +fn to_coordinates(entries: Vec) -> BTreeSet { let mut wire = BTreeSet::new(); let mut it = entries .into_iter() - .map(direction_length) + .map(|entry| (entry.chars().nth(0).unwrap(), entry[1..].parse().unwrap())) .flat_map(|(direction, length)| repeat(direction).take(length)); - successors( - it.next() - .map(|direction| (next((0, 0), direction.as_ref()))), - |c| it.next().map(|direction| (next(*c, direction.as_ref()))), - ) + successors(it.next().map(|direction| (next((0, 0), direction))), |c| { + it.next().map(|direction| (next(*c, direction))) + }) + .enumerate() .for_each(|c| { - wire.insert(c); + wire.insert(Coord(c.0 + 1, c.1)); }); wire } -fn distance(position: (i32, i32)) -> i32 { - position.0.abs() + position.1.abs() -} - -fn closest(input: String) -> Option { - let entries: Vec> = input +fn closest(input: &str) -> Option { + let entries: Vec> = input .trim() .split("\n") .map(|line| line.split(",").map(String::from).collect()) @@ -54,32 +64,49 @@ fn closest(input: String) -> Option { entries[0] .intersection(&entries[1]) .cloned() - .map(distance) + .map(|c| (c.1).0.abs() + (c.1).1.abs()) .min() } -fn first(input: String) -> Option {} +fn first(input: &str) -> Option { + let entries: Vec> = input + .trim() + .split("\n") + .map(|line| line.split(",").map(String::from).collect()) + .map(to_coordinates) + .collect(); + + entries[0] + .intersection(&entries[1]) + .cloned() + .map(|c| { + let other = entries[1].get(&c); + (c.0 + other.unwrap().0) as i32 + }) + .min() +} pub fn main() -> io::Result<()> { - let closest = closest(std::include_str!("../day3-input.txt").to_owned()); - println!("{:?}", closest); + let input = std::include_str!("../day3-input.txt"); + println!("{:?}", closest(input)); + println!("{:?}", first(input)); Ok(()) } #[test] fn test_coordinates_for_entry() { - let mut expected: BTreeSet<(i32, i32)> = BTreeSet::new(); + let mut expected: BTreeSet = BTreeSet::new(); for i in 1..11 { - expected.insert((i, 0)); + expected.insert(Coord(i - 1, (i as i32, 0))); } assert_eq!(to_coordinates(vec!["R10".to_owned()]), expected); expected = BTreeSet::new(); - expected.insert((1, 0)); - expected.insert((2, 0)); - expected.insert((2, 1)); - expected.insert((2, 2)); + expected.insert(Coord(0, (1, 0))); + expected.insert(Coord(1, (2, 0))); + expected.insert(Coord(2, (2, 1))); + expected.insert(Coord(3, (2, 2))); let input = "R2,U2".to_owned().split(",").map(String::from).collect(); assert_eq!(to_coordinates(input), expected); } @@ -87,11 +114,19 @@ fn test_coordinates_for_entry() { #[test] fn test_part_one() { let input = "R75,D30,R83,U83,L12,D49,R71,U7,L72\n\ - U62,R66,U55,R34,D71,R55,D58,R83" - .to_owned(); + U62,R66,U55,R34,D71,R55,D58,R83"; assert_eq!(closest(input), Some(159)); let input = "R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51\n\ - U98,R91,D20,R16,D67,R40,U7,R15,U6,R7" - .to_owned(); + U98,R91,D20,R16,D67,R40,U7,R15,U6,R7"; assert_eq!(closest(input), Some(135)); } + +#[test] +fn test_part_two() { + let input = "R75,D30,R83,U83,L12,D49,R71,U7,L72\n\ + U62,R66,U55,R34,D71,R55,D58,R83"; + assert_eq!(first(input), Some(610)); + let input = "R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51\n\ + U98,R91,D20,R16,D67,R40,U7,R15,U6,R7"; + assert_eq!(first(input), Some(464)); +}