day 17 was a doozy
This commit is contained in:
		
							parent
							
								
									534ebef096
								
							
						
					
					
						commit
						5f0d6f9869
					
				
							
								
								
									
										6
									
								
								day17/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								day17/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| [package] | ||||
| name = "day17" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| [dependencies] | ||||
							
								
								
									
										257
									
								
								day17/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								day17/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,257 @@ | ||||
| use std::collections::HashSet; | ||||
| use std::collections::HashMap; | ||||
| use std::env; | ||||
| use std::fs; | ||||
| 
 | ||||
| fn main() { | ||||
|     println!("Hello, AoC day 13!"); | ||||
| 
 | ||||
|     let args: Vec<String> = env::args().collect(); | ||||
|     if args.len() != 2 { | ||||
|         println!("wrong number of arguments!"); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
| 
 | ||||
|     let file_path = &args[1]; | ||||
| 
 | ||||
|     let binding = fs::read_to_string(file_path) | ||||
|         .expect("should be able to read the file"); | ||||
| 
 | ||||
|     let mut register: [u128; 3] = [0,0,0]; | ||||
|     let mut program: Vec<u8> = Vec::new(); | ||||
|     let mut instruction_pointer: usize = 0; | ||||
|     let mut stdout: Vec<u8> = Vec::new(); | ||||
| 
 | ||||
|     for line in binding.lines() { | ||||
|         if line.contains("Register A: ") { | ||||
|             register[0] = line.replace("Register A: ", "").parse().unwrap(); | ||||
|         } | ||||
|         if line.contains("Register B: ") { | ||||
|             register[1] = line.replace("Register B: ", "").parse().unwrap(); | ||||
|         } | ||||
|         if line.contains("Register B: ") { | ||||
|             register[2] = line.replace("Register B: ", "").parse().unwrap(); | ||||
|         } | ||||
| 
 | ||||
|         if line.contains("Program: ") { | ||||
|             program = line.replace("Program: ", "") | ||||
|                 .split(",") | ||||
|                 .map(|x| x.parse().unwrap()) | ||||
|                 .collect(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     println!("initial state:"); | ||||
|     print_state(®ister, &program, &instruction_pointer); | ||||
| 
 | ||||
|     // part a
 | ||||
|     print!("program output: "); | ||||
|     while let Ok(result) = step(&mut register, &program, &mut instruction_pointer) { | ||||
|         if let Some(output) = result { | ||||
|             stdout.push(output); | ||||
|         } | ||||
|     } | ||||
|     println!("{stdout:?}"); | ||||
| 
 | ||||
|     println!(""); | ||||
| 
 | ||||
|     // part b
 | ||||
|     let mut head = vec![0_u128]; | ||||
|     let mut suffixes: HashMap<u128, Vec<u8>> = HashMap::new(); | ||||
|     let mut winners: HashSet<u128> = HashSet::new(); | ||||
|     while let Some(prefix) = head.pop() { | ||||
|         let desired; | ||||
|         if prefix == 0 { | ||||
|             desired = program[program.len()-1]; | ||||
|         } else { | ||||
|             let length = format!("{prefix:o}").len(); | ||||
|             if length >= program.len() { | ||||
|                 winners.insert(prefix); | ||||
|                 continue; | ||||
|             } | ||||
|             desired = program[program.len() - length - 1] | ||||
|         } | ||||
|         if suffixes.contains_key(&prefix) { continue; } | ||||
|         let octets = find_octets(prefix, desired); | ||||
|         for x in &octets { | ||||
|             head.push((prefix << 3) + (*x as u128)); | ||||
|         } | ||||
|         suffixes.insert(prefix, octets); | ||||
|     } | ||||
| 
 | ||||
|     let mut smallest = u128::MAX; | ||||
|     
 | ||||
|     for winner in winners { | ||||
|         if winner < smallest { 
 | ||||
|             smallest = winner; | ||||
|         } | ||||
|     }    
 | ||||
| 
 | ||||
|     println!("the smallest quining initial value was {smallest} "); | ||||
| 
 | ||||
|     register[0] = smallest; | ||||
|     register[1] = 0; | ||||
|     register[2] = 0; | ||||
|     
 | ||||
|     instruction_pointer = 0; | ||||
|     
 | ||||
|     stdout.drain(..); | ||||
| 
 | ||||
|     println!("program output: "); | ||||
|     while let Ok(result) = step(&mut register, &program, &mut instruction_pointer) { | ||||
|         if let Some(output) = result { | ||||
|             stdout.push(output); | ||||
|         } | ||||
|     } | ||||
|     println!("{program:?}"); | ||||
|     println!("{stdout:?}"); | ||||
| } | ||||
| 
 | ||||
| fn step( | ||||
|     register: &mut [u128; 3], 
 | ||||
|     program: &Vec<u8>, 
 | ||||
|     instruction_pointer: &mut usize) 
 | ||||
| -> Result<Option<u8>, ()> { | ||||
| 
 | ||||
|     if *instruction_pointer >= program.len() { return Err(()); } | ||||
|     let instruction = program[*instruction_pointer]; | ||||
|     if *instruction_pointer + 1 >= program.len() { return Err(()); } | ||||
|     let operand = program[*instruction_pointer + 1]; | ||||
| 
 | ||||
|     let literal_operand = operand; | ||||
|     let combo_operand = match operand { 
 | ||||
|         4 => register[0], 
 | ||||
|         5 => register[1], 
 | ||||
|         6 => register[2], | ||||
|         anything => anything.into(), | ||||
|     }; | ||||
|     let mut output: Option<u8> = None; | ||||
| 
 | ||||
|     *instruction_pointer += 2; | ||||
| 
 | ||||
|     /* | ||||
|     println!("executing {} {}", | ||||
|         match instruction {0=>"adv",1=>"bxl",2=>"bst",3=>"jnz",4=>"bxc",5=>"out",6=>"bdv",7=>"cdv",_=>"???"}, | ||||
|         literal_operand); | ||||
|     */ 
 | ||||
| 
 | ||||
|     match instruction { | ||||
|         0 => { register[0] = div_thing(register[0], combo_operand); }, // adv
 | ||||
|         1 => { register[1] = register[1] ^ (literal_operand as u128); }, // bxl
 | ||||
|         2 => { register[1] = combo_operand % 8; }, // bst
 | ||||
|         3 => match register[0] { // jnz
 | ||||
|             0 => {}, | ||||
|             _ => { *instruction_pointer = literal_operand as usize; } | ||||
|         }, | ||||
|         4 => { register[1] = register[1] ^ register[2]; }, // bxc
 | ||||
|         5 => { output = Some((combo_operand % 8) as u8); }, // out
 | ||||
|         6 => { register[1] = div_thing(register[0], combo_operand); }, // bdv
 | ||||
|         7 => { register[2] = div_thing(register[0], combo_operand); }, // cdv
 | ||||
|         _ => { return Err(()); }, | ||||
|     } | ||||
|     return Ok(output); | ||||
| } | ||||
| 
 | ||||
| fn div_thing(a: u128, b: u128) -> u128 { | ||||
|     let power = 2_u128.pow(b.try_into().unwrap()); | ||||
|     return a / power; | ||||
| } | ||||
| 
 | ||||
| fn print_state(register: &[u128;3], program: &Vec<u8>, instruction_pointer: &usize) { | ||||
|     println!("registers: {register:?}"); | ||||
|     println!("program: {program:?}"); | ||||
|     println!("current pointer: {instruction_pointer}"); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| 
 | ||||
| 
 | ||||
| 2 bst -> modulo combo operand => B | ||||
| 4 bxc -> B xor C => B | ||||
| 
 | ||||
| 1 bxl -> B xor literal operand => B | ||||
| 4 bxc -> B xor C => B | ||||
| 
 | ||||
| 7 cdv -> A / 2^(combo operand) => C | ||||
| 5 out -> print combo operand | ||||
| 
 | ||||
| 4 bxc -> B xor C => B | ||||
| 1 bxl -> B xor literal operand => B | ||||
| 
 | ||||
| 1 bxl -> B xor literal operand => B | ||||
| 4 bxc -> B xor C => B | ||||
| 
 | ||||
| 5 out => print combo operand 
 | ||||
| 5 out => print combo operand | ||||
| 
 | ||||
| 0 adv => A / 2^(combo operand) => A | ||||
| 3 jnz => jump literal operand if A != 0 | ||||
| 
 | ||||
| 3 jnz => jump literal operand if A != 0 | ||||
| 0 adv => A / 2^(combo operand) => A | ||||
| 
 | ||||
| 2,4,1,4,7,5,4,1,1,4,5,5,0,3,3,0 | ||||
| 
 | ||||
| there is only one JNZ executed in the normal execution, and it goes to the start. 
 | ||||
| all instructions are always aligned. | ||||
| 
 | ||||
| 
 | ||||
| 2 bst -> A % 8 => B | ||||
| 1 bxl -> B xor 4 => B | ||||
| 7 cdv -> A / 2^B => C | ||||
| 4 bxc -> B xor C => B | ||||
| 1 bxl -> B xor 4 => B | ||||
| 5 out => print B | ||||
| 0 adv => A / 2^3 => A | ||||
| 
 | ||||
| halt if A == 0, otherwise repeat | ||||
| 
 | ||||
| 
 | ||||
| B = X % 8 | ||||
| B = B xor 4 // flip byte 3 (4's position)
 | ||||
| C = A >> B | ||||
| B = B xor C | ||||
| B = B xor 4 // flip byte 3
 | ||||
| print B | ||||
| A = A / 2^3 | ||||
| treat A as a sequence of octets | ||||
| 
 | ||||
| 0o7654321 | ||||
| _111_110_101_100_011_010_001 | ||||
| B = 001 | ||||
| B = 001 xor 100 = 101 = 0d5 | ||||
| C = _111_110_101_100_011_010_001 >> 5 = 001_111_101_011_000_110 | ||||
| B = B xor C = 101 xor 001_111_101_011_000_110 = 001_111_101_011_000_011 | ||||
| print 011 = 0d3 | ||||
| A = A >> 3 | ||||
| 
 | ||||
| last octet we want to output is 0 = 000 | ||||
| 
 | ||||
| X = 000...ijk | ||||
| B=ijk | ||||
| B = i j k xor 4 => ~i j k | ||||
| C = i j k >> ~i j k | ||||
| B = ~i j k xor C | ||||
| B = B xor 4 | ||||
| print B | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| fn find_octets(prefix: u128, target: u8) -> Vec<u8> {  
 | ||||
|     // returns all suffixes such that (prefix << 3) + suffix produces target as the output
 | ||||
|     let mut suffixes: Vec<u8> = Vec::with_capacity(3); | ||||
|     
 | ||||
|     for candidate in 0..8_u8 { | ||||
|         let a = (prefix << 3) + (candidate as u128); | ||||
|         let mut b = a % 8; | ||||
|         b = b ^ 4; | ||||
|         let c = a >> b; | ||||
|         b = b ^ c; | ||||
|         b = b ^ 4; | ||||
|         if b % 8 == target.into() { | ||||
|             suffixes.push(candidate); | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     suffixes | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user