day24
This commit is contained in:
		
							parent
							
								
									ac4c0f3838
								
							
						
					
					
						commit
						6585356f0e
					
				| @ -145,22 +145,6 @@ fn expand_cliques(current: Vec<usize>, num: usize, adj: &[Vec<usize>]) -> Vec<Ve | ||||
|     expansions | ||||
| } | ||||
| 
 | ||||
| // fn max_clique(r: &mut HashSet<usize>, coloring: &[i32]) {
 | ||||
| //     let mut q = HashSet::new();
 | ||||
| //     let mut q_max = HashSet::new();
 | ||||
| 
 | ||||
| //     while !r.is_empty() {
 | ||||
| //         let p = *r.iter().max_by_key(|node| coloring[**node]).unwrap();
 | ||||
| //         r.remove(&p);
 | ||||
| //         if q.len() + coloring[p] > q_max.len() {
 | ||||
| //             q.insert(p);
 | ||||
| //             q.remove(p);
 | ||||
| //         } else {
 | ||||
| //             return;
 | ||||
| //         }
 | ||||
| //     }
 | ||||
| // }
 | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|  | ||||
							
								
								
									
										303
									
								
								aoc_2024/src/day24.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								aoc_2024/src/day24.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,303 @@ | ||||
| use std::collections::VecDeque; | ||||
| 
 | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use hashbrown::{HashMap, HashSet}; | ||||
| use nom::{ | ||||
|     bytes::complete::tag, | ||||
|     character::complete::{anychar, newline, one_of, space1, u64}, | ||||
|     multi::{fill, many1, separated_list0}, | ||||
|     sequence::{delimited, separated_pair}, | ||||
|     IResult, | ||||
| }; | ||||
| 
 | ||||
| type Line = [char; 3]; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| enum Operation { | ||||
|     And, | ||||
|     Or, | ||||
|     Xor, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| struct Gate { | ||||
|     operation: Operation, | ||||
|     in_0: Line, | ||||
|     in_1: Line, | ||||
|     out: Line, | ||||
| } | ||||
| 
 | ||||
| type Input = (Vec<(Line, u64)>, Vec<Gate>); | ||||
| 
 | ||||
| #[aoc_generator(day24)] | ||||
| fn parse(input: &str) -> Input { | ||||
|     separated_pair( | ||||
|         separated_list0(newline, separated_pair(parse_line, tag(": "), u64)), | ||||
|         tag("\n\n"), | ||||
|         separated_list0(newline, parse_instruction), | ||||
|     )(input) | ||||
|     .unwrap() | ||||
|     .1 | ||||
| } | ||||
| 
 | ||||
| fn parse_line(input: &str) -> IResult<&str, [char; 3]> { | ||||
|     let mut buffer = ['0'; 3]; | ||||
|     let (input, _) = fill(anychar, &mut buffer)(input)?; | ||||
|     Ok((input, buffer)) | ||||
| } | ||||
| 
 | ||||
| fn parse_instruction(input: &str) -> IResult<&str, Gate> { | ||||
|     let (input, in_0) = parse_line(input)?; | ||||
|     let (input, operation) = delimited(space1, many1(one_of("ANDXOR")), space1)(input)?; | ||||
|     let (input, in_1) = parse_line(input)?; | ||||
|     let (input, _) = tag(" -> ")(input)?; | ||||
|     let (input, out) = parse_line(input)?; | ||||
|     match operation[0] { | ||||
|         'A' => Ok(( | ||||
|             input, | ||||
|             Gate { | ||||
|                 in_0, | ||||
|                 in_1, | ||||
|                 out, | ||||
|                 operation: Operation::And, | ||||
|             }, | ||||
|         )), | ||||
|         'O' => Ok(( | ||||
|             input, | ||||
|             Gate { | ||||
|                 in_0, | ||||
|                 in_1, | ||||
|                 out, | ||||
|                 operation: Operation::Or, | ||||
|             }, | ||||
|         )), | ||||
|         'X' => Ok(( | ||||
|             input, | ||||
|             Gate { | ||||
|                 in_0, | ||||
|                 in_1, | ||||
|                 out, | ||||
|                 operation: Operation::Xor, | ||||
|             }, | ||||
|         )), | ||||
|         _ => unreachable!(), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[aoc(day24, part1)] | ||||
| fn part1(input: &Input) -> usize { | ||||
|     let fixed = &input.0; | ||||
| 
 | ||||
|     let mut values = HashMap::new(); | ||||
| 
 | ||||
|     for (line, value) in fixed { | ||||
|         values.insert(line, *value); | ||||
|     } | ||||
| 
 | ||||
|     let mut gates = VecDeque::new(); | ||||
| 
 | ||||
|     for gate in &input.1 { | ||||
|         gates.push_back(gate); | ||||
|     } | ||||
| 
 | ||||
|     while let Some(gate) = gates.pop_front() { | ||||
|         if values.contains_key(&gate.in_0) && values.contains_key(&gate.in_1) { | ||||
|             let in_0 = values[&gate.in_0]; | ||||
|             let in_1 = values[&gate.in_1]; | ||||
|             let out = match gate.operation { | ||||
|                 Operation::And => in_0 & in_1, | ||||
|                 Operation::Or => in_0 | in_1, | ||||
|                 Operation::Xor => in_0 ^ in_1, | ||||
|             }; | ||||
|             values.insert(&gate.out, out); | ||||
|         } else { | ||||
|             gates.push_back(gate); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     values | ||||
|         .into_iter() | ||||
|         .filter(|(line, value)| line[0] == 'z' && *value == 1) | ||||
|         .map(|(line, _)| { | ||||
|             1 << line[1..3] | ||||
|                 .iter() | ||||
|                 .collect::<String>() | ||||
|                 .parse::<u64>() | ||||
|                 .unwrap() | ||||
|         }) | ||||
|         .sum() | ||||
| } | ||||
| 
 | ||||
| #[aoc(day24, part2)] | ||||
| fn part2(input: &Input) -> String { | ||||
|     let swaps: &[(Line, Line)] = &[ | ||||
|         (['h', 'm', 't'], ['z', '1', '8']), | ||||
|         (['b', 'f', 'q'], ['z', '2', '7']), | ||||
|         (['h', 'k', 'h'], ['z', '3', '1']), | ||||
|         (['f', 'j', 'p'], ['b', 'n', 'g']), | ||||
|     ]; | ||||
|     // let swaps: &[(Line, Line)] = &[];
 | ||||
|     let mut gates = input.1.clone(); | ||||
|     for gate in &mut gates { | ||||
|         for (from, to) in swaps { | ||||
|             if gate.out == *from { | ||||
|                 gate.out = *to; | ||||
|             } else if gate.out == *to { | ||||
|                 gate.out = *from; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for gate in &gates { | ||||
|         if gate.out[0] == 'z' && gate.operation != Operation::Xor { | ||||
|             println!("gate {:?} outputs to a z but is not xor", gate); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let mut c = ['r', 'j', 'r']; | ||||
| 
 | ||||
|     for bit in 1..=44 { | ||||
|         let x = [ | ||||
|             'x', | ||||
|             (bit as u8 / 10 + 48) as char, | ||||
|             (bit as u8 % 10 + 48) as char, | ||||
|         ]; | ||||
|         let y = [ | ||||
|             'y', | ||||
|             (bit as u8 / 10 + 48) as char, | ||||
|             (bit as u8 % 10 + 48) as char, | ||||
|         ]; | ||||
| 
 | ||||
|         let xy_gates = find_gate(&gates, &x, &y); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             xy_gates.len(), | ||||
|             2, | ||||
|             "there is not exactly two xy gates {:?}\nrelated gates: {:?}", | ||||
|             xy_gates, | ||||
|             find_debug_gate(&gates, &x, &y) | ||||
|         ); | ||||
| 
 | ||||
|         let line_xy_xor = xy_gates | ||||
|             .iter() | ||||
|             .find(|g| g.operation == Operation::Xor) | ||||
|             .unwrap() | ||||
|             .out; | ||||
| 
 | ||||
|         let line_xy_and = xy_gates | ||||
|             .iter() | ||||
|             .find(|g| g.operation == Operation::And) | ||||
|             .unwrap() | ||||
|             .out; | ||||
| 
 | ||||
|         let xyc_gates = find_gate(&gates, &line_xy_xor, &c); | ||||
| 
 | ||||
|         assert_eq!(xyc_gates.len(), 2, | ||||
|             "there is not exactly two output gates {:?}\nrelated gates: {:?}\nxy_and: {}\nxy_xor: {}", | ||||
|             xyc_gates, | ||||
|             find_debug_gate(&gates, &line_xy_xor, &c), | ||||
|             display_line(&line_xy_and), | ||||
|             display_line(&line_xy_xor), | ||||
|         ); | ||||
| 
 | ||||
|         let line_xyc_xor = xyc_gates | ||||
|             .iter() | ||||
|             .find(|g| g.operation == Operation::Xor) | ||||
|             .unwrap() | ||||
|             .out; | ||||
| 
 | ||||
|         let line_xyc_and = xyc_gates | ||||
|             .iter() | ||||
|             .find(|g| g.operation == Operation::And) | ||||
|             .unwrap() | ||||
|             .out; | ||||
| 
 | ||||
|         let xyco_gates = find_gate(&gates, &line_xyc_and, &line_xy_and); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             xyco_gates.len(), | ||||
|             1, | ||||
|             "there is no or more than one output gate {:?}\nrelated gates: {:?}\nxy_and: {}\nxy_xor: {}\nxyc_and: {}\nxyc_xor: {}", | ||||
|             xyco_gates, | ||||
|             find_debug_gate(&gates, &line_xyc_and, &line_xy_and), | ||||
|             display_line(&line_xy_and), | ||||
|             display_line(&line_xy_xor), | ||||
|             display_line(&line_xyc_and), | ||||
|             display_line(&line_xyc_xor), | ||||
|         ); | ||||
| 
 | ||||
|         c = xyco_gates[0].out; | ||||
| 
 | ||||
|         println!( | ||||
|             "for bit {} z-output is {} and carry out is {}", | ||||
|             bit, | ||||
|             display_line(&line_xyc_xor), | ||||
|             display_line(&c) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     let mut wires = swaps | ||||
|         .iter() | ||||
|         .flat_map(|(a, b)| [display_line(a), display_line(b)]) | ||||
|         .collect::<Vec<String>>(); | ||||
| 
 | ||||
|     wires.sort(); | ||||
| 
 | ||||
|     wires.join(",") | ||||
| } | ||||
| 
 | ||||
| fn display_line(line: &Line) -> String { | ||||
|     line.iter().collect() | ||||
| } | ||||
| 
 | ||||
| fn find_gate(gates: &[Gate], in_0: &Line, in_1: &Line) -> Vec<Gate> { | ||||
|     gates | ||||
|         .iter() | ||||
|         .filter(|gate| { | ||||
|             (gate.in_0 == *in_0 && gate.in_1 == *in_1) || (gate.in_0 == *in_1 && gate.in_1 == *in_0) | ||||
|         }) | ||||
|         .copied() | ||||
|         .collect() | ||||
| } | ||||
| 
 | ||||
| fn find_debug_gate(gates: &[Gate], in_0: &Line, in_1: &Line) -> Vec<Gate> { | ||||
|     gates | ||||
|         .iter() | ||||
|         .filter(|gate| { | ||||
|             gate.in_0 == *in_0 || gate.in_1 == *in_1 || gate.in_0 == *in_1 || gate.in_1 == *in_0 | ||||
|         }) | ||||
|         .copied() | ||||
|         .collect() | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!( | ||||
|             part1(&parse( | ||||
|                 "x00: 1
 | ||||
| x01: 1 | ||||
| x02: 1 | ||||
| y00: 0 | ||||
| y01: 1 | ||||
| y02: 0 | ||||
| 
 | ||||
| x00 AND y00 -> z00 | ||||
| x01 XOR y01 -> z01 | ||||
| x02 OR y02 -> z02" | ||||
|             )), | ||||
|             4 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part2_example() { | ||||
|         assert_eq!( | ||||
|             part2(&parse(include_str!("../input/2024/day24.txt").trim_end())), | ||||
|             "z00,z01,z02,z05" | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @ -1,3 +1,5 @@ | ||||
| mod day24; | ||||
| mod day23; | ||||
| mod day22; | ||||
| mod day21; | ||||
| mod day1; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jan-Bulthuis
						Jan-Bulthuis