#![allow(dead_code)] #![allow(unused_variables)] #![allow(unused_mut)] use std::collections::HashSet; use std::env; use std::fs::File; use std::io::Read; #[derive(Debug, PartialEq, Clone, Copy)] enum Field { Wall, Box, Empty, } fn sim(rx: i64, ry: i64, dx: i64, dy: i64, mut m: &mut Vec>) -> (i64, i64) { let mx = rx + dx; let my = ry + dy; let f = m[my as usize][mx as usize]; if f == Field::Empty { return (mx, my); } else if f == Field::Wall { return (rx, ry); } let mut x = mx + dx; let mut y = my + dy; loop { let f = m[y as usize][x as usize]; if f == Field::Wall { return (rx, ry); } if f == Field::Empty { m[my as usize][mx as usize] = Field::Empty; m[y as usize][x as usize] = Field::Box; return (mx, my); } x += dx; y += dy; } } fn sim2(rx: i64, ry: i64, dx: i64, dy: i64, mut m: &mut Vec>) -> (i64, i64) { let mx = rx + dx; let my = ry + dy; let mut boxes: Vec<(i64, i64)> = Vec::new(); let mut new_boxes: HashSet<(i64, i64)> = HashSet::new(); let mut all_boxes: HashSet<(i64, i64)> = HashSet::new(); let mut cur_boxes: HashSet<(i64, i64)>; let f = m[my as usize][mx as usize]; match f { '#' => return (rx, ry), '.' => return (mx, my), '[' => { new_boxes.insert((mx, my)); boxes.push((mx, my)); new_boxes.insert((mx + 1, my)); boxes.push((mx + 1, my)); } ']' => { new_boxes.insert((mx, my)); boxes.push((mx, my)); new_boxes.insert((mx - 1, my)); boxes.push((mx - 1, my)); } _ => panic!(), } all_boxes = &all_boxes | &new_boxes; cur_boxes = new_boxes.clone(); new_boxes.clear(); loop { for (x, y) in cur_boxes.clone() { let nx = x + dx; let ny = y + dy; let f = m[ny as usize][nx as usize]; match f { '#' => return (rx, ry), '.' => (), '[' => { if !all_boxes.contains(&(nx, ny)) { new_boxes.insert((nx, ny)); if !boxes.contains(&(nx, ny)) { boxes.push((nx, ny)); } } if !all_boxes.contains(&(nx + 1, ny)) { new_boxes.insert((nx + 1, ny)); if !boxes.contains(&(nx + 1, ny)) { boxes.push((nx + 1, ny)); } } } ']' => { if !all_boxes.contains(&(nx, ny)) { new_boxes.insert((nx, ny)); if !boxes.contains(&(nx, ny)) { boxes.push((nx, ny)); } } if !all_boxes.contains(&(nx - 1, ny)) { new_boxes.insert((nx - 1, ny)); if !boxes.contains(&(nx - 1, ny)) { boxes.push((nx - 1, ny)); } } } _ => panic!(), } } if new_boxes.len() == 0 { break; } all_boxes = &all_boxes | &new_boxes; cur_boxes = new_boxes.clone(); new_boxes.clear(); } for (x, y) in boxes.into_iter().rev() { let tmp = m[y as usize][x as usize]; m[y as usize][x as usize] = m[(y + dy) as usize][(x + dx) as usize]; m[(y + dy) as usize][(x + dx) as usize] = tmp; } return (mx, my); } fn gps(m: &Vec>) -> i64 { let mut ret = 0; for y in 0..m.len() { for x in 0..m[0].len() { if m[y][x] == Field::Box { ret += 100 * y + x; } } } return ret as i64; } fn gps2(m: &Vec>) -> i64 { let mut ret = 0; for y in 0..m.len() { for x in 0..m[0].len() { if m[y][x] == '[' { ret += 100 * y + x; } } } return ret as i64; } fn print_m(m: &Vec>) { for l in m { for f in l { match f { Field::Box => print!("O"), Field::Empty => print!("."), Field::Wall => print!("#"), } } println!(); } } fn print_m2(rx: i64, ry: i64, m: &Vec>) { for (y, l) in m.iter().enumerate() { for (x, c) in l.iter().enumerate() { if x as i64 == rx && y as i64 == ry { print!("@"); } else { print!("{}", c); } } println!(); } } fn main() { let args: Vec = env::args().collect(); let filename = if args.len() == 1 { "in/".to_owned() + args[0].split('/').last().unwrap() + ".pzl" } else { args[1].clone() }; let mut f = File::open(filename).expect("cannot open file"); let mut content = String::new(); f.read_to_string(&mut content).expect("cannot read file"); let (para1, para2) = content.trim_end().split_once("\n\n").unwrap(); let mut rx = 0; let mut ry = 0; let mut m: Vec> = Vec::new(); let mut m2: Vec> = Vec::new(); for (y, line) in para1.split("\n").enumerate() { let mut l: Vec = Vec::new(); let mut l2: Vec = Vec::new(); for (x, c) in line.chars().enumerate() { let x = x as i64; let y = y as i64; if c == '@' { rx = x; ry = y; } if c == 'O' { l.push(Field::Box); l2.push('['); l2.push(']'); } else if c == '#' { l.push(Field::Wall); l2.push('#'); l2.push('#'); } else { l.push(Field::Empty); l2.push('.'); l2.push('.'); } } m.push(l); m2.push(l2); } let mut rx2 = 2 * rx; let mut ry2 = ry; let mut dirs: Vec<(i64, i64)> = Vec::new(); for line in para2.split("\n") { for c in line.chars() { let d = match c { '<' => (-1, 0), '>' => (1, 0), '^' => (0, -1), 'v' => (0, 1), _ => panic!(), }; dirs.push(d); } } for dir in dirs { (rx, ry) = sim(rx, ry, dir.0, dir.1, &mut m); (rx2, ry2) = sim2(rx2, ry2, dir.0, dir.1, &mut m2); //print_m(&m); //print_m2(rx2, ry2, &m2); } let res1 = gps(&m); let res2 = gps2(&m2); println!("res1: {}", res1); println!("res2: {}", res2); assert_eq!(res1, 1414416); assert_eq!(res2, 1386070); }