advent-of-code

Perserverance, or the lack thereof

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

day-07.rs (8020B)

    1 use std::collections::VecDeque;
    2 
    3 fn main() {
    4     let input = std::fs::read_to_string("input.txt")
    5         .unwrap()
    6         .trim()
    7         .split(",")
    8         .map(|op| op.parse::<i32>().unwrap())
    9         .collect::<Vec<i32>>();
   10     println!("Rust:");
   11     println!("Part 1: {}", part_1(&input));
   12     println!("Part 2: {}", part_2(&input));
   13 }
   14 
   15 fn computer(program: &Vec<i32>, input: &Vec<i32>) -> Vec<i32> {
   16     let mut program = program.clone();
   17     let mut input = input.clone().into_iter().collect::<VecDeque<i32>>();
   18     let mut output = vec![];
   19     let mut pc = 0;
   20 
   21     loop {
   22         let (finished, mut step_output) = computer_step(&mut program, &mut pc, input.pop_front());
   23         output.append(&mut step_output);
   24         if finished {
   25             break;
   26         }
   27     }
   28 
   29     output
   30 }
   31 
   32 fn computer_step(
   33     program: &mut Vec<i32>,
   34     pc: &mut usize,
   35     mut input: Option<i32>,
   36 ) -> (bool, Vec<i32>) {
   37     // Runs from given pc until completion or next request for input.
   38     // Modifies program and pc.
   39     // Returns if the program has terminated and the output.
   40     let mut output = vec![];
   41 
   42     let get_param = |loc: usize, im_mode: bool, program: &Vec<i32>| -> i32 {
   43         if im_mode {
   44             program[loc]
   45         } else {
   46             program[program[loc] as usize]
   47         }
   48     };
   49 
   50     loop {
   51         let op_code = program[*pc] % 100;
   52         let im_mode_1 = (program[*pc] % 1000) / 100 > 0;
   53         let im_mode_2 = (program[*pc] % 10000) / 1000 > 0;
   54         // Third parameter is location to write to, and will never be immediate
   55         // mode.
   56         match op_code {
   57             1 => {
   58                 let res_loc = program[*pc + 3];
   59                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
   60                 let param_2 = get_param(*pc + 2, im_mode_2, &program);
   61                 program[res_loc as usize] = param_1 + param_2;
   62                 *pc += 4;
   63             }
   64             2 => {
   65                 let res_loc = program[*pc + 3];
   66                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
   67                 let param_2 = get_param(*pc + 2, im_mode_2, &program);
   68                 program[res_loc as usize] = param_1 * param_2;
   69                 *pc += 4;
   70             }
   71             3 => {
   72                 let res_loc = program[*pc + 1];
   73                 // Only use input once.
   74                 if input.is_some() {
   75                     program[res_loc as usize] = input.unwrap();
   76                     input = None;
   77                 } else {
   78                     // Need new input.
   79                     return (false, output);
   80                 };
   81                 *pc += 2;
   82             }
   83             4 => {
   84                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
   85                 output.push(param_1);
   86                 *pc += 2;
   87             }
   88             5 => {
   89                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
   90                 let param_2 = get_param(*pc + 2, im_mode_2, &program);
   91                 if param_1 != 0 {
   92                     *pc = param_2 as usize;
   93                 } else {
   94                     *pc += 3;
   95                 }
   96             }
   97             6 => {
   98                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
   99                 let param_2 = get_param(*pc + 2, im_mode_2, &program);
  100                 if param_1 == 0 {
  101                     *pc = param_2 as usize;
  102                 } else {
  103                     *pc += 3;
  104                 }
  105             }
  106             7 => {
  107                 let res_loc = program[*pc + 3];
  108                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
  109                 let param_2 = get_param(*pc + 2, im_mode_2, &program);
  110                 program[res_loc as usize] = if param_1 < param_2 { 1 } else { 0 };
  111                 *pc += 4;
  112             }
  113             8 => {
  114                 let res_loc = program[*pc + 3];
  115                 let param_1 = get_param(*pc + 1, im_mode_1, &program);
  116                 let param_2 = get_param(*pc + 2, im_mode_2, &program);
  117                 program[res_loc as usize] = if param_1 == param_2 { 1 } else { 0 };
  118                 *pc += 4;
  119             }
  120             99 => {
  121                 break;
  122             }
  123             _ => {
  124                 println!("Unknown op {}", op_code);
  125                 println!("{}", program[*pc]);
  126                 panic!();
  127             }
  128         }
  129     }
  130 
  131     (true, output)
  132 }
  133 
  134 fn feedback_amp(program: &Vec<i32>, phase: &Vec<i32>) -> i32 {
  135     let num_amps = phase.len();
  136     let mut programs = vec![program.clone(); num_amps];
  137     let mut pcs = vec![0; num_amps];
  138     let mut inputs = phase
  139         .iter()
  140         .map(|&x| {
  141             let mut input = VecDeque::<i32>::new();
  142             input.push_back(x);
  143             input
  144         })
  145         .collect::<Vec<VecDeque<i32>>>();
  146 
  147     // Additional input for first amplifier.
  148     inputs[0].push_back(0);
  149     // Index of currently working amp.
  150     let mut work_idx = 0;
  151     loop {
  152         // Run current amp.
  153         let (finished, step_output) = computer_step(
  154             &mut programs[work_idx],
  155             &mut pcs[work_idx],
  156             inputs[work_idx].pop_front(),
  157         );
  158         // Pipe output to next amp.
  159         step_output
  160             .into_iter()
  161             .for_each(|x| inputs[(work_idx + 1) % num_amps].push_back(x));
  162         // Check for completion.
  163         if finished && work_idx + 1 == num_amps {
  164             break;
  165         }
  166         // Move to next amp.
  167         work_idx = (work_idx + 1) % num_amps;
  168     }
  169 
  170     *inputs[0].back().unwrap()
  171 }
  172 
  173 fn part_1(input: &Vec<i32>) -> i32 {
  174     let mut max_output = 0;
  175     for phase_1 in 0..=4 {
  176         let out_1 = computer(input, &vec![phase_1, 0])[0];
  177         for phase_2 in 0..=4 {
  178             if phase_2 == phase_1 {
  179                 continue;
  180             }
  181             let out_2 = computer(input, &vec![phase_2, out_1])[0];
  182             for phase_3 in 0..=4 {
  183                 if phase_3 == phase_1 || phase_3 == phase_2 {
  184                     continue;
  185                 }
  186                 let out_3 = computer(input, &vec![phase_3, out_2])[0];
  187                 for phase_4 in 0..=4 {
  188                     if phase_4 == phase_1 || phase_4 == phase_2 || phase_4 == phase_3 {
  189                         continue;
  190                     }
  191                     let out_4 = computer(input, &vec![phase_4, out_3])[0];
  192                     for phase_5 in 0..=4 {
  193                         if phase_5 == phase_1
  194                             || phase_5 == phase_2
  195                             || phase_5 == phase_3
  196                             || phase_5 == phase_4
  197                         {
  198                             continue;
  199                         }
  200                         let out_5 = computer(input, &vec![phase_5, out_4])[0];
  201                         max_output = max_output.max(out_5);
  202                     }
  203                 }
  204             }
  205         }
  206     }
  207 
  208     max_output
  209 }
  210 
  211 fn part_2(input: &Vec<i32>) -> i32 {
  212     let mut max_output = 0;
  213 
  214     for phase_1 in 5..=9 {
  215         for phase_2 in 5..=9 {
  216             if phase_2 == phase_1 {
  217                 continue;
  218             }
  219             for phase_3 in 5..=9 {
  220                 if phase_3 == phase_1 || phase_3 == phase_2 {
  221                     continue;
  222                 }
  223                 for phase_4 in 5..=9 {
  224                     if phase_4 == phase_1 || phase_4 == phase_2 || phase_4 == phase_3 {
  225                         continue;
  226                     }
  227                     for phase_5 in 5..=9 {
  228                         if phase_5 == phase_1
  229                             || phase_5 == phase_2
  230                             || phase_5 == phase_3
  231                             || phase_5 == phase_4
  232                         {
  233                             continue;
  234                         }
  235                         max_output = max_output.max(feedback_amp(
  236                             input,
  237                             &vec![phase_1, phase_2, phase_3, phase_4, phase_5],
  238                         ));
  239                     }
  240                 }
  241             }
  242         }
  243     }
  244 
  245     max_output
  246 }