#![allow(dead_code)] #![allow(unused_variables)] #![allow(unused_mut)] use num::complex::Complex as c; use num::Complex; use std::cmp::max; use std::collections::HashMap; use std::collections::HashSet; use std::env; use std::fs::File; use std::io::Read; #[derive(Debug)] enum Field { Empty, Slash, Backslash, Vert, Horiz, } type Matrix = Vec>; type C32 = Complex; fn slash_dir(dir: C32) -> C32 { if dir.im != 0 { dir * c::i() } else { -dir * c::i() } } fn backslash_dir(dir: C32) -> C32 { if dir.re != 0 { dir * c::i() } else { -dir * c::i() } } fn rec(mut pos: C32, dir: C32, m: &Matrix, v: &mut HashMap<(C32, C32), bool>) -> () { pos += dir; if !(0 <= pos.re && pos.re < m[0].len() as i32 && 0 <= pos.im && pos.im < m.len() as i32) { return; } if let Some(_) = v.insert((pos, dir), true) { return; } match m[pos.im as usize][pos.re as usize] { Field::Vert => { if dir.im != 0 { rec(pos, dir, m, v); } else { rec(pos, dir * c::i(), m, v); rec(pos, -dir * c::i(), m, v); } } Field::Horiz => { if dir.re != 0 { rec(pos, dir, m, v); } else { rec(pos, dir * c::i(), m, v); rec(pos, -dir * c::i(), m, v); } } Field::Slash => rec(pos, slash_dir(dir), m, v), Field::Backslash => rec(pos, backslash_dir(dir), m, v), Field::Empty => rec(pos, dir, m, v), }; } fn print_energized(e: &HashSet<&C32>, x_len: usize, y_len: usize) { for y in 0..y_len { for x in 0..x_len { if let Some(_) = e.get(&((x as i32) + (y as i32) * c::i())) { print!("#"); } else { print!("."); } } println!(); } } fn get_energized(pos: C32, dir: C32, m: &Matrix) -> usize { let mut visited: HashMap<(C32, C32), bool> = HashMap::new(); rec(pos, dir, m, &mut visited); let mut energized: HashSet<&C32> = HashSet::new(); for (pos, dir) in visited.keys() { energized.insert(pos); } // print_energized(&energized, m[0].len(), m.len()); return energized.len(); } 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 lines = content.trim_end().split("\n"); let mut m: Matrix = Vec::new(); for line in lines { let mut l = Vec::new(); for c in line.chars() { let a = match c { '.' => Field::Empty, '/' => Field::Slash, '\\' => Field::Backslash, '|' => Field::Vert, '-' => Field::Horiz, _ => panic!(), }; l.push(a); } m.push(l); } let mut res1 = get_energized(c::new(-1, 0), c::new(1, 0), &m); let mut res2 = 0; for y in 0..m.len() { res2 = max(res2, get_energized(c::new(-1, y as i32), c::new(1, 0), &m)); res2 = max( res2, get_energized(c::new(m[0].len() as i32, y as i32), c::new(-1, 0), &m), ); } for x in 0..m[0].len() { res2 = max(res2, get_energized(c::new(x as i32, -1), c::new(0, 1), &m)); res2 = max( res2, get_energized(c::new(m.len() as i32, x as i32), c::new(0, -1), &m), ); } println!("res1: {}", res1); println!("res2: {}", res2); assert_eq!(res1, 6921); assert_eq!(res2, 7594); }