use std::{ collections::{HashMap, VecDeque}, env, fs, io::{self, Write}, path::PathBuf, }; fn main() { let program: Vec = load_program(); let mut tape: Vec = vec![0]; let mut cell_index: usize = 0; let mut ip: usize = 0; let mut icount: usize = 0; let mut user_input: Vec = vec![]; let mut table: HashMap = HashMap::new(); let mut stack: VecDeque = VecDeque::new(); for (ip, instruction) in program.iter().enumerate() { if *instruction == b'[' { stack.push_back(ip); } else if *instruction == b']' { let begin_index = stack.pop_back().unwrap(); table.insert(begin_index, ip); table.insert(ip, begin_index); } } while ip < program.len() { let Some(instruction) = program.get(ip) else { break; }; match instruction { b'+' => { tape[cell_index] = tape[cell_index].wrapping_add(1); icount += 1; } b'-' => { tape[cell_index] = tape[cell_index].wrapping_sub(1); icount += 1; } b'>' => { cell_index = cell_index.wrapping_add(1); if tape.len() <= cell_index { tape.push(0); } icount += 1; } b'<' => { cell_index = cell_index.wrapping_sub(1); icount += 1; } b'.' => { print!("{}", tape[cell_index] as char); icount += 1; } b',' => { if user_input.is_empty() { user_input = input(); } tape[cell_index] = user_input.remove(0); icount += 1; } b'[' => { if tape[cell_index] == 0 { ip = *table.get(&ip).unwrap(); } icount += 1; } b']' => { if tape[cell_index] != 0 { ip = *table.get(&ip).unwrap(); } icount += 1; } _ => {} } ip += 1; } println!(); println!("Instructions ran: {icount}"); // println!("{tape:?}"); } fn input() -> Vec { let mut input = String::new(); print!("Input: "); let _ = io::stdout().flush(); let _ = io::stdin().read_line(&mut input); input.as_bytes().to_vec() } fn load_program() -> Vec { let args: Vec = env::args().collect(); let input = args.get(1).expect("malformed arguments"); let path: PathBuf = input.into(); let input = fs::read_to_string(path).expect("failed to read the program file"); input.as_bytes().to_vec() }