Refactor to struct and enumerate steps

This commit is contained in:
Vladan Popovic 2019-12-15 23:18:00 +01:00
parent 6acbdc53f1
commit 9d1d057e09

View file

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