advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git

day-17.rs (8577B)

    1 use std::collections::HashMap;
    2 use std::collections::VecDeque;
    3 type Op = i128;
    4 
    5 fn main() {
    6     let input = std::fs::read_to_string("input.txt")
    7         .unwrap()
    8         .trim()
    9         .split(",")
   10         .map(|op| op.parse::<Op>().unwrap())
   11         .collect::<Vec<Op>>();
   12     println!("Rust:");
   13     println!("Part 1: {}", part_1(&input));
   14     println!("Part 2: {}", part_2(&input));
   15 }
   16 
   17 fn computer_step(
   18     program: &mut HashMap<usize, Op>,
   19     pc: &mut usize,
   20     relative_base: &mut Op,
   21     input: &mut Option<Op>,
   22 ) -> (bool, Vec<Op>) {
   23     let mut output = vec![];
   24     let get_param = |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> Op {
   25         match mode {
   26             // Position mode.
   27             0 => *program.get(&(program[&loc] as usize)).unwrap_or(&0),
   28             // Immediate mode.
   29             1 => program[&loc],
   30             // Relative mode.
   31             2 => *program
   32                 .get(&((*relative_base + program[&loc]) as usize))
   33                 .unwrap_or(&0),
   34             _ => panic!(),
   35         }
   36     };
   37 
   38     let get_res_loc =
   39         |loc: usize, mode, program: &HashMap<usize, Op>, relative_base: &Op| -> usize {
   40             match mode {
   41                 // Position mode.
   42                 0 => program[&loc] as usize,
   43                 // Immediate mode is banned.
   44                 // Relative mode.
   45                 2 => (relative_base + program[&loc]) as usize,
   46                 _ => panic!(),
   47             }
   48         };
   49 
   50     loop {
   51         let op_code = program[pc] % 100;
   52         let mode_1 = (program[pc] % 1000) / 100;
   53         let mode_2 = (program[pc] % 10000) / 1000;
   54         let mode_3 = (program[pc] % 100000) / 10000;
   55         match op_code {
   56             1 => {
   57                 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base);
   58                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
   59                 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base);
   60                 *program.entry(res_loc).or_default() = param_1 + param_2;
   61                 *pc += 4;
   62             }
   63             2 => {
   64                 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base);
   65                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
   66                 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base);
   67                 *program.entry(res_loc as usize).or_default() = param_1 * param_2;
   68                 *pc += 4;
   69             }
   70             3 => {
   71                 let res_loc = get_res_loc(*pc + 1, mode_1, &program, relative_base);
   72                 // Only use input once.
   73                 if input.is_some() {
   74                     *program.entry(res_loc as usize).or_default() = input.unwrap();
   75                     *input = None;
   76                 } else {
   77                     // Need new input.
   78                     return (false, output);
   79                 };
   80                 *pc += 2;
   81             }
   82             4 => {
   83                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
   84                 output.push(param_1);
   85                 *pc += 2;
   86             }
   87             5 => {
   88                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
   89                 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base);
   90                 if param_1 != 0 {
   91                     *pc = param_2 as usize;
   92                 } else {
   93                     *pc += 3;
   94                 }
   95             }
   96             6 => {
   97                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
   98                 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base);
   99                 if param_1 == 0 {
  100                     *pc = param_2 as usize;
  101                 } else {
  102                     *pc += 3;
  103                 }
  104             }
  105             7 => {
  106                 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base);
  107                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
  108                 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base);
  109                 *program.entry(res_loc as usize).or_default() =
  110                     if param_1 < param_2 { 1 } else { 0 };
  111                 *pc += 4;
  112             }
  113             8 => {
  114                 let res_loc = get_res_loc(*pc + 3, mode_3, &program, relative_base);
  115                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
  116                 let param_2 = get_param(*pc + 2, mode_2, &program, relative_base);
  117                 *program.entry(res_loc as usize).or_default() =
  118                     if param_1 == param_2 { 1 } else { 0 };
  119                 *pc += 4;
  120             }
  121             9 => {
  122                 let param_1 = get_param(*pc + 1, mode_1, &program, relative_base);
  123                 *relative_base += param_1;
  124                 *pc += 2;
  125             }
  126             99 => {
  127                 break;
  128             }
  129             _ => {
  130                 println!("Unknown op {}", op_code);
  131                 println!("{}", program[pc]);
  132                 panic!();
  133             }
  134         }
  135     }
  136     (true, output)
  137 }
  138 
  139 fn get_view(input: &Vec<Op>) -> Vec<Vec<char>> {
  140     // Get view of the scaffoldings.
  141     let mut program = input
  142         .iter()
  143         .enumerate()
  144         .map(|(idx, &op)| (idx, op))
  145         .collect::<HashMap<usize, Op>>();
  146     // Set program state.
  147     let mut pc = 0;
  148     let mut relative_base = 0;
  149     let (_, output) = computer_step(&mut program, &mut pc, &mut relative_base, &mut None);
  150     // Split output into vector of vector.
  151     let width = output
  152         .iter()
  153         .enumerate()
  154         .filter(|(_, &op)| op == 10)
  155         .next()
  156         .unwrap()
  157         .0
  158         + 1;
  159     // No need to include the new lines at the end.
  160     output[..(output.len() - 1)]
  161         .chunks(width)
  162         .map(|chunk| {
  163             chunk
  164                 .iter()
  165                 .filter(|&&op| op != 10)
  166                 .map(|&op| op as u8 as char)
  167                 .collect()
  168         })
  169         .collect()
  170 }
  171 
  172 fn print_view(view: &Vec<Vec<char>>) {
  173     for row in view {
  174         for px in row {
  175             print!("{}", px);
  176         }
  177         println!();
  178     }
  179 }
  180 
  181 fn calc_alignment_parameter(view: &Vec<Vec<char>>) -> usize {
  182     // Get view width.
  183     let width = view[0].len();
  184     let height = view.len();
  185     let mut alignment_param = 0;
  186     // Current coordinate.
  187     // No intersection can occur on the borders.
  188     for x in 1..(width - 1) {
  189         for y in 1..(height - 1) {
  190             // Check for intersection.
  191             // All 5 squares should be scaffolding.
  192             if view[y][x] != '.'
  193                 && view[y][x + 1] != '.'
  194                 && view[y][x - 1] != '.'
  195                 && view[y + 1][x] != '.'
  196                 && view[y - 1][x] != '.'
  197             {
  198                 alignment_param += x * y;
  199             }
  200         }
  201     }
  202     alignment_param
  203 }
  204 
  205 fn collect_dust(
  206     input: &Vec<Op>,
  207     main_routine: &Vec<Op>,
  208     func_a: &Vec<Op>,
  209     func_b: &Vec<Op>,
  210     func_c: &Vec<Op>,
  211 ) -> usize {
  212     let mut program = input
  213         .iter()
  214         .enumerate()
  215         .map(|(idx, &op)| (idx, op))
  216         .collect::<HashMap<usize, Op>>();
  217     // Enable movements.
  218     *program.get_mut(&0).unwrap() = 2;
  219     // Set program state.
  220     let mut pc = 0;
  221     let mut relative_base = 0;
  222     // Assemble commands.
  223     let mut commands = main_routine
  224         .iter()
  225         .chain(func_a)
  226         .chain(func_b)
  227         .chain(func_c)
  228         .chain(&['n' as u8 as Op, '\n' as u8 as Op]) // No video feeds.
  229         .cloned()
  230         .collect::<VecDeque<Op>>();
  231     // Collect output.
  232     let mut output = Vec::new();
  233     // Run program.
  234     loop {
  235         let (finished, mut step_output) = computer_step(
  236             &mut program,
  237             &mut pc,
  238             &mut relative_base,
  239             &mut commands.pop_front(),
  240         );
  241         output.append(&mut step_output);
  242         if finished {
  243             break;
  244         }
  245     }
  246     *output.last().unwrap() as usize
  247 }
  248 
  249 fn part_1(input: &Vec<Op>) -> usize {
  250     let view = get_view(input);
  251     print_view(&view);
  252     calc_alignment_parameter(&view)
  253 }
  254 
  255 fn part_2(input: &Vec<Op>) -> usize {
  256     let cmd_to_ascii = |cmd: &str| -> Vec<Op> { cmd.chars().map(|ch| ch as u8 as Op).collect() };
  257     let main_routine = cmd_to_ascii("A,B,A,B,C,A,B,C,A,C\n");
  258     let func_a = cmd_to_ascii("R,6,L,6,L,10\n");
  259     let func_b = cmd_to_ascii("L,8,L,6,L,10,L,6\n");
  260     let func_c = cmd_to_ascii("R,6,L,8,L,10,R,6\n");
  261     collect_dust(input, &main_routine, &func_a, &func_b, &func_c)
  262 }