#![allow(dead_code)] #![allow(unused_variables)] #![allow(unused_mut)] use num::complex::Complex as c; use num::Complex; use std::cmp::min; use std::collections::HashMap; use std::collections::HashSet; use std::fs::File; use std::io::Read; type Matrix = Vec>; fn bfs1(m: &Matrix) -> u32 { let mut s: HashMap<(Complex, Complex, u32), u32> = HashMap::new(); let mut hs: HashSet<(Complex, Complex, u32, u32)> = HashSet::new(); let mut hs_next: HashSet<(Complex, Complex, u32, u32)> = HashSet::new(); hs.insert((c::new(0, 0), c::new(1, 0), 0, 0)); let mut res: Vec = Vec::new(); while hs.len() > 0 { for (pos, dir, conti, mut hl) in hs { if conti > 2 { continue; } if !(0 <= pos.re && pos.re < m[0].len() as i32 && 0 <= pos.im && pos.im < m.len() as i32) { continue; } hl += m[pos.im as usize][pos.re as usize]; if pos == c::new(m[0].len() as i32 - 1, m.len() as i32 - 1) { res.push(hl); continue; } if let Some(hl_) = s.get(&(pos, dir, conti)) { if hl_ <= &hl { continue; } } s.insert((pos, dir, conti), hl); let new_dir = dir; let new_pos = pos + new_dir; hs_next.insert((new_pos, new_dir, conti + 1, hl)); let new_dir = dir * c::i(); let new_pos = pos + new_dir; hs_next.insert((new_pos, new_dir, 0, hl)); let new_dir = dir * (-c::i()); let new_pos = pos + new_dir; hs_next.insert((new_pos, new_dir, 0, hl)); } hs = hs_next; hs_next = HashSet::new(); } return res.into_iter().fold(999999999, min) - m[0][0]; } fn bfs2(m: &Matrix) -> u32 { let mut s: HashMap<(Complex, Complex, u32), u32> = HashMap::new(); let mut hs: HashSet<(Complex, Complex, u32, u32)> = HashSet::new(); let mut hs_next: HashSet<(Complex, Complex, u32, u32)> = HashSet::new(); hs.insert((c::new(0, 0), c::new(1, 0), 0, 0)); let mut res: Vec = Vec::new(); while hs.len() > 0 { for (pos, dir, conti, mut hl) in hs { if conti > 9 { continue; } if !(0 <= pos.re && pos.re < m[0].len() as i32 && 0 <= pos.im && pos.im < m.len() as i32) { continue; } hl += m[pos.im as usize][pos.re as usize]; if conti > 2 && pos == c::new(m[0].len() as i32 - 1, m.len() as i32 - 1) { res.push(hl); continue; } if let Some(hl_) = s.get(&(pos, dir, conti)) { if hl_ <= &hl { continue; } } s.insert((pos, dir, conti), hl); let new_dir = dir; let new_pos = pos + new_dir; hs_next.insert((new_pos, new_dir, conti + 1, hl)); if conti > 2 { let new_dir = dir * c::i(); let new_pos = pos + new_dir; hs_next.insert((new_pos, new_dir, 0, hl)); let new_dir = dir * (-c::i()); let new_pos = pos + new_dir; hs_next.insert((new_pos, new_dir, 0, hl)); } } hs = hs_next; hs_next = HashSet::new(); } return res.into_iter().fold(999999999, min) - m[0][0]; } fn main() { // let filename = "in/day17.ref"; let filename = "in/day17.pzl"; 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 lines = content.trim_end().split('\n'); let mut m: Matrix = Vec::new(); for line in lines { let mut mr: Vec = Vec::new(); for c in line.chars() { mr.push(c.to_digit(10).unwrap()); } m.push(mr); } let res1 = bfs1(&m); let res2 = bfs2(&m); println!("res1: {}", res1); println!("res2: {}", res2); assert_eq!(res1, 635); assert_eq!(res2, 734); }