From 73b612d25b36a590ddc1a345e3af13047bc05ee7 Mon Sep 17 00:00:00 2001 From: Johannes Date: Sat, 21 Dec 2019 23:08:59 +0100 Subject: [PATCH] day 15 task 1 --- input/day15.txt | 1 + src/main.rs | 2 +- src/tasks/day15.rs | 253 +++++++++++++++++++++++++++++++++++++++++++++ src/tasks/day21.rs | 1 + src/tasks/mod.rs | 1 + 5 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 input/day15.txt create mode 100644 src/tasks/day15.rs diff --git a/input/day15.txt b/input/day15.txt new file mode 100644 index 0000000..b6ead7e --- /dev/null +++ b/input/day15.txt @@ -0,0 +1 @@ +3,1033,1008,1033,1,1032,1005,1032,31,1008,1033,2,1032,1005,1032,58,1008,1033,3,1032,1005,1032,81,1008,1033,4,1032,1005,1032,104,99,1001,1034,0,1039,1002,1036,1,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1106,0,124,1001,1034,0,1039,102,1,1036,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1105,1,124,1001,1034,-1,1039,1008,1036,0,1041,102,1,1035,1040,1002,1038,1,1043,101,0,1037,1042,1105,1,124,1001,1034,1,1039,1008,1036,0,1041,102,1,1035,1040,1001,1038,0,1043,101,0,1037,1042,1006,1039,217,1006,1040,217,1008,1039,40,1032,1005,1032,217,1008,1040,40,1032,1005,1032,217,1008,1039,33,1032,1006,1032,165,1008,1040,33,1032,1006,1032,165,1101,0,2,1044,1106,0,224,2,1041,1043,1032,1006,1032,179,1102,1,1,1044,1105,1,224,1,1041,1043,1032,1006,1032,217,1,1042,1043,1032,1001,1032,-1,1032,1002,1032,39,1032,1,1032,1039,1032,101,-1,1032,1032,101,252,1032,211,1007,0,42,1044,1106,0,224,1102,0,1,1044,1106,0,224,1006,1044,247,1001,1039,0,1034,1001,1040,0,1035,1001,1041,0,1036,1001,1043,0,1038,102,1,1042,1037,4,1044,1106,0,0,6,28,51,33,63,27,52,11,53,13,96,8,87,11,23,65,43,11,13,9,37,66,68,40,19,41,6,90,28,19,38,86,38,22,7,44,36,23,17,1,16,54,36,74,14,79,2,14,83,10,38,19,62,66,27,56,33,52,47,98,41,39,77,83,48,29,49,15,80,59,9,72,79,55,24,66,50,24,27,56,37,41,13,72,35,13,64,70,5,66,78,37,78,24,43,93,22,41,30,58,14,45,6,27,44,48,40,52,31,12,3,72,7,14,59,35,17,63,34,79,93,17,54,98,35,21,91,25,32,77,10,31,88,17,35,79,96,11,83,15,48,9,19,64,24,65,86,32,71,22,88,55,31,18,88,68,34,40,94,1,71,24,40,44,28,43,4,98,21,80,17,53,2,94,6,43,59,23,66,63,12,30,45,39,93,41,85,43,51,18,99,59,86,40,36,26,94,33,41,28,66,79,81,11,61,46,32,72,71,47,39,22,69,60,36,50,12,44,28,41,79,17,6,74,8,56,39,33,67,23,20,51,12,7,26,57,1,92,80,11,52,19,5,54,13,41,56,37,22,57,43,18,97,27,83,30,3,77,85,66,64,17,99,27,25,95,40,81,97,13,35,46,14,25,63,36,72,87,20,96,29,2,69,90,27,27,91,52,14,14,73,55,4,73,19,85,39,84,23,23,90,40,5,88,53,77,8,92,11,82,66,6,27,84,53,38,93,34,37,58,20,43,25,73,78,30,17,92,54,38,26,67,16,30,28,79,77,26,3,15,82,59,34,34,18,44,34,33,83,35,90,31,58,44,16,18,65,8,70,90,32,46,21,41,54,39,43,93,23,99,11,43,50,98,33,34,53,54,53,16,39,88,53,36,69,85,26,44,38,62,98,6,79,26,35,49,67,22,11,74,35,80,4,50,18,54,4,10,4,58,4,46,20,15,77,73,11,41,58,85,39,87,37,73,36,36,67,28,12,17,34,53,38,89,96,34,39,67,64,33,81,37,74,88,20,84,94,53,39,57,73,13,76,1,35,14,73,29,29,23,73,52,16,85,87,33,48,13,2,93,78,7,17,60,49,13,36,89,40,25,44,55,26,81,37,31,84,31,62,2,66,77,23,88,11,81,9,63,46,19,35,54,17,85,24,1,86,28,72,1,1,61,27,38,81,8,67,82,3,11,77,35,62,83,20,28,61,37,37,92,22,72,76,37,52,17,62,68,38,53,2,57,82,67,25,11,59,3,49,97,1,40,91,75,7,85,98,33,90,1,37,57,14,34,67,65,20,85,10,18,86,20,52,84,24,20,70,10,64,16,64,2,15,85,36,28,7,87,47,44,9,29,54,83,28,37,81,68,18,12,80,26,98,97,25,86,69,39,70,22,23,72,15,56,94,27,14,13,8,50,73,90,24,95,14,41,57,22,67,25,80,46,39,84,80,19,22,63,53,45,62,21,84,36,69,41,44,96,38,92,21,23,64,35,11,75,57,88,6,7,90,10,36,19,68,78,23,62,34,49,4,80,38,2,70,48,39,55,20,22,39,8,90,64,38,39,47,41,63,72,5,10,72,88,35,50,5,66,30,80,74,23,97,39,98,19,17,85,38,34,62,37,25,58,15,93,37,13,71,72,72,4,84,40,92,61,88,9,7,62,59,87,17,36,39,43,21,11,16,58,16,58,20,66,18,83,33,66,62,90,32,74,15,58,62,43,16,66,22,90,2,68,30,54,18,59,22,50,12,60,35,66,77,51,36,64,89,82,21,85,0,0,21,21,1,10,1,0,0,0,0,0,0 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 10a210c..62cc75c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ mod tasks; fn main() { - tasks::day21::run(); + tasks::day15::run(); } diff --git a/src/tasks/day15.rs b/src/tasks/day15.rs new file mode 100644 index 0000000..329d5d5 --- /dev/null +++ b/src/tasks/day15.rs @@ -0,0 +1,253 @@ +use super::day05::*; +use std::collections::HashMap; +use std::collections::VecDeque; +use Direction::*; + +#[allow(dead_code)] +pub fn run() { + let ram = load_ram("input/day15.txt"); + task1(ram.clone()); +} + +#[allow(dead_code)] +fn task1(ram: RAM) { + let (map, goal) = explore_map(ram); + let shortest_path = map.get_shortest_path_to(Pos(0, 0), goal); + /* + map.print( + Map::positions_on_path(Pos(0, 0), &shortest_path) + .iter() + .map(|p| (*p, 'x')) + .collect(), + ); + */ + + println!( + "Task 1: shortest path to goal ({:?}) has length {}", + goal, + shortest_path.len() + ); +} + +fn explore_map(ram: RAM) -> (Map, Pos) { + let mut map = Map { + positions: HashMap::new(), + }; + let mut current = Pos(0, 0); + map.positions.insert(current, '.'); + let mut target: Option = None; + let mut pc = IntCodeComputer::new(vec![], ram); + while let Some(non_explored_neighbor) = map.get_unexplored() { + // move to next field with unexplored neighbors + // *find path + // *follow directions + let round_starts_from = current; + let directions = map.get_shortest_path_to(round_starts_from, non_explored_neighbor); + for d in directions { + let res = pc.run_single(d.to_robot_cmd()); + if res == 0 { + map.print(HashMap::new()); + panic!("Ran against a wall stepping {:?} from {:?}.", d, current); + } + current = current.neighbor(d); + } + + // explore all 4 neighbor positions + // i.e. for every direction move - if result is 0 mark as wall, + // if result is 1 or 2 move back and mark as empty. If result is 2 store + // target position + let ns = vec![N, S, W, E]; + for d in ns { + let r = pc.run_single(d.to_robot_cmd()); + match r { + 0 => { + map.positions.insert(current.neighbor(d), '#'); + } + 1 => { + map.positions.insert(current.neighbor(d), '.'); + pc.run_single(d.opposite().to_robot_cmd()); + } + 2 => { + map.positions.insert(current.neighbor(d), '.'); + pc.run_single(d.opposite().to_robot_cmd()); + target = Some(current.neighbor(d)); + } + _ => panic!("unknown field type {}", r), + }; + } + } + + (map, target.unwrap()) +} + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +struct Pos(i32, i32); + +impl Pos { + fn add(&self, other: Self) -> Self { + Pos(self.0 + other.0, self.1 + other.1) + } + + fn direction_to(&self, from: Pos) -> Direction { + let m: HashMap = vec![ + (Pos(0, 1), N), + (Pos(0, -1), S), + (Pos(1, 0), W), + (Pos(-1, 0), E), + ] + .into_iter() + .collect(); + m.get(&Pos(self.0 - from.0, self.1 - from.1)) + .map(|p| *p) + .unwrap() + } + + fn neighbor(&self, direction: Direction) -> Pos { + match direction { + N => self.add(Pos(0, -1)), + S => self.add(Pos(0, 1)), + W => self.add(Pos(-1, 0)), + E => self.add(Pos(1, 0)), + } + } +} + +#[derive(Debug)] +struct Map { + positions: HashMap, +} + +impl Map { + fn get_unexplored(&self) -> Option { + let neighbors = vec![Pos(-1, 0), Pos(1, 0), Pos(0, -1), Pos(0, 1)]; + let r = self + .positions + .iter() + .filter(|(_, c)| **c == '.') + .map(|(p, _)| p) + .find(|pos| { + neighbors + .iter() + .any(|delta| !self.positions.contains_key(&pos.add(*delta))) + }); + r.map(|p| *p) + } + + fn get_shortest_path_to(&self, start: Pos, goal: Pos) -> Vec { + let neighbors = vec![Pos(-1, 0), Pos(1, 0), Pos(0, -1), Pos(0, 1)]; + let mut open: VecDeque = VecDeque::new(); + open.push_back(start); + let mut predecessors: HashMap> = HashMap::new(); + predecessors.insert(start, None); + while let Some(current) = open.pop_front() { + let field = self.positions.get(¤t); + if let Some(v) = field { + if *v != '.' { + continue; + } + } else { + continue; + } + neighbors.iter().for_each(|d| { + let n = current.add(*d); + if !predecessors.contains_key(&n) { + predecessors.insert(n, Some(current)); + open.push_back(n); + } + }); + if current == goal { + break; + } + } + let mut directions = Vec::new(); + let mut current = goal; + while let Some(Some(pred)) = predecessors.get(¤t) { + directions.push(current.direction_to(*pred).opposite()); + current = *pred; + } + directions.reverse(); + directions + } + + #[allow(dead_code)] + fn positions_on_path(start: Pos, directions: &Vec) -> Vec { + let mut result = vec![start]; + let mut current = start; + for d in directions { + current = current.neighbor(*d); + result.push(current); + } + result + } + + fn print(&self, special: HashMap) { + let xmin = (self + .positions + .iter() + .min_by_key(|(Pos(x, _), _)| x) + .unwrap() + .0) + .0; + let xmax = (self + .positions + .iter() + .max_by_key(|(Pos(x, _), _)| x) + .unwrap() + .0) + .0; + let ymin = (self + .positions + .iter() + .min_by_key(|(Pos(_, y), _)| y) + .unwrap() + .0) + .1; + let ymax = (self + .positions + .iter() + .max_by_key(|(Pos(_, y), _)| y) + .unwrap() + .0) + .1; + for y in ymin..=ymax { + for x in xmin..=xmax { + let c = self.positions.get(&Pos(x, y)).unwrap_or(&' '); + let c = if let Some(s) = special.get(&Pos(x, y)) { + s + } else { + c + }; + print!("{}", c); + } + println!(""); + } + } +} + +#[derive(Hash, PartialEq, Copy, Clone, Debug)] +enum Direction { + N, + S, + W, + E, +} + +impl Direction { + fn opposite(&self) -> Self { + match self { + N => S, + S => N, + W => E, + E => W, + } + } + + fn to_robot_cmd(&self) -> i128 { + match self { + N => 1, + S => 2, + W => 3, + E => 4, + } + } +} diff --git a/src/tasks/day21.rs b/src/tasks/day21.rs index bb8e125..08f1cf8 100644 --- a/src/tasks/day21.rs +++ b/src/tasks/day21.rs @@ -8,6 +8,7 @@ pub fn run() { .enumerate() .map(|(i, s)| (i, s.parse::().unwrap())) .collect(); + task1(ram.clone()); task2(ram.clone()); } diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index a455911..be4bb81 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -11,5 +11,6 @@ pub mod day11; pub mod day12; pub mod day13; pub mod day14; +pub mod day15; pub mod day16; pub mod day21;