day 23. also, long term nuclear warning messages in day 21.
This commit is contained in:
parent
926fc4f6a8
commit
28f5eb17b0
@ -4,3 +4,4 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
memoize = "0.4.2"
|
||||
|
@ -1,7 +1,22 @@
|
||||
/*
|
||||
THIS PLACE IS NOT A PLACE OF HONOR...
|
||||
NO HIGHLY ESTEEMED DEED IS COMMEMORATED HERE...
|
||||
NOTHING VALUED IS HERE.
|
||||
|
||||
THE DANGER IS PRESENT IN YOUR TIME AS IT WAS IN OURS.
|
||||
|
||||
THE DANGER IS UNLEASHED ONLY IF YOU SUBSTANTIALLY DISTURB THIS FILE...
|
||||
THIS FILE IS BEST LEFT SHUNNED AND UNINHABITED.
|
||||
*/
|
||||
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
use memoize::memoize;
|
||||
|
||||
use crate::Dir::{North, South, East, West, Stay };
|
||||
|
||||
|
||||
@ -118,7 +133,6 @@ fn main() {
|
||||
&keypad_door,
|
||||
&door_code,
|
||||
'A');
|
||||
println!("{options_door:?}");
|
||||
for arrow_code_1 in sequences(options_door, &door_map, keypad_door[&'A']) {
|
||||
print_code(&arrow_code_1);
|
||||
|
||||
@ -146,8 +160,519 @@ fn main() {
|
||||
}
|
||||
|
||||
println!("the sum of the complexity scores is {}", sum);
|
||||
|
||||
println!("okay let's play around");
|
||||
let code_0 = "029A";
|
||||
println!("starting sequence is {code_0}");
|
||||
let mut seed = 0;
|
||||
let code_1 = &expand(
|
||||
&code_0.chars().collect(),
|
||||
&door_map,
|
||||
&keypad_door,
|
||||
'A',
|
||||
&mut seed);
|
||||
print_code(code_1);
|
||||
let code_2 = &expand(
|
||||
&code_1,
|
||||
&keypad_map,
|
||||
&keypad_arrows,
|
||||
Stay,
|
||||
&mut seed);
|
||||
print_code(code_2);
|
||||
let code_3 = &expand(
|
||||
&code_2,
|
||||
&keypad_map,
|
||||
&keypad_arrows,
|
||||
Stay,
|
||||
&mut seed);
|
||||
print_code(code_3);
|
||||
let code_4 = &expand(
|
||||
&code_3,
|
||||
&keypad_map,
|
||||
&keypad_arrows,
|
||||
Stay,
|
||||
&mut seed);
|
||||
print_code(code_4);
|
||||
seed = 0b11111111111111111111111;
|
||||
let code_1 = &expand(
|
||||
&code_0.chars().collect(),
|
||||
&door_map,
|
||||
&keypad_door,
|
||||
'A',
|
||||
&mut seed);
|
||||
print_code(code_1);
|
||||
let code_2 = &expand(
|
||||
&code_1,
|
||||
&keypad_map,
|
||||
&keypad_arrows,
|
||||
Stay,
|
||||
&mut seed);
|
||||
print_code(code_2);
|
||||
let code_3 = &expand(
|
||||
&code_2,
|
||||
&keypad_map,
|
||||
&keypad_arrows,
|
||||
Stay,
|
||||
&mut seed);
|
||||
print_code(code_3);
|
||||
let code_4 = &expand(
|
||||
&code_3,
|
||||
&keypad_map,
|
||||
&keypad_arrows,
|
||||
Stay,
|
||||
&mut seed);
|
||||
print_code(code_4);
|
||||
|
||||
println!("\n\n\nokay, i think i got it. now let's do the memoized solution.");
|
||||
|
||||
|
||||
let mut bests: HashMap<(Dir, Dir), Vec<Dir>> = HashMap::new();
|
||||
for prev in [Stay, East, West, North, South] {
|
||||
for next in [Stay, East, West, North, South] {
|
||||
let four_deep = shortest_seq(
|
||||
keypad_arrows[&prev],
|
||||
keypad_arrows[&next],
|
||||
7,
|
||||
vec![(0,3)]);
|
||||
let mut result = four_deep;
|
||||
for _ in 0..6 {
|
||||
result = execute_code(&result, &keypad_map, keypad_arrows[&Stay]);
|
||||
}
|
||||
bests.insert((prev, next), result);
|
||||
}
|
||||
}
|
||||
for (key, value) in &bests {
|
||||
print!("{key:?}:");
|
||||
print_code(&value);
|
||||
}
|
||||
|
||||
let mut sum = 0;
|
||||
for line in file.lines() {
|
||||
let num: i32 = line[..line.len()-1].parse().expect("failed to parse door code as number");
|
||||
|
||||
println!("looking at code {line}, generating:");
|
||||
print_code(&thru_keypads(line, 2));
|
||||
print_code(&thru_keypads(line, 3));
|
||||
print_code(&thru_keypads(line, 4));
|
||||
|
||||
let extra = 25;
|
||||
let mut length = 0;
|
||||
let mut prev = 'A';
|
||||
for d in line.chars() {
|
||||
length += length_calc_numpad(prev, d, 1+extra);
|
||||
prev = d;
|
||||
}
|
||||
println!("length should be {length}");
|
||||
|
||||
sum += length * (num as i64);
|
||||
}
|
||||
|
||||
println!("the answer is {sum}");
|
||||
}
|
||||
|
||||
fn length_calc_numpad(prev: char, next: char, depth: i32) -> i64 {
|
||||
let optimals: HashMap<(char, char), Vec<Dir>> = HashMap::from([
|
||||
(('A', 'A'), vec![Stay]),
|
||||
(('A', '0'), vec![West, Stay]),
|
||||
(('A', '1'), vec![North, West, West, Stay]),
|
||||
(('A', '2'), vec![West, North, Stay]),
|
||||
(('A', '3'), vec![North, Stay]),
|
||||
(('A', '4'), vec![North, North, West, West, Stay]),
|
||||
(('A', '5'), vec![West, North, North, Stay]),
|
||||
(('A', '6'), vec![North, North, Stay]),
|
||||
(('A', '7'), vec![North, North, North, West, West, Stay]),
|
||||
(('A', '8'), vec![West, North, North, North, Stay]),
|
||||
(('A', '9'), vec![North, North, North, Stay]),
|
||||
|
||||
(('0', 'A'), vec![East, Stay]),
|
||||
(('0', '0'), vec![Stay]),
|
||||
(('0', '1'), vec![North, West, Stay]),
|
||||
(('0', '2'), vec![North, Stay]),
|
||||
(('0', '3'), vec![North, East, Stay]),
|
||||
(('0', '4'), vec![North, North, West, Stay]),
|
||||
(('0', '5'), vec![North, North, Stay]),
|
||||
(('0', '6'), vec![North, North, East, Stay]),
|
||||
(('0', '7'), vec![North, North, North, West, Stay]),
|
||||
(('0', '8'), vec![North, North, North, Stay]),
|
||||
(('0', '9'), vec![North, North, North, East, Stay]),
|
||||
|
||||
(('1', 'A'), vec![East, East, South, Stay]),
|
||||
(('1', '0'), vec![East, South, Stay]),
|
||||
(('1', '1'), vec![Stay]),
|
||||
(('1', '2'), vec![East, Stay]),
|
||||
(('1', '3'), vec![East, East, Stay]),
|
||||
(('1', '4'), vec![North, Stay]),
|
||||
(('1', '5'), vec![North, East, Stay]),
|
||||
(('1', '6'), vec![North, East, East, Stay]),
|
||||
(('1', '7'), vec![North, North, Stay]),
|
||||
(('1', '8'), vec![North, North, East, Stay]),
|
||||
(('1', '9'), vec![North, North, East, East, Stay]),
|
||||
|
||||
(('2', 'A'), vec![South, East, Stay]),
|
||||
(('2', '0'), vec![South, Stay]),
|
||||
(('2', '1'), vec![West, Stay]),
|
||||
(('2', '2'), vec![Stay]),
|
||||
(('2', '3'), vec![East, Stay]),
|
||||
(('2', '4'), vec![West, North, Stay]),
|
||||
(('2', '5'), vec![North, Stay]),
|
||||
(('2', '6'), vec![East, North, Stay]),
|
||||
(('2', '7'), vec![West, North, North, Stay]),
|
||||
(('2', '8'), vec![North, North, Stay]),
|
||||
(('2', '9'), vec![East, North, North, Stay]),
|
||||
|
||||
(('3', 'A'), vec![South, Stay]),
|
||||
(('3', '0'), vec![West, South, Stay]),
|
||||
(('3', '1'), vec![West, West, Stay]),
|
||||
(('3', '2'), vec![West, Stay]),
|
||||
(('3', '3'), vec![Stay]),
|
||||
(('3', '4'), vec![West, West, North, Stay]),
|
||||
(('3', '5'), vec![West, North, Stay]),
|
||||
(('3', '6'), vec![North, Stay]),
|
||||
(('3', '7'), vec![West, West, North, North, Stay]),
|
||||
(('3', '8'), vec![West, North, Stay]),
|
||||
(('3', '9'), vec![North, North, Stay]),
|
||||
|
||||
(('4', 'A'), vec![East, East, South, South, Stay]),
|
||||
(('4', '0'), vec![East, South, South, Stay]),
|
||||
(('4', '1'), vec![South, Stay]),
|
||||
(('4', '2'), vec![South, East, Stay]),
|
||||
(('4', '3'), vec![South, East, East, Stay]),
|
||||
(('4', '4'), vec![Stay]),
|
||||
(('4', '5'), vec![East, Stay]),
|
||||
(('4', '6'), vec![East, East, Stay]),
|
||||
(('4', '7'), vec![North, Stay]),
|
||||
(('4', '8'), vec![North, East, Stay]),
|
||||
(('4', '9'), vec![North, East, East, Stay]),
|
||||
|
||||
(('5', 'A'), vec![South, South, East, Stay]),
|
||||
(('5', '0'), vec![South, South, Stay]),
|
||||
(('5', '1'), vec![West, South, Stay]),
|
||||
(('5', '2'), vec![South, Stay]),
|
||||
(('5', '3'), vec![South, East, Stay]),
|
||||
(('5', '4'), vec![West, Stay]),
|
||||
(('5', '5'), vec![Stay]),
|
||||
(('5', '6'), vec![East, Stay]),
|
||||
(('5', '7'), vec![West, North, Stay]),
|
||||
(('5', '8'), vec![North, Stay]),
|
||||
(('5', '9'), vec![North, East, Stay]),
|
||||
|
||||
(('6', 'A'), vec![South, South, Stay]),
|
||||
(('6', '0'), vec![West, South, South, Stay]),
|
||||
(('6', '1'), vec![West, West, South, Stay]),
|
||||
(('6', '2'), vec![West, South, Stay]),
|
||||
(('6', '3'), vec![South, Stay]),
|
||||
(('6', '4'), vec![West, West, Stay]),
|
||||
(('6', '5'), vec![West, Stay]),
|
||||
(('6', '6'), vec![Stay]),
|
||||
(('6', '7'), vec![West, West, North, Stay]),
|
||||
(('6', '8'), vec![West, North, Stay]),
|
||||
(('6', '9'), vec![North, Stay]),
|
||||
|
||||
(('7', 'A'), vec![East, East, South, South, South, Stay]),
|
||||
(('7', '0'), vec![East, South, South, South, Stay]),
|
||||
(('7', '1'), vec![South, South, Stay]),
|
||||
(('7', '2'), vec![South, South, East, Stay]),
|
||||
(('7', '3'), vec![South, South, East, East, Stay]),
|
||||
(('7', '4'), vec![South, Stay]),
|
||||
(('7', '5'), vec![South, East, Stay]),
|
||||
(('7', '6'), vec![South, East, East, Stay]),
|
||||
(('7', '7'), vec![Stay]),
|
||||
(('7', '8'), vec![East, Stay]),
|
||||
(('7', '9'), vec![East, East, Stay]),
|
||||
|
||||
(('8', 'A'), vec![South, South, South, East, Stay]),
|
||||
(('8', '0'), vec![South, South, South, Stay]),
|
||||
(('8', '1'), vec![West, South, South, Stay]),
|
||||
(('8', '2'), vec![South, South, Stay]),
|
||||
(('8', '3'), vec![South, South, East, Stay]),
|
||||
(('8', '4'), vec![West, South, Stay]),
|
||||
(('8', '5'), vec![South, Stay]),
|
||||
(('8', '6'), vec![South, East, Stay]),
|
||||
(('8', '7'), vec![West, West, Stay]),
|
||||
(('8', '8'), vec![Stay]),
|
||||
(('8', '9'), vec![East, Stay]),
|
||||
|
||||
(('9', 'A'), vec![South, South, South, Stay]),
|
||||
(('9', '0'), vec![West, South, South, South, Stay]),
|
||||
(('9', '1'), vec![West, West, South, South, Stay]),
|
||||
(('9', '2'), vec![West, South, South, Stay]),
|
||||
(('9', '3'), vec![South, South, Stay]),
|
||||
(('9', '4'), vec![West, West, South, Stay]),
|
||||
(('9', '5'), vec![West, South, Stay]),
|
||||
(('9', '6'), vec![South, Stay]),
|
||||
(('9', '7'), vec![West, West, Stay]),
|
||||
(('9', '8'), vec![West, Stay]),
|
||||
(('9', '9'), vec![Stay]),
|
||||
]);
|
||||
|
||||
if depth == 0 {
|
||||
return 1;
|
||||
} else {
|
||||
let mut p = Stay;
|
||||
let mut len = 0;
|
||||
for d in &optimals[&(prev, next)] {
|
||||
len += length_calc(p, *d, depth - 1);
|
||||
p = *d;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
#[memoize]
|
||||
fn length_calc(prev: Dir, next: Dir, depth: i32) -> i64 {
|
||||
let optimals: HashMap<(Dir, Dir), Vec<Dir>> = HashMap::from([
|
||||
((Stay, Stay), vec![Stay]),
|
||||
((Stay, North), vec![West, Stay]),
|
||||
((Stay, East), vec![South, Stay]),
|
||||
((Stay, South), vec![West, South, Stay]),
|
||||
((Stay, West), vec![South, West, West, Stay]),
|
||||
|
||||
((North, Stay), vec![East, Stay]),
|
||||
((North, North), vec![Stay]),
|
||||
((North, South), vec![South, Stay]),
|
||||
((North, East), vec![South, East, Stay]),
|
||||
((North, West), vec![South, West, Stay]),
|
||||
|
||||
((South, Stay), vec![North, East, Stay]),
|
||||
((South, North), vec![North, Stay]),
|
||||
((South, South), vec![Stay]),
|
||||
((South, East), vec![East, Stay]),
|
||||
((South, West), vec![West, Stay]),
|
||||
|
||||
((East, Stay), vec![North, Stay]),
|
||||
((East, North), vec![West, North, Stay]),
|
||||
((East, South), vec![West, Stay]),
|
||||
((East, East), vec![Stay]),
|
||||
((East, West), vec![West, West, Stay]),
|
||||
|
||||
((West, Stay), vec![East, East, North, Stay]),
|
||||
((West, North), vec![East, North, Stay]),
|
||||
((West, South), vec![East, Stay]),
|
||||
((West, East), vec![East, East, Stay]),
|
||||
((West, West), vec![Stay]),
|
||||
]);
|
||||
|
||||
if depth == 0 {
|
||||
return 1;
|
||||
} else {
|
||||
let mut p = Stay;
|
||||
let mut len = 0;
|
||||
for d in &optimals[&(prev, next)] {
|
||||
len += length_calc(p, *d, depth - 1);
|
||||
p = *d;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn expandaband(sequence: Vec<Dir>, optimals: &HashMap<(Dir, Dir), Vec<Dir>>) -> Vec<Dir> {
|
||||
let mut output = vec![];
|
||||
let mut prev = Stay;
|
||||
for dir in sequence {
|
||||
output.extend(optimals.get(&(prev, dir)).unwrap());
|
||||
prev = dir;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
fn thru_keypads(code: &str, keypads: i32) -> Vec<Dir> {
|
||||
let keypad_door: HashMap<char, Coord> = HashMap::from([
|
||||
('7', (0,0)), ('8', (1,0)), ('9', (2,0)),
|
||||
('4', (0,1)), ('5', (1,1)), ('6', (2,1)),
|
||||
('1', (0,2)), ('2', (1,2)), ('3', (2,2)),
|
||||
('0', (1,3)), ('A', (2,3)),
|
||||
]);
|
||||
let mut prev = 'A';
|
||||
let mut output = vec![];
|
||||
for c in code.chars() {
|
||||
//println!("navigating from {prev} to {c}");
|
||||
let shortest = shortest_seq(
|
||||
keypad_door[&prev],
|
||||
keypad_door[&c],
|
||||
keypads-1,
|
||||
vec![(0,3)]);
|
||||
output.extend(shortest);
|
||||
prev = c;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
#[memoize]
|
||||
fn shortest_seq(
|
||||
start: Coord,
|
||||
end: Coord,
|
||||
keypads: i32,
|
||||
blacklist: Vec<Coord>,
|
||||
) -> Vec<Dir> {
|
||||
// starting at start what is the shortest sequence to navigate to and press end,
|
||||
// through many keypads?
|
||||
let keypad: HashMap<Dir, Coord> = HashMap::from([
|
||||
(North, (1,0)), (Stay, (2,0)),
|
||||
(West, (0,1)), (South, (1,1)), (East, (2,1)),
|
||||
]);
|
||||
|
||||
let paths: Vec<_> = all_paths(start, end)
|
||||
.into_iter()
|
||||
.filter(|p| traversal_avoids(start, p, &blacklist))
|
||||
.collect();
|
||||
//println!("with {keypads} left");
|
||||
|
||||
if keypads == 1 {
|
||||
let mut output = vec![];
|
||||
output.extend(paths[0].clone());
|
||||
output.push(Stay);
|
||||
return output;
|
||||
} else {
|
||||
let mut next_keypad_paths = vec![];
|
||||
for path in paths {
|
||||
let mut longer = vec![];
|
||||
let mut prev = keypad[&Stay];
|
||||
for dir in path {
|
||||
longer.extend(
|
||||
shortest_seq(
|
||||
prev,
|
||||
keypad[&dir],
|
||||
keypads-1,
|
||||
vec![(0,0)]
|
||||
)
|
||||
);
|
||||
prev = keypad[&dir];
|
||||
}
|
||||
longer.extend(
|
||||
shortest_seq(
|
||||
prev,
|
||||
keypad[&Stay],
|
||||
keypads-1,
|
||||
vec![(0,0)]
|
||||
)
|
||||
);
|
||||
next_keypad_paths.push(longer);
|
||||
}
|
||||
let mut shortest = &next_keypad_paths[0];
|
||||
for path in &next_keypad_paths {
|
||||
if path.len() < shortest.len() {
|
||||
shortest = path;
|
||||
}
|
||||
}
|
||||
return shortest.to_vec();
|
||||
}
|
||||
}
|
||||
|
||||
fn traversal_avoids(start: Coord, path: &Vec<Dir>, blacklist: &Vec<Coord>) -> bool {
|
||||
let mut here = start;
|
||||
let mut hit = blacklist.contains(&here);
|
||||
for d in path {
|
||||
here = step(&here, *d, 1);
|
||||
hit = hit || blacklist.contains(&here);
|
||||
}
|
||||
return !hit;
|
||||
}
|
||||
|
||||
fn all_paths(prev: Coord, next: Coord) -> Vec<Vec<Dir>> {
|
||||
let mut out = vec![];
|
||||
|
||||
match (next.0-prev.0, next.1-prev.1) {
|
||||
(0, 0) => out.push(vec![]),
|
||||
(mut x, 0) => {
|
||||
let mut horizontal = vec![];
|
||||
while x > 0 { horizontal.push(East); x-=1; }
|
||||
while x < 0 { horizontal.push(West); x+=1; }
|
||||
out.push(horizontal);
|
||||
},
|
||||
(0, mut y) => {
|
||||
let mut vertical = vec![];
|
||||
while y > 0 { vertical.push(South); y-=1; }
|
||||
while y < 0 { vertical.push(North); y+=1; }
|
||||
out.push(vertical);
|
||||
},
|
||||
(_x, _y) => {
|
||||
for p1 in all_paths(prev, (next.0, prev.1)) {
|
||||
for p2 in all_paths((next.0, prev.1), next) {
|
||||
let mut p12 = vec![];
|
||||
p12.extend(p1.clone());
|
||||
p12.extend(p2);
|
||||
out.push(p12);
|
||||
}
|
||||
}
|
||||
for p1 in all_paths(prev, (prev.0, next.1)) {
|
||||
for p2 in all_paths((prev.0, next.1), next) {
|
||||
let mut p12 = vec![];
|
||||
p12.extend(p1.clone());
|
||||
p12.extend(p2);
|
||||
out.push(p12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
fn expand<T: std::cmp::Eq + std::hash::Hash>(
|
||||
sequence: &Vec<T>,
|
||||
map: &HashMap<Coord, T>,
|
||||
keypad: &HashMap<T, Coord>,
|
||||
start: T,
|
||||
seed: &mut u128
|
||||
) -> Vec<Dir> {
|
||||
let mut here = keypad[&start];
|
||||
let mut output = Vec::new();
|
||||
for t in sequence {
|
||||
let there = keypad[&t];
|
||||
let diff = (there.0 - here.0, there.1 - here.1);
|
||||
|
||||
output.extend(build_path(diff, seed));
|
||||
|
||||
here = there;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
fn build_path(diff: Coord, seed: &mut u128) -> Vec<Dir> {
|
||||
let mut output = vec![];
|
||||
match diff {
|
||||
(0, 0) => output.push(Stay),
|
||||
(x, 0) => {
|
||||
for _ in 0..x.abs() {
|
||||
if x < 0 { output.push(West); }
|
||||
if x > 0 { output.push(East); }
|
||||
}
|
||||
output.push(Stay);
|
||||
},
|
||||
(0, y) => {
|
||||
for _ in 0..y.abs() {
|
||||
if y < 0 { output.push(North); }
|
||||
if y > 0 { output.push(South); }
|
||||
}
|
||||
output.push(Stay);
|
||||
},
|
||||
(x, y) => {
|
||||
if *seed & 1 == 0 {
|
||||
for _ in 0..y.abs() {
|
||||
if y < 0 { output.push(North); }
|
||||
if y > 0 { output.push(South); }
|
||||
}
|
||||
for _ in 0..x.abs() {
|
||||
if x < 0 { output.push(West); }
|
||||
if x > 0 { output.push(East); }
|
||||
}
|
||||
} else {
|
||||
for _ in 0..x.abs() {
|
||||
if x < 0 { output.push(West); }
|
||||
if x > 0 { output.push(East); }
|
||||
}
|
||||
for _ in 0..y.abs() {
|
||||
if y < 0 { output.push(North); }
|
||||
if y > 0 { output.push(South); }
|
||||
}
|
||||
}
|
||||
output.push(Stay);
|
||||
*seed = *seed >> 1;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn sequences<T>(options: Vec<Vec<(Dir, i32)>>, map: &HashMap<Coord, T>, start: Coord) -> Vec<Vec<Dir>> {
|
||||
let mut out: Vec<(Vec<Dir>, Coord, Dir)> = vec![(vec![], start, Stay)];
|
||||
|
||||
@ -278,8 +803,4 @@ fn execute_code<T: Clone + Copy>(
|
||||
}
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
6
day23/Cargo.toml
Normal file
6
day23/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "day23"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
124
day23/src/main.rs
Normal file
124
day23/src/main.rs
Normal file
@ -0,0 +1,124 @@
|
||||
use std::collections::HashSet;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, AoC day 23!");
|
||||
|
||||
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 file = fs::read_to_string(file_path)
|
||||
.expect("should be able to read the file");
|
||||
|
||||
println!("building adjacency matrix");
|
||||
let mut adjacency = HashMap::new();
|
||||
let mut edges = HashSet::new();
|
||||
for line in file.lines() {
|
||||
let (a, b) = line.split_once("-").expect("badly formatted line");
|
||||
|
||||
let a_edges = adjacency.entry(a).or_insert(vec![]);
|
||||
a_edges.push(b);
|
||||
let b_edges = adjacency.entry(b).or_insert(vec![]);
|
||||
b_edges.push(a);
|
||||
|
||||
edges.insert((a,b));
|
||||
edges.insert((b,a));
|
||||
}
|
||||
|
||||
println!("sorting edges");
|
||||
for (_, edges) in adjacency.iter_mut() {
|
||||
edges.sort();
|
||||
}
|
||||
|
||||
// part a
|
||||
|
||||
println!("looking for 3-cliques");
|
||||
let mut cliques = HashSet::new();
|
||||
for (&a, a_connections) in &adjacency {
|
||||
for &b in a_connections {
|
||||
for &c in adjacency.get(b).unwrap() {
|
||||
if edges.contains(&(a,c)) {
|
||||
let mut clique = vec![a, b, c];
|
||||
clique.sort();
|
||||
cliques.insert(clique);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut sorted_cliques = cliques.iter().collect::<Vec<_>>();
|
||||
sorted_cliques.sort();
|
||||
let mut count_t = 0;
|
||||
for c in sorted_cliques {
|
||||
//println!("{},{},{}", c[0], c[1], c[2]);
|
||||
let mut found = false;
|
||||
for computer in c {
|
||||
if computer.starts_with("t") {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if found {
|
||||
count_t += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!("found {count_t} cliques with a computer with t in the name");
|
||||
|
||||
// part b
|
||||
let mut done = false;
|
||||
while !done {
|
||||
done = true;
|
||||
let mut new_cliques = HashSet::new();
|
||||
|
||||
for old_clique in cliques.iter() {
|
||||
let mut computers = old_clique.clone();
|
||||
let me = computers[0];
|
||||
for you in adjacency.get(me).unwrap() {
|
||||
if computers.contains(you) {
|
||||
continue;
|
||||
}
|
||||
let mut accepted = true;
|
||||
for them in &computers {
|
||||
if *them == me {
|
||||
continue;
|
||||
} else if !edges.contains(&(you, *them)) {
|
||||
accepted = false;
|
||||
}
|
||||
}
|
||||
// grow the clique iff 'you' is connected to all the members of the clique
|
||||
if accepted {
|
||||
done = false;
|
||||
computers.push(you);
|
||||
break;
|
||||
}
|
||||
}
|
||||
computers.sort();
|
||||
new_cliques.insert(computers);
|
||||
}
|
||||
|
||||
cliques = new_cliques;
|
||||
}
|
||||
|
||||
let mut clique_size = 0;
|
||||
for clique in &cliques {
|
||||
// for comp in clique { print!("{comp},"); }
|
||||
// print!("\n");
|
||||
clique_size = clique_size.max(clique.len());
|
||||
}
|
||||
println!("the largest clique is {clique_size} computers");
|
||||
|
||||
for clique in &cliques {
|
||||
if clique.len() == clique_size {
|
||||
for comp in clique { print!("{comp},"); }
|
||||
print!("\n");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user