From 3b06ca1c640015311d9c31ed13bd525768acc8c0 Mon Sep 17 00:00:00 2001 From: Tyler Hallada Date: Thu, 5 Dec 2019 19:56:00 -0500 Subject: [PATCH] Completed day 3 --- day3/Cargo.lock | 6 ++ day3/Cargo.toml | 9 ++ day3/input/input.txt | 2 + day3/input/test1.txt | 2 + day3/input/test2.txt | 2 + day3/input/test3.txt | 2 + day3/src/main.rs | 200 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 223 insertions(+) create mode 100644 day3/Cargo.lock create mode 100644 day3/Cargo.toml create mode 100644 day3/input/input.txt create mode 100644 day3/input/test1.txt create mode 100644 day3/input/test2.txt create mode 100644 day3/input/test3.txt create mode 100644 day3/src/main.rs diff --git a/day3/Cargo.lock b/day3/Cargo.lock new file mode 100644 index 0000000..81ec217 --- /dev/null +++ b/day3/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "day3" +version = "0.1.0" + diff --git a/day3/Cargo.toml b/day3/Cargo.toml new file mode 100644 index 0000000..7b20a0e --- /dev/null +++ b/day3/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day3" +version = "0.1.0" +authors = ["Tyler Hallada "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day3/input/input.txt b/day3/input/input.txt new file mode 100644 index 0000000..bfa570c --- /dev/null +++ b/day3/input/input.txt @@ -0,0 +1,2 @@ +R999,D467,L84,D619,L49,U380,R287,U80,R744,D642,L340,U738,R959,U710,R882,U861,L130,D354,L579,D586,R798,D735,L661,D453,L828,U953,R604,D834,R921,D348,R620,U775,R364,U552,L221,U119,R590,U29,L267,D745,L128,U468,L978,D717,R883,D227,R691,D330,L33,U520,L862,D132,R99,U400,L455,U737,L603,U220,L689,U131,R158,D674,R617,D287,R422,U734,L73,U327,L525,D245,R849,D692,R114,U136,R762,D5,R329,U429,L849,U748,R816,U556,R614,D412,R416,D306,R307,U826,R880,U936,L164,U984,L689,D934,R790,D14,R561,D736,L3,D442,R301,D520,L451,U76,R844,D307,L144,D800,L462,D138,R956,U225,L393,D186,L924,D445,L86,D640,L920,D877,L197,U191,L371,D701,R826,D282,R856,D412,L788,D417,R69,D678,R978,D268,L268,U112,L69,U164,L748,U191,R227,D227,R59,U749,R134,U779,R865,U247,R55,D567,R821,U799,R937,D942,L445,D571,R685,D111,R107,D769,R269,D968,R102,U335,R538,U125,L725,D654,R451,D242,R777,U813,R799,D786,L804,U313,L322,U771,R219,U316,L973,U963,R84,D289,R825,D299,L425,D49,R995,D486,R550,D789,R735,D501,R966,U955,R432,U635,L353,D600,R675,D236,R864,U322,R719,D418,L877,U833,R839,D634,L533,D438,L734,U130,L578,U498,L984,D413,L615,U40,L699,U656,L653,U419,R856,U882,R30,D266,R386,D692,L210,U802,L390,U753,L406,U338,R743,D320,L125,U204,R391,U537,R887,D194,L302,U400,R510,U92,L310,D382,R597,U498,R851,D357,L568,U800,R918,D106,R673,D735,L86,D67,R398,D677,R355,D501,L909,D133,R729,D293,L498,U222,R832,U671,R751,U36,R422,U840,L636,D476,L292,D105,L239,U199,R669,U736,L345,D911,L277,U452,L979,D153,R882,U604,R602,U495,L311,U453,L215,D713,R873 +L996,U773,L865,D472,L988,D570,L388,U458,L87,U885,L115,U55,R75,U582,R695,U883,R83,U285,R96,D244,L647,D359,R136,U107,R912,U871,L844,U395,L63,U899,L205,D137,R549,U221,L859,D429,L809,U127,R304,U679,L511,U144,R926,U95,L805,U811,R42,D248,L546,D644,L551,D897,R368,D391,L224,U164,L490,D991,L146,D615,R536,U247,R10,U998,L957,D233,R706,D926,R760,U438,R270,D983,R134,U738,L262,U301,L480,D635,L702,D715,R479,U500,R19,D291,R368,U203,R305,D999,R106,U355,L683,D298,R90,U968,L254,D936,R89,U496,R253,U688,R99,U637,L783,D451,R673,D762,R997,D50,L488,U551,L871,U388,R949,D371,R584,D908,L880,U523,R557,U436,R520,U587,L56,U18,R397,U541,R660,D444,R51,U187,R221,U902,R726,U303,R97,D817,R185,D218,L240,D67,L259,U334,R821,U629,R21,D970,R282,U155,R555,D678,L99,D570,R863,D405,R941,U584,L303,D109,L871,U180,R595,D226,L670,D943,L127,U647,R452,D570,R75,D284,R414,U404,R515,U993,R408,U488,R890,D318,L415,U969,R769,D976,L732,U1,R489,U655,R930,U638,R649,D254,R161,U287,L659,D26,L477,D821,L124,U538,R17,D711,L203,U888,R904,U648,L908,D65,L215,U283,R698,U28,R72,U214,R499,D89,R489,D58,R949,D91,L710,U960,L755,D402,L27,D873,R61,U607,R57,D548,R369,U622,L244,U19,R61,D606,R928,D968,R10,D988,R816,U500,R915,D400,R546,D283,L627,D919,L259,U337,R374,U795,L355,D989,L224,D77,L872,U901,R476,U765,L320,U768,L937,D437,R141,D822,L326,D324,L498,U994,L518,D857,R973,D681,L710,D590,L879,U499,R488,D151,L242,U988,L944,U683,L24,U491,R823,D246,R872,D654,R28,U581,L142,U31,R435,D686,L147,D102,R952,D607,L959,D929,L46 diff --git a/day3/input/test1.txt b/day3/input/test1.txt new file mode 100644 index 0000000..73b95a1 --- /dev/null +++ b/day3/input/test1.txt @@ -0,0 +1,2 @@ +R8,U5,L5,D3 +U7,R6,D4,L4 diff --git a/day3/input/test2.txt b/day3/input/test2.txt new file mode 100644 index 0000000..620a05e --- /dev/null +++ b/day3/input/test2.txt @@ -0,0 +1,2 @@ +R75,D30,R83,U83,L12,D49,R71,U7,L72 +U62,R66,U55,R34,D71,R55,D58,R83 diff --git a/day3/input/test3.txt b/day3/input/test3.txt new file mode 100644 index 0000000..4f3a2a4 --- /dev/null +++ b/day3/input/test3.txt @@ -0,0 +1,2 @@ +R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51 +U98,R91,D20,R16,D67,R40,U7,R15,U6,R7 diff --git a/day3/src/main.rs b/day3/src/main.rs new file mode 100644 index 0000000..9a06116 --- /dev/null +++ b/day3/src/main.rs @@ -0,0 +1,200 @@ +use std::collections::HashMap; +use std::error::Error; +use std::fs; +use std::result; +use std::str::FromStr; + +const INPUT: &str = "input/input.txt"; + +type Result = result::Result>; + +#[derive(Debug, PartialEq)] +struct CrossedWires { + wires: Vec>, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct Point { + x: i32, + y: i32, +} + +#[derive(Debug, PartialEq)] +struct Move { + direction: Direction, + distance: i32, +} + +#[derive(Debug, PartialEq)] +enum Direction { + Up, + Down, + Right, + Left, +} + +impl CrossedWires { + fn find_intersections(&self) -> HashMap { + let mut intersections: HashMap = HashMap::new(); + + let mut occupied_points: HashMap = HashMap::new(); + for (wire_index, wire) in self.wires.iter().enumerate() { + let mut steps = 0; + let mut end_point = Point { x: 0, y: 0 }; + for movement in wire.iter() { + let mut point = end_point.clone(); + for _ in 0..movement.distance { + match movement.direction { + Direction::Up => point.y += 1, + Direction::Down => point.y -= 1, + Direction::Right => point.x += 1, + Direction::Left => point.x -= 1, + }; + steps += 1; + if wire_index == 0 { + occupied_points.insert(point, steps); + } else { + if let Some(first_wire_steps) = occupied_points.get(&point) { + intersections.insert(point, first_wire_steps + steps); + } + } + } + end_point = point; + } + } + + intersections + } +} + +impl FromStr for CrossedWires { + type Err = Box; + + fn from_str(s: &str) -> Result { + let mut wires = s.split("\n"); + let first_moves = wires.next().expect("First wire not found in input"); + let second_moves = wires.next().expect("Second wire not found in input"); + + Ok(CrossedWires { + wires: vec![ + get_moves_from_string(first_moves)?, + get_moves_from_string(second_moves)?, + ], + }) + } +} + +impl From for Direction { + fn from(c: char) -> Direction { + match c { + 'U' => Direction::Up, + 'D' => Direction::Down, + 'R' => Direction::Right, + 'L' => Direction::Left, + _ => panic!("Could not parse direction: {}", c), + } + } +} + +fn get_moves_from_string(moves_string: &str) -> Result> { + let moves_strings = moves_string.split(","); + let mut moves = vec![]; + + for wire_move in moves_strings { + let mut wire_move = wire_move.chars(); + let direction: Direction = + Direction::from(wire_move.next().expect("Invalid empty wire move")); + let distance: i32 = wire_move.collect::().parse()?; + + moves.push(Move { + direction, + distance, + }); + } + Ok(moves) +} + +fn read_wires(filename: &str) -> Result { + let wires = fs::read_to_string(filename)?; + Ok(wires.parse()?) +} + +fn solve_part1() -> Result { + let wires = read_wires(INPUT)?; + let intersections = wires.find_intersections(); + let intersect_points = intersections.keys(); + let distances = intersect_points.map(|point| point.x.abs() + point.y.abs()); + Ok(distances.min().expect("No intersections found")) +} + +fn solve_part2() -> Result { + let wires = read_wires(INPUT)?; + let intersections = wires.find_intersections(); + let min_intersection = intersections + .iter() + .min_by_key(|(_, steps)| steps.clone()).expect("No intersections found"); + Ok(*min_intersection.1 as i32) +} + +fn main() -> Result<()> { + println!("Part 1: {}", solve_part1()?); + println!("Part 2: {}", solve_part2()?); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_INPUT1: &str = "input/test1.txt"; + // const TEST_INPUT2: &str = "input/test2.txt"; + // const TEST_INPUT3: &str = "input/test3.txt"; + + #[test] + fn reads_wires() { + assert_eq!( + read_wires(TEST_INPUT1).unwrap(), + CrossedWires { + wires: vec![ + vec![ + Move { + direction: Direction::Right, + distance: 8 + }, + Move { + direction: Direction::Up, + distance: 5 + }, + Move { + direction: Direction::Left, + distance: 5 + }, + Move { + direction: Direction::Down, + distance: 3 + }, + ], + vec![ + Move { + direction: Direction::Up, + distance: 7 + }, + Move { + direction: Direction::Right, + distance: 6 + }, + Move { + direction: Direction::Down, + distance: 4 + }, + Move { + direction: Direction::Left, + distance: 4 + }, + ], + ], + } + ); + } +}