Day 3!
This commit is contained in:
2
inputs/day3
Normal file
2
inputs/day3
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
R998,U367,R735,U926,R23,U457,R262,D473,L353,U242,L930,U895,R321,U683,L333,U623,R105,D527,R437,D473,L100,D251,L958,U384,R655,U543,L704,D759,R529,D176,R835,U797,R453,D650,L801,U437,L468,D841,R928,D747,L803,U677,R942,D851,R265,D684,L206,U763,L566,U774,L517,U337,L86,D585,R212,U656,L799,D953,L24,U388,L465,U656,L467,U649,R658,U519,L966,D290,L979,D819,R208,D907,R941,D458,L882,U408,R539,D939,R557,D771,L448,U460,L586,U148,R678,U360,R715,U312,L12,D746,L958,U216,R275,D278,L368,U663,L60,D543,L605,D991,L369,D599,R464,D387,L835,D876,L810,U377,L521,U113,L803,U680,L732,D449,R891,D558,L25,U249,L264,U643,L544,U504,R876,U403,R950,U19,L224,D287,R28,U914,R906,U970,R335,U295,R841,D810,R891,D596,R451,D79,R924,U823,L724,U968,R342,D349,R656,U373,R864,U374,L401,D102,L730,D886,R268,D188,R621,U258,L788,U408,L199,D422,R101,U368,L636,U543,R7,U722,L533,U242,L340,D195,R158,D291,L84,U936,L570,D937,L321,U947,L707,U32,L56,U650,L427,U490,L472,U258,R694,U87,L887,U575,R826,D398,R602,U794,R855,U225,R435,U591,L58,U281,L834,D400,R89,D201,L328,U278,L494,D70,L770,D182,L251,D44,R753,U431,R573,D71,R809,U983,L159,U26,R540,U516,R5,D23,L603,U65,L260,D187,R973,U877,R110,U49,L502,D68,R32,U153,R495,D315,R720,D439,R264,D603,R717,U586,R732,D111,R997,U578,L243,U256,R147,D425,L141,U758,R451,U779,R964,D219,L151,D789,L496,D484,R627,D431,R433,D761,R355,U975,L983,U364,L200,U578,L488,U668,L48,D774,R438,D456,L819,D927,R831,D598,L437,U979,R686,U930,L454,D553,L77,D955,L98,U201,L724,U211,R501,U492,L495,U732,L511
|
||||||
|
L998,U949,R912,D186,R359,D694,L878,U542,L446,D118,L927,U175,R434,U473,R147,D54,R896,U890,R300,D537,R254,D322,R758,D690,R231,U269,R288,U968,R638,U192,L732,D355,R879,U451,R336,D872,L141,D842,L126,U584,L973,D940,R890,D75,L104,U340,L821,D590,R577,U859,L948,D199,L872,D751,L368,U506,L308,U827,R181,U94,R670,U901,R739,D48,L985,D801,R722,D597,R654,D606,R183,U646,R939,U677,R32,U936,L541,D934,R316,U354,L415,D930,R572,U571,R147,D609,L534,D406,R872,D527,L816,D960,R652,D429,L402,D858,R374,D930,L81,U106,R977,U251,R917,U966,R353,U732,L613,U280,L713,D937,R481,U52,R746,U203,L500,D557,L209,U249,R89,D58,L149,U872,R331,D460,R343,D423,R392,D160,L876,U981,L399,D642,R525,U515,L537,U113,R886,D516,L301,D680,L236,U399,R460,D869,L942,D280,R669,U476,R683,D97,R199,D444,R137,D489,L704,D120,R753,D100,L737,U375,L495,D325,R48,D269,R575,U895,L184,D10,L502,D610,R618,D744,R585,U861,R695,D775,L942,U64,L819,U161,L332,U513,L461,D366,R273,D493,L197,D97,L6,U63,L564,U59,L699,U30,L68,U861,R35,U564,R540,U371,L115,D595,L412,D781,L185,D41,R207,D264,R999,D799,R421,D117,R377,D571,R268,D947,R77,D2,R712,D600,L516,U389,L868,D762,L996,U205,L178,D339,L844,D629,R67,D732,R109,D858,R630,U470,L121,D542,L751,U353,L61,U770,R952,U703,R264,D537,L569,U55,L795,U389,R836,U166,R585,U275,L734,U966,L130,D357,L260,U719,L647,D606,R547,U575,R791,U686,L597,D486,L774,U386,L163,U912,L234,D238,L948,U279,R789,U300,R117,D28,L833,U835,L340,U693,R343,D573,R882,D241,L731,U812,R600,D663,R902,U402,R831,D802,L577,U920,L947,D538,L192
|
||||||
31
src/args.rs
31
src/args.rs
@@ -1,10 +1,15 @@
|
|||||||
use clap::{App,Arg,SubCommand};
|
use clap::{App,Arg,SubCommand};
|
||||||
use crate::machine::Computer;
|
use crate::machine::Computer;
|
||||||
|
use crate::wiremap::{Wire};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::str;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
ComputeFuel(Vec<u64>),
|
ComputeFuel(Vec<u64>),
|
||||||
RunComputer(Computer),
|
RunComputer(Computer),
|
||||||
|
WireMap(Vec<Wire>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_number(s: String) -> Result<(), String> {
|
fn is_number(s: String) -> Result<(), String> {
|
||||||
@@ -49,6 +54,14 @@ impl Command {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.validator(is_file))
|
.validator(is_file))
|
||||||
)
|
)
|
||||||
|
.subcommand(SubCommand::with_name("wiremap")
|
||||||
|
.about("compute the given wire map")
|
||||||
|
.arg(Arg::with_name("MAP")
|
||||||
|
.index(1)
|
||||||
|
.help("The wiremap to run.")
|
||||||
|
.required(true)
|
||||||
|
.validator(is_file))
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
if let Some(problem1) = matches.subcommand_matches("fuel") {
|
if let Some(problem1) = matches.subcommand_matches("fuel") {
|
||||||
@@ -65,9 +78,25 @@ impl Command {
|
|||||||
if let Some(problem2) = matches.subcommand_matches("compute") {
|
if let Some(problem2) = matches.subcommand_matches("compute") {
|
||||||
let start_pos_str = problem2.value_of("START_POSITION").unwrap();
|
let start_pos_str = problem2.value_of("START_POSITION").unwrap();
|
||||||
let start_pos = usize::from_str_radix(&start_pos_str, 10).unwrap();
|
let start_pos = usize::from_str_radix(&start_pos_str, 10).unwrap();
|
||||||
let mut computer = Computer::load(problem2.value_of("COMPUTER").unwrap(), start_pos);
|
let computer = Computer::load(problem2.value_of("COMPUTER").unwrap(), start_pos);
|
||||||
return Command::RunComputer(computer);
|
return Command::RunComputer(computer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(problem3) = matches.subcommand_matches("wiremap") {
|
||||||
|
let file_contents = fs::read(problem3.value_of("MAP").unwrap()).unwrap();
|
||||||
|
let str_contents = str::from_utf8(&file_contents).unwrap();
|
||||||
|
let mut contents_iter = str_contents.chars().peekable();
|
||||||
|
let mut resvec = Vec::new();
|
||||||
|
|
||||||
|
while contents_iter.peek().is_some() {
|
||||||
|
let nextline = contents_iter.by_ref().take_while(|x| *x != '\n');
|
||||||
|
let nextstr = String::from_iter(nextline);
|
||||||
|
let next = Wire::from_str(&nextstr).unwrap();
|
||||||
|
resvec.push(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::WireMap(resvec);
|
||||||
|
}
|
||||||
|
|
||||||
panic!("Failed to run a reasonable command.");
|
panic!("Failed to run a reasonable command.");
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/main.rs
34
src/main.rs
@@ -1,11 +1,11 @@
|
|||||||
mod args;
|
mod args;
|
||||||
mod fuel;
|
mod fuel;
|
||||||
mod machine;
|
mod machine;
|
||||||
|
mod wiremap;
|
||||||
|
|
||||||
use crate::args::Command;
|
use crate::args::Command;
|
||||||
use crate::fuel::calculate_fuel;
|
use crate::fuel::calculate_fuel;
|
||||||
use crate::machine::{Computer};
|
use crate::wiremap::WireMap;
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match Command::get() {
|
match Command::get() {
|
||||||
@@ -40,5 +40,35 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Command::WireMap(wires) => {
|
||||||
|
let mut wiremap = WireMap::new();
|
||||||
|
|
||||||
|
for (num, wire) in wires.iter().enumerate() {
|
||||||
|
wiremap.add_wire(wire, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (target, distance) = wiremap.closest_intersection();
|
||||||
|
println!("Closest intersection: ({}, {}) [distance {}]",
|
||||||
|
target.0, target.1, distance);
|
||||||
|
|
||||||
|
let mut best_total_steps = usize::max_value();
|
||||||
|
|
||||||
|
for (target_num, join_point) in wiremap.joins().iter().enumerate() {
|
||||||
|
let mut total_steps = 0;
|
||||||
|
|
||||||
|
for (num, wire) in wires.iter().enumerate() {
|
||||||
|
let wire_steps = wiremap.steps_to(wire, *join_point);
|
||||||
|
println!("Wire #{} takes {} steps to target #{}.", num, wire_steps, target_num);
|
||||||
|
total_steps += wire_steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if total_steps < best_total_steps {
|
||||||
|
best_total_steps = total_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Total steps taken: {}", best_total_steps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
584
src/wiremap.rs
Normal file
584
src/wiremap.rs
Normal file
@@ -0,0 +1,584 @@
|
|||||||
|
use std::cmp::{max,min};
|
||||||
|
use std::io::{Write,stdout};
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::fmt;
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct WireMap {
|
||||||
|
map: Vec<Vec<WireState>>,
|
||||||
|
turtle: (usize, usize),
|
||||||
|
turtle_color: WireState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WireMap {
|
||||||
|
pub fn new() -> WireMap {
|
||||||
|
WireMap{ map: vec![vec![WireState::Origin]],
|
||||||
|
turtle: (0,0),
|
||||||
|
turtle_color: WireState::Nothing }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn origin(&self) -> (usize, usize) {
|
||||||
|
for (y, line) in self.map.iter().enumerate() {
|
||||||
|
for (x, pos) in line.iter().enumerate() {
|
||||||
|
if *pos == WireState::Origin {
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("No origin found?!");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn joins(&self) -> Vec<(usize,usize)> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
for (y, line) in self.map.iter().enumerate() {
|
||||||
|
for (x, pos) in line.iter().enumerate() {
|
||||||
|
if *pos == WireState::BothWires {
|
||||||
|
res.push((x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn closest_intersection(&self) -> ((usize, usize), usize) {
|
||||||
|
let mut best = usize::max_value();
|
||||||
|
let mut best_point = (0, 0);
|
||||||
|
let (ox, oy) = self.origin();
|
||||||
|
|
||||||
|
for (jx, jy) in self.joins().iter() {
|
||||||
|
let maxx = max(ox, *jx);
|
||||||
|
let minx = min(ox, *jx);
|
||||||
|
let maxy = max(oy, *jy);
|
||||||
|
let miny = min(oy, *jy);
|
||||||
|
let distance = (maxx - minx) + (maxy - miny);
|
||||||
|
if distance < best {
|
||||||
|
best = distance;
|
||||||
|
best_point = (*jx, *jy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(best_point, best)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_turtle(&mut self, color: WireState) {
|
||||||
|
self.turtle_color = color;
|
||||||
|
self.turtle = self.origin();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_down(&mut self, mut amt: usize) {
|
||||||
|
let (cur_x, mut cur_y) = self.turtle;
|
||||||
|
let end_y = cur_y + amt;
|
||||||
|
|
||||||
|
// make sure we're not going to fall off the end
|
||||||
|
if end_y >= self.map.len() {
|
||||||
|
let mut new_row = Vec::with_capacity(self.map[0].len());
|
||||||
|
new_row.resize(self.map[0].len(), WireState::Nothing);
|
||||||
|
self.map.resize(end_y + 1, new_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
while amt > 0 {
|
||||||
|
cur_y += 1;
|
||||||
|
self.map[cur_y][cur_x] = self.map[cur_y][cur_x].merge(&self.turtle_color);
|
||||||
|
amt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.turtle = (cur_x, cur_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_up(&mut self, mut amt: usize) {
|
||||||
|
let (cur_x, mut cur_y) = self.turtle;
|
||||||
|
|
||||||
|
while amt > cur_y {
|
||||||
|
let mut new_row = Vec::with_capacity(self.map[0].len());
|
||||||
|
new_row.resize(self.map[0].len(), WireState::Nothing);
|
||||||
|
self.map.insert(0, new_row);
|
||||||
|
cur_y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while amt > 0 {
|
||||||
|
cur_y -= 1;
|
||||||
|
self.map[cur_y][cur_x] = self.map[cur_y][cur_x].merge(&self.turtle_color);
|
||||||
|
amt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.turtle = (cur_x, cur_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_right(&mut self, mut amt: usize) {
|
||||||
|
let (mut cur_x, cur_y) = self.turtle;
|
||||||
|
let end_x = cur_x + amt;
|
||||||
|
|
||||||
|
// make sure we're not going to fall off the end
|
||||||
|
if end_x >= self.map[0].len() {
|
||||||
|
for row in self.map.iter_mut() {
|
||||||
|
row.resize(end_x + 1, WireState::Nothing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while amt > 0 {
|
||||||
|
cur_x += 1;
|
||||||
|
self.map[cur_y][cur_x] = self.map[cur_y][cur_x].merge(&self.turtle_color);
|
||||||
|
amt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.turtle = (cur_x, cur_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_left(&mut self, mut amt: usize) {
|
||||||
|
let (mut cur_x, cur_y) = self.turtle;
|
||||||
|
|
||||||
|
while amt > cur_x {
|
||||||
|
for row in self.map.iter_mut() {
|
||||||
|
row.insert(0, WireState::Nothing);
|
||||||
|
}
|
||||||
|
cur_x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while amt > 0 {
|
||||||
|
cur_x -= 1;
|
||||||
|
self.map[cur_y][cur_x] = self.map[cur_y][cur_x].merge(&self.turtle_color);
|
||||||
|
amt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.turtle = (cur_x, cur_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_wire(&mut self, wire: &Wire, num: usize) {
|
||||||
|
let state = if num == 1 { WireState::Wire1 } else { WireState::Wire2 };
|
||||||
|
self.reset_turtle(state);
|
||||||
|
print!("Adding wire {}: ", num);
|
||||||
|
for segment in wire.segments.iter() {
|
||||||
|
print!("{} ", segment); let _ = stdout().flush();
|
||||||
|
match segment.direction {
|
||||||
|
Direction::Right => self.advance_right(segment.magnitude),
|
||||||
|
Direction::Left => self.advance_left(segment.magnitude),
|
||||||
|
Direction::Down => self.advance_down(segment.magnitude),
|
||||||
|
Direction::Up => self.advance_up(segment.magnitude),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("DONE.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn steps_to(&self, wire: &Wire, target: (usize, usize)) -> usize {
|
||||||
|
let mut steps = 0;
|
||||||
|
let (mut cur_x, mut cur_y) = self.origin();
|
||||||
|
|
||||||
|
for segment in wire.segments.iter() {
|
||||||
|
let mut count = segment.magnitude;
|
||||||
|
|
||||||
|
match segment.direction {
|
||||||
|
Direction::Right => {
|
||||||
|
while count > 0 {
|
||||||
|
cur_x += 1; steps += 1; count -= 1;
|
||||||
|
if (cur_x, cur_y) == target {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
while count > 0 {
|
||||||
|
cur_x -= 1; steps += 1; count -= 1;
|
||||||
|
if (cur_x, cur_y) == target {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
while count > 0 {
|
||||||
|
cur_y += 1; steps += 1; count -= 1;
|
||||||
|
if (cur_x, cur_y) == target {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Up => {
|
||||||
|
while count > 0 {
|
||||||
|
cur_y -= 1; steps += 1; count -= 1;
|
||||||
|
if (cur_x, cur_y) == target {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Didn't find target on wire path?!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub enum WireState {
|
||||||
|
Nothing,
|
||||||
|
Origin,
|
||||||
|
Wire1,
|
||||||
|
Wire2,
|
||||||
|
BothWires
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WireState {
|
||||||
|
fn merge(&self, other: &WireState) -> WireState {
|
||||||
|
if self == &WireState::Nothing {
|
||||||
|
return other.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self == &WireState::Origin {
|
||||||
|
panic!("Ran back over Origin!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if self == &WireState::BothWires {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self == other {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
WireState::BothWires
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct Wire {
|
||||||
|
segments: Vec<Segment>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WireParseError {
|
||||||
|
SegmentParseError(SegmentParseError),
|
||||||
|
NoSegmentsFound
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SegmentParseError> for WireParseError {
|
||||||
|
fn from(x: SegmentParseError) -> WireParseError {
|
||||||
|
WireParseError::SegmentParseError(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Wire {
|
||||||
|
type Err = WireParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Wire, Self::Err> {
|
||||||
|
let mut segments = Vec::new();
|
||||||
|
let mut chars = s.chars().peekable();
|
||||||
|
|
||||||
|
while chars.peek().is_some() {
|
||||||
|
let next_str = chars.by_ref().take_while(|c| *c != ',');
|
||||||
|
let next = Segment::from_str(&String::from_iter(next_str))?;
|
||||||
|
segments.push(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if segments.is_empty() {
|
||||||
|
return Err(WireParseError::NoSegmentsFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Wire{ segments })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub struct Segment {
|
||||||
|
direction: Direction,
|
||||||
|
magnitude: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Segment {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self.direction {
|
||||||
|
Direction::Right => write!(f, "R{}", self.magnitude),
|
||||||
|
Direction::Left => write!(f, "L{}", self.magnitude),
|
||||||
|
Direction::Up => write!(f, "U{}", self.magnitude),
|
||||||
|
Direction::Down => write!(f, "D{}", self.magnitude),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SegmentParseError {
|
||||||
|
UnknownDirection(char),
|
||||||
|
NumberParseError(ParseIntError),
|
||||||
|
NoDirectionFound
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for SegmentParseError {
|
||||||
|
fn from(x: ParseIntError) -> SegmentParseError {
|
||||||
|
SegmentParseError::NumberParseError(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Segment {
|
||||||
|
type Err = SegmentParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Segment,Self::Err> {
|
||||||
|
let magnitude = usize::from_str_radix(&s[1..], 10)?;
|
||||||
|
let direction = match s.chars().nth(0) {
|
||||||
|
None => return Err(SegmentParseError::NoDirectionFound),
|
||||||
|
Some('R') => Direction::Right,
|
||||||
|
Some('L') => Direction::Left,
|
||||||
|
Some('U') => Direction::Up,
|
||||||
|
Some('D') => Direction::Down,
|
||||||
|
Some(d) => return Err(SegmentParseError::UnknownDirection(d)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Segment{ direction, magnitude })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,PartialEq)]
|
||||||
|
pub enum Direction {
|
||||||
|
Right,
|
||||||
|
Left,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn segment_parsing() {
|
||||||
|
let test1 = Segment::from_str("R75").unwrap();
|
||||||
|
let answer1 = Segment{ direction: Direction::Right, magnitude: 75 };
|
||||||
|
assert_eq!(test1, answer1);
|
||||||
|
let test2 = Segment::from_str("U7").unwrap();
|
||||||
|
let answer2 = Segment{ direction: Direction::Up, magnitude: 7 };
|
||||||
|
assert_eq!(test2, answer2);
|
||||||
|
let test3 = Segment::from_str("D20").unwrap();
|
||||||
|
let answer3 = Segment{ direction: Direction::Down, magnitude: 20 };
|
||||||
|
assert_eq!(test3, answer3);
|
||||||
|
let test4 = Segment::from_str("L0").unwrap();
|
||||||
|
let answer4 = Segment{ direction: Direction::Left, magnitude: 0 };
|
||||||
|
assert_eq!(test4, answer4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wire_parsing() {
|
||||||
|
let input1 = "R75,D30,R83,U83,L12,D49,R71,U7,L72";
|
||||||
|
let test1 = Wire::from_str(input1).unwrap();
|
||||||
|
let answer1 = Wire {
|
||||||
|
segments: vec![ Segment{ direction: Direction::Right, magnitude: 75 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 30 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 83 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 83 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 12 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 49 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 71 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 7 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 72 },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
assert_eq!(test1, answer1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extend_down() {
|
||||||
|
let mut base = WireMap::new();
|
||||||
|
base.turtle_color = WireState::Wire1;
|
||||||
|
base.advance_down(4);
|
||||||
|
let target = WireMap {
|
||||||
|
map: vec![vec![WireState::Origin],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
],
|
||||||
|
turtle: (0, 4),
|
||||||
|
turtle_color: WireState::Wire1,
|
||||||
|
};
|
||||||
|
assert_eq!(target, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extend_up() {
|
||||||
|
let mut base = WireMap::new();
|
||||||
|
base.turtle_color = WireState::Wire1;
|
||||||
|
base.advance_up(4);
|
||||||
|
let target = WireMap {
|
||||||
|
map: vec![vec![WireState::Wire1],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
vec![WireState::Wire1],
|
||||||
|
vec![WireState::Origin],
|
||||||
|
],
|
||||||
|
turtle: (0, 0),
|
||||||
|
turtle_color: WireState::Wire1,
|
||||||
|
};
|
||||||
|
assert_eq!(target, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extend_right() {
|
||||||
|
let mut base = WireMap::new();
|
||||||
|
base.turtle_color = WireState::Wire1;
|
||||||
|
base.advance_right(4);
|
||||||
|
let target = WireMap {
|
||||||
|
map: vec![vec![WireState::Origin,
|
||||||
|
WireState::Wire1,
|
||||||
|
WireState::Wire1,
|
||||||
|
WireState::Wire1,
|
||||||
|
WireState::Wire1,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
turtle: (4, 0),
|
||||||
|
turtle_color: WireState::Wire1,
|
||||||
|
};
|
||||||
|
assert_eq!(target, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extend_left() {
|
||||||
|
let mut base = WireMap::new();
|
||||||
|
base.turtle_color = WireState::Wire1;
|
||||||
|
base.advance_left(4);
|
||||||
|
let target = WireMap {
|
||||||
|
map: vec![vec![WireState::Wire1,
|
||||||
|
WireState::Wire1,
|
||||||
|
WireState::Wire1,
|
||||||
|
WireState::Wire1,
|
||||||
|
WireState::Origin,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
turtle: (0, 0),
|
||||||
|
turtle_color: WireState::Wire1,
|
||||||
|
};
|
||||||
|
assert_eq!(target, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
const B: WireState = WireState::BothWires;
|
||||||
|
#[cfg(test)]
|
||||||
|
const N: WireState = WireState::Nothing;
|
||||||
|
#[cfg(test)]
|
||||||
|
const O: WireState = WireState::Origin;
|
||||||
|
#[cfg(test)]
|
||||||
|
const W1: WireState = WireState::Wire1;
|
||||||
|
#[cfg(test)]
|
||||||
|
const W2: WireState = WireState::Wire2;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_wires() {
|
||||||
|
let mut base = WireMap::new();
|
||||||
|
let wire1 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 8 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 5 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 5 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 3 },
|
||||||
|
] };
|
||||||
|
base.add_wire(&wire1, 1);
|
||||||
|
let target1 = WireMap {
|
||||||
|
turtle: (3, 3),
|
||||||
|
turtle_color: WireState::Wire1,
|
||||||
|
map: vec![
|
||||||
|
vec![N, N, N, W1, W1, W1, W1, W1, W1],
|
||||||
|
vec![N, N, N, W1, N, N, N, N, W1],
|
||||||
|
vec![N, N, N, W1, N, N, N, N, W1],
|
||||||
|
vec![N, N, N, W1, N, N, N, N, W1],
|
||||||
|
vec![N, N, N, N, N, N, N, N, W1],
|
||||||
|
vec![O, W1, W1, W1, W1, W1, W1, W1, W1],
|
||||||
|
]
|
||||||
|
};
|
||||||
|
assert_eq!(base, target1);
|
||||||
|
let wire2 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 7 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 6 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 4 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 4 },
|
||||||
|
] };
|
||||||
|
base.add_wire(&wire2, 2);
|
||||||
|
let target2 = WireMap {
|
||||||
|
turtle: (2, 4),
|
||||||
|
turtle_color: WireState::Wire2,
|
||||||
|
map: vec![
|
||||||
|
vec![W2, W2, W2, W2, W2, W2, W2, N, N ],
|
||||||
|
vec![W2, N, N, N, N, N, W2, N, N ],
|
||||||
|
vec![W2, N, N, W1, W1, W1, B, W1, W1],
|
||||||
|
vec![W2, N, N, W1, N, N, W2, N, W1],
|
||||||
|
vec![W2, N, W2, B, W2, W2, W2, N, W1],
|
||||||
|
vec![W2, N, N, W1, N, N, N, N, W1],
|
||||||
|
vec![W2, N, N, N, N, N, N, N, W1],
|
||||||
|
vec![O, W1, W1, W1, W1, W1, W1, W1, W1],
|
||||||
|
]
|
||||||
|
};
|
||||||
|
assert_eq!(base, target2);
|
||||||
|
assert_eq!((0, 7), base.origin());
|
||||||
|
assert_eq!(vec![(6,2),(3,4)], base.joins());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_distances() {
|
||||||
|
let mut example1 = WireMap::new();
|
||||||
|
let ex1wire1 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 8 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 5 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 5 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 3 },
|
||||||
|
] };
|
||||||
|
example1.add_wire(&ex1wire1, 1);
|
||||||
|
let ex1wire2 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 7 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 6 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 4 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 4 },
|
||||||
|
] };
|
||||||
|
example1.add_wire(&ex1wire2, 2);
|
||||||
|
let (ex1inter, ex1dist) = example1.closest_intersection();
|
||||||
|
assert_eq!(6, ex1dist);
|
||||||
|
assert_eq!(20, example1.steps_to(&ex1wire1, ex1inter));
|
||||||
|
assert_eq!(20, example1.steps_to(&ex1wire2, ex1inter));
|
||||||
|
|
||||||
|
let mut example2 = WireMap::new();
|
||||||
|
let ex2wire1 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 75 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 30 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 83 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 83 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 12 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 49 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 71 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 7 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 72 },
|
||||||
|
] };
|
||||||
|
example2.add_wire(&ex2wire1, 1);
|
||||||
|
let ex2wire2 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 62 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 66 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 55 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 34 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 71 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 55 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 58 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 83 },
|
||||||
|
] };
|
||||||
|
example2.add_wire(&ex2wire2, 2);
|
||||||
|
assert_eq!(159, example2.closest_intersection().1);
|
||||||
|
|
||||||
|
let mut example3 = WireMap::new();
|
||||||
|
let ex3wire1 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 98 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 47 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 26 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 63 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 33 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 87 },
|
||||||
|
Segment{ direction: Direction::Left, magnitude: 62 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 20 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 33 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 53 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 51 },
|
||||||
|
] };
|
||||||
|
example3.add_wire(&ex3wire1, 1);
|
||||||
|
let ex3wire2 = Wire{ segments: vec![
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 98 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 91 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 20 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 16 },
|
||||||
|
Segment{ direction: Direction::Down, magnitude: 67 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 40 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 7 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 15 },
|
||||||
|
Segment{ direction: Direction::Up, magnitude: 6 },
|
||||||
|
Segment{ direction: Direction::Right, magnitude: 7 },
|
||||||
|
] };
|
||||||
|
example3.add_wire(&ex3wire2, 2);
|
||||||
|
assert_eq!(135, example3.closest_intersection().1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user