Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Looking for work!
Took me an extra day to clean it up so I wasn't disgusted with it. I definitely followed the Advent of Code "Brute Force until proven otherwise" approach. I considered doing it by only considering each leg of wire as two endpoints and calculating the intersections, but this was easier and more straightforward.
I also tried out Rust's type aliases to make things read a bit easier, which I'm really happy with.
Part 2 almost got me with a sneaky "Off by Two" error. I forgot to count the step off of the origin on both wires, leading me to be short by 2 on my final answer. A quick test case based on the examples provided showed I landed at 608 instead of 610 and I got suspicious.
Altogether much happier with this than I was last night. :)
/// Day 3: Crossed Wires/// /// Figure out which directions wires go and where they crossusestd::collections::HashSet;usestd::iter::FromIterator;usestd::fs;usestd::ops::Add;/// A coordinate is a 2D location (or Vector change!) with X and Y components#[derive(Debug,PartialEq,Eq,Hash,Copy,Clone)]structCoordinate{x:isize,y:isize,}/// You can Add Coordinates together with + to get a new oneimplAddforCoordinate{typeOutput=Self;fnadd(self,other:Self)->Self{Self{x:self.x+other.x,y:self.y+other.y,}}}implCoordinate{pubfnnew(x:isize,y:isize)->Self{Self{x,y}}}/// A Wire is a chain of coordinates that are electrically connectedtypeWire=Vec<Coordinate>;/// Moves are an ordered list of delta moves to make to form a wiretypeMoves=Vec<Coordinate>;/// Expects two lines of comma separated move strings, one for each wire./// The move strings are of the pattern [UDLR][0-9]+/// [UDLR]: Specifies whether the wire is going up, down, left or right/// [0-9]+: Specifies how many spaces that leg of the wire covers/// /// Returns both processed wiresfnparse_input()->(Wire,Wire){lettext=fs::read_to_string("data/day3.txt").unwrap();letlines:Vec<&str>=text.split("\n").collect();letmutwires=lines.into_iter().map(build_moves).map(make_wire);(wires.next().unwrap(),wires.next().unwrap())}/// Builds a list of Moves out of an input comma separated string as described/// above.fnbuild_moves(text_moves:&str)->Moves{letmutresults:Vec<Coordinate>=Vec::new();forstepintext_moves.split(","){let(direction,count_text)=step.split_at(1);letcount:usize=count_text.parse().unwrap();letmove_coord=ifdirection=="U"{Coordinate::new(0,1)}elseifdirection=="D"{Coordinate::new(0,-1)}elseifdirection=="L"{Coordinate::new(-1,0)}elseifdirection=="R"{Coordinate::new(1,0)}else{panic!("Weird step {}",direction);};for_in0..count{results.push(move_coord);}}results}/// Build a Wire out of relative Movesfnmake_wire(moves:Moves)->Wire{letmutcurrent=Coordinate{x:0,y:0};letmutresults:Wire=Vec::new();forstepinmoves{current=step+current;results.push(current);}results}/// Calculate a Coordinate's absolute distance from the originfnorigin_manhattan_distance(coord:&Coordinate)->usize{(coord.x.abs()+coord.y.abs())asusize}/// Given two Wires, find the location where they cross that is closest to the/// origin (which is where both wires start, and doesn't count as a cross)fnfind_closest_cross(a:&Wire,b:&Wire)->Coordinate{leta_set:HashSet<&Coordinate>=HashSet::from_iter(a.iter());letb_set:HashSet<&Coordinate>=HashSet::from_iter(b.iter());**a_set.intersection(&b_set).min_by_key(|c|origin_manhattan_distance(c)).unwrap()}/// Find the first occurrence of a Coordinate in a Wire (index-wise, but 1-based)fnfind_in_wire(wire:&Wire,target:&Coordinate)->usize{wire.iter().position(|e|e==target).unwrap()+1}/// Find the shortest distance you can travel on each wire (summed) before you/// hit a cross.fnshortest_cross_distance(a:&Wire,b:&Wire)->usize{leta_set:HashSet<&Coordinate>=HashSet::from_iter(a.iter());letb_set:HashSet<&Coordinate>=HashSet::from_iter(b.iter());a_set.intersection(&b_set).map(|c|find_in_wire(a,c)+find_in_wire(b,c)).min().unwrap()}/// Main Day 3 logic to solve the puzzlespubfnrun(){let(a,b)=parse_input();letclosest_cross=find_closest_cross(&a,&b);println!("Closest cross distance is {}",origin_manhattan_distance(&closest_cross));println!("Fewest combined steps: {}",shortest_cross_distance(&a,&b));}
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Took me an extra day to clean it up so I wasn't disgusted with it. I definitely followed the Advent of Code "Brute Force until proven otherwise" approach. I considered doing it by only considering each leg of wire as two endpoints and calculating the intersections, but this was easier and more straightforward.
I also tried out Rust's type aliases to make things read a bit easier, which I'm really happy with.
Part 2 almost got me with a sneaky "Off by Two" error. I forgot to count the step off of the origin on both wires, leading me to be short by 2 on my final answer. A quick test case based on the examples provided showed I landed at 608 instead of 610 and I got suspicious.
Altogether much happier with this than I was last night. :)