summaryrefslogtreecommitdiff
path: root/2018/src/day13.rs
diff options
context:
space:
mode:
Diffstat (limited to '2018/src/day13.rs')
-rw-r--r--2018/src/day13.rs176
1 files changed, 176 insertions, 0 deletions
diff --git a/2018/src/day13.rs b/2018/src/day13.rs
new file mode 100644
index 0000000..13ff3a4
--- /dev/null
+++ b/2018/src/day13.rs
@@ -0,0 +1,176 @@
+use std::io;
+use std::io::BufRead;
+use std::collections::HashMap;
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+struct Pos { x: usize, y: usize }
+
+#[derive(Clone)]
+struct Dir { x: i32, y: i32 }
+
+impl Dir {
+ fn rotright(&self) -> Dir {
+ Dir { x: -self.y, y: self.x }
+ }
+
+ fn rotleft(&self) -> Dir {
+ Dir { x: self.y, y: -self.x }
+ }
+}
+
+enum Choice {
+ Left,
+ Forward,
+ Right,
+}
+
+impl Choice {
+ fn incr(&mut self) {
+ match self {
+ Choice::Left => *self = Choice::Forward,
+ Choice::Forward => *self = Choice::Right,
+ Choice::Right => *self = Choice::Left,
+ }
+ }
+
+ fn apply(&self, dir: &Dir) -> Dir {
+ match self {
+ Choice::Left => dir.rotleft(),
+ Choice::Forward => dir.clone(),
+ Choice::Right => dir.rotright(),
+ }
+ }
+}
+
+struct Cart {
+ pos: Pos,
+ dir: Dir,
+ choice: Choice,
+}
+
+impl Cart {
+ fn nextpos(&self) -> Pos {
+ Pos { x: (self.pos.x as i32 + self.dir.x) as usize,
+ y: (self.pos.y as i32 + self.dir.y) as usize }
+ }
+}
+
+fn newdir(dir: &Dir, c: u8) -> Dir {
+ // println!(" newdir {},{} {}", dir.x, dir.y, std::char::from_u32(c as u32).unwrap());
+ if c == '|' as u8 || c == '-' as u8 {
+ Dir { x: dir.x, y: dir.y }
+ } else if c == '/' as u8 {
+ if dir.y == 0 {
+ dir.rotleft()
+ } else {
+ dir.rotright()
+ }
+ } else if c == '\\' as u8 {
+ if dir.y == 0 {
+ dir.rotright()
+ } else {
+ dir.rotleft()
+ }
+ } else {
+ println!("<{}>", c);
+ unreachable!();
+ }
+}
+
+fn print_dir(dir: &Dir) -> char {
+ match dir {
+ Dir{x:1,y:0} => '>',
+ Dir{x:-1,y:0} => '<',
+ Dir{x:0,y:1} => 'v',
+ Dir{x:0,y:-1} => '^',
+ Dir{..} => '?',
+ }
+}
+
+fn print_grid(grid: &Vec<Vec<u8>>, carts: &Vec<Cart>) {
+ let mut hascart: HashMap<Pos, usize> = HashMap::new();
+ for (i, cart) in carts.iter().enumerate() {
+ hascart.insert(cart.pos.clone(), i);
+ }
+
+ for y in 0..grid.len() {
+ for x in 0..grid[y].len() {
+ match hascart.get(&Pos { x, y }) {
+ Some(&idx) => {
+ print!("{}", print_dir(&carts[idx].dir));
+ }
+ None => {
+ print!("{}", std::char::from_u32(grid[y][x] as u32).unwrap());
+ }
+ }
+ }
+
+ println!("");
+ }
+}
+
+pub fn main<T: BufRead>(reader: T) -> io::Result<(String, String)> {
+ let mut grid: Vec<Vec<u8>> = reader.lines().map(|l| l.unwrap().as_bytes().to_vec()).collect();
+ let h = grid.len();
+ let w = grid[0].len();
+
+ let mut hascart = Vec::new();
+ for _ in 0..h {
+ hascart.push(vec![false; w]);
+ }
+
+ let mut carts: Vec<Cart> = Vec::new();
+ for y in 0..h {
+ for x in 0..w {
+ macro_rules! grid_process {
+ ( $c1:expr, $c2:expr, $dx:expr, $dy:expr ) => {
+ if grid[y][x] == $c1 as u8 {
+ grid[y][x] = $c2 as u8;
+ carts.push(Cart { pos: Pos { x, y }, dir: Dir { x: $dx, y: $dy }, choice: Choice::Left });
+ hascart[y][x] = true;
+ }
+ }
+ }
+
+ grid_process!('>', '-', 1, 0);
+ grid_process!('<', '-', -1, 0);
+ grid_process!('^', '|', 0, -1);
+ grid_process!('v', '|', 0, 1);
+ }
+ }
+
+ let part1;
+
+ 'outer: loop {
+ for mut cart in &mut carts {
+ let pos2 = cart.nextpos();
+ let c = grid[pos2.y][pos2.x];
+
+ // println!("cart at {},{} {},{}", cart.pos.x, cart.pos.y, cart.dir.x, cart.dir.y);
+
+ let dir2;
+ if c == '+' as u8 {
+ dir2 = cart.choice.apply(&cart.dir);
+ cart.choice.incr();
+ } else {
+ dir2 = newdir(&cart.dir, c);
+ }
+
+ if hascart[pos2.y][pos2.x] {
+ part1 = format!("{},{}", pos2.x, pos2.y);
+ break 'outer;
+ }
+
+ hascart[cart.pos.y][cart.pos.x] = false;
+ hascart[pos2.y][pos2.x] = true;
+ cart.pos = pos2;
+ cart.dir = dir2;
+ }
+
+ carts.sort_by_key(|cart| (cart.pos.y, cart.pos.x));
+
+ // print_grid(&grid, &carts);
+ }
+
+ Ok((part1, String::new()))
+}