i do not understand day 20
i mean 21
This commit is contained in:
parent
d6e487d400
commit
12bdd65215
@ -1,8 +1,23 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use regex::Regex;
|
use crate::Dir::{North, South, East, West };
|
||||||
|
|
||||||
|
|
||||||
|
type Coord = (i32, i32);
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
|
||||||
|
enum Dir { North, South, East, West }
|
||||||
|
|
||||||
|
fn step(start: &Coord, d: Dir, steps: i32) -> Coord {
|
||||||
|
match d {
|
||||||
|
North => (start.0, start.1 - steps),
|
||||||
|
South => (start.0, start.1 + steps),
|
||||||
|
East => (start.0 + steps, start.1),
|
||||||
|
West => (start.0 - steps, start.1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, AoC day 13!");
|
println!("Hello, AoC day 13!");
|
||||||
@ -18,109 +33,69 @@ fn main() {
|
|||||||
let binding = fs::read_to_string(file_path)
|
let binding = fs::read_to_string(file_path)
|
||||||
.expect("should be able to read the file");
|
.expect("should be able to read the file");
|
||||||
|
|
||||||
let (towels, designs) = binding.split_once("\n\n").expect("should have two sections");
|
let mut map = HashMap::new();
|
||||||
|
let mut distances_to_end: HashMap<Coord, i32> = HashMap::new();
|
||||||
|
|
||||||
let all_towels: Vec<&str> = towels.split(", ").collect();
|
let mut start = (0,0);
|
||||||
|
let mut exit = (0,0);
|
||||||
let re = Regex::new(
|
let mut y = 0;
|
||||||
&format!("^({})+$", all_towels.join("|"))
|
for line in binding.lines() {
|
||||||
).expect("making the regex");
|
let mut x = 0;
|
||||||
|
for c in line.chars() {
|
||||||
let mut count = 0;
|
match c {
|
||||||
for line in designs.lines() {
|
'S' => { start = (x,y); map.insert((x,y), '.'); },
|
||||||
if re.is_match(line) {
|
'E' => { exit = (x,y); map.insert((x,y), '.'); },
|
||||||
count += 1;
|
_ => { map.insert((x,y), c); }
|
||||||
|
};
|
||||||
|
x += 1;
|
||||||
}
|
}
|
||||||
|
y += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("found {count} valid designs");
|
distances_to_end.insert(exit, 0);
|
||||||
|
let visited: HashSet<Coord> = HashSet::new();
|
||||||
let mut tree = build_tree(&all_towels);
|
let mut wavefront: Vec<Coord> = vec![exit];
|
||||||
|
while let Some(here) = wavefront.pop() {
|
||||||
//println!("{tree:?}");
|
let here_distance = distances_to_end.get(&here).unwrap().clone();
|
||||||
println!("{} nodes in the tree", tree.len());
|
for x in neighbors(&here) {
|
||||||
|
if map.get(&x) != Some(&'.') {
|
||||||
let mut count = 0;
|
continue;
|
||||||
|
}
|
||||||
for line in designs.lines() {
|
if visited.contains(&x) {
|
||||||
count += eat(&mut tree, line);
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(d) = distances_to_end.get(&x) {
|
||||||
|
if *d < here_distance {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
distances_to_end.insert(x, here_distance + 1);
|
||||||
|
wavefront.push(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("found {count} solutions total");
|
}
|
||||||
|
|
||||||
|
println!("the distance from {start:?} to {exit:?} is {}", distances_to_end.get(&start).unwrap());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat(tree: &mut Vec<TreeCell>, haystack: &str) -> u128 {
|
fn second_neighbors(start: &Coord) -> Vec<Coord> {
|
||||||
let mut heads: HashMap<usize, u128> = HashMap::new();
|
vec![
|
||||||
heads.insert(0, 1);
|
step(start, North, 2),
|
||||||
|
step(&step(start, North, 1), West, 1),
|
||||||
//println!("examining {haystack}");
|
step(&step(start, North, 1), East, 1),
|
||||||
|
step(start, West, 2),
|
||||||
for c in haystack.chars() {
|
step(start, East, 2),
|
||||||
// iterating by character
|
step(&step(start, West, 1), South, 1),
|
||||||
let mut new_heads = HashMap::new();
|
step(&step(start, East, 1), South, 1),
|
||||||
|
step(start, South, 2)
|
||||||
//println!("looking at {c}; the heads we're tracking are {heads:?}");
|
]
|
||||||
|
|
||||||
// this first loop branches to the start from valid states
|
|
||||||
for (node_idx, num_heads) in heads.drain() {
|
|
||||||
let TreeCell { next: _, valid } = &tree[node_idx];
|
|
||||||
if *valid {
|
|
||||||
let next_idx = 0;
|
|
||||||
let existing_heads = new_heads.get(&next_idx).unwrap_or(&0);
|
|
||||||
new_heads.insert(next_idx, existing_heads + num_heads);
|
|
||||||
}
|
|
||||||
let existing_heads = new_heads.get(&node_idx).unwrap_or(&0);
|
|
||||||
new_heads.insert(node_idx, existing_heads + num_heads);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this second loop advances all the heads
|
|
||||||
for (node_idx, num_heads) in new_heads.drain() {
|
|
||||||
let TreeCell { next, valid: _ } = &tree[node_idx];
|
|
||||||
if let Some(next_idx) = next.get(&c) {
|
|
||||||
heads.insert(*next_idx, num_heads);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
for (node_idx, number) in heads {
|
|
||||||
if tree[node_idx].valid { count += number; }
|
|
||||||
}
|
|
||||||
//println!("there are {count} heads in success states");
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
fn neighbors(start: &Coord) -> Vec<Coord> {
|
||||||
|
vec![
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
step(start, North, 1),
|
||||||
struct TreeCell {next: HashMap<char, usize>, valid: bool}
|
step(start, West, 1),
|
||||||
|
step(start, East, 1),
|
||||||
fn build_tree(patterns: &[&str]) -> Vec<TreeCell> {
|
step(start, South, 1)
|
||||||
let mut cells = vec![TreeCell {next: HashMap::new(), valid: false}];
|
]
|
||||||
|
|
||||||
for stripes in patterns {
|
|
||||||
add_to_tree(stripes, &mut cells, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cells;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_to_tree(pattern: &str, tree: &mut Vec<TreeCell>, index: usize) {
|
|
||||||
match pattern.chars().next() {
|
|
||||||
None => tree[index].valid = true,
|
|
||||||
Some(c) => {
|
|
||||||
if tree[index].next.contains_key(&c) {
|
|
||||||
add_to_tree(&pattern[1..], tree, *tree[index].next.get(&c).unwrap());
|
|
||||||
} else {
|
|
||||||
let new_index = tree.len();
|
|
||||||
let new_treecell = TreeCell { next: HashMap::new(), valid: false };
|
|
||||||
tree.push(new_treecell); // now this is at new_index
|
|
||||||
tree[index].next.insert(c, new_index);
|
|
||||||
|
|
||||||
add_to_tree(&pattern[1..], tree, new_index);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
6
day20/Cargo.toml
Normal file
6
day20/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "day20"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
183
day20/src/main.rs
Normal file
183
day20/src/main.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use crate::Dir::{North, South, East, West };
|
||||||
|
|
||||||
|
|
||||||
|
type Coord = (i32, i32);
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
|
||||||
|
enum Dir { North, South, East, West }
|
||||||
|
|
||||||
|
fn step(start: &Coord, d: Dir, steps: i32) -> Coord {
|
||||||
|
match d {
|
||||||
|
North => (start.0, start.1 - steps),
|
||||||
|
South => (start.0, start.1 + steps),
|
||||||
|
East => (start.0 + steps, start.1),
|
||||||
|
West => (start.0 - steps, start.1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 map = HashMap::new();
|
||||||
|
|
||||||
|
let mut start = (0,0);
|
||||||
|
let mut exit = (0,0);
|
||||||
|
let mut y = 0;
|
||||||
|
for line in binding.lines() {
|
||||||
|
let mut x = 0;
|
||||||
|
for c in line.chars() {
|
||||||
|
match c {
|
||||||
|
'S' => { start = (x,y); map.insert((x,y), '.'); },
|
||||||
|
'E' => { exit = (x,y); map.insert((x,y), '.'); },
|
||||||
|
_ => { map.insert((x,y), c); }
|
||||||
|
};
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut distances_to_end: HashMap<Coord, i32> = HashMap::new();
|
||||||
|
distances_to_end.insert(exit, 0);
|
||||||
|
let mut visited: HashSet<Coord> = HashSet::new();
|
||||||
|
let mut wavefront: Vec<Coord> = vec![exit];
|
||||||
|
while let Some(here) = wavefront.pop() {
|
||||||
|
let here_distance = distances_to_end.get(&here).unwrap().clone();
|
||||||
|
for x in neighbors(&here) {
|
||||||
|
if map.get(&x) != Some(&'.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if visited.contains(&x) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(d) = distances_to_end.get(&x) {
|
||||||
|
if *d < here_distance {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
distances_to_end.insert(x, here_distance + 1);
|
||||||
|
wavefront.push(x);
|
||||||
|
}
|
||||||
|
visited.insert(here);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("the distance from {start:?} to {exit:?} is {}", distances_to_end.get(&start).unwrap());
|
||||||
|
|
||||||
|
let mut cheats: HashMap<(Coord, Coord), i32> = HashMap::new();
|
||||||
|
|
||||||
|
for (here, distance) in &distances_to_end {
|
||||||
|
for there in second_neighbors(&here) {
|
||||||
|
if let Some(next_distance) = distances_to_end.get(&there) {
|
||||||
|
cheats.insert((*here, there), distance-next_distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut counts: HashMap<i32, i32> = HashMap::new();
|
||||||
|
|
||||||
|
for (_, advantage) in cheats {
|
||||||
|
counts.insert(advantage, counts.get(&advantage).unwrap_or(&0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for (x, c) in counts {
|
||||||
|
if x > 100 {
|
||||||
|
count += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("there were {count} cheats worth more than 100");
|
||||||
|
|
||||||
|
// part b
|
||||||
|
|
||||||
|
let mut cheats: HashMap<(Coord, Coord), i32> = HashMap::new();
|
||||||
|
|
||||||
|
for (here, distance) in &distances_to_end {
|
||||||
|
for there in twenty_step_neighbors(&here) {
|
||||||
|
if let Some(next_distance) = distances_to_end.get(&there) {
|
||||||
|
let cheat_length = (here.0 - there.0).abs() + (here.1 - there.1).abs();
|
||||||
|
cheats.insert((*here, there), distance-next_distance - cheat_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut counts: HashMap<i32, i32> = HashMap::new();
|
||||||
|
|
||||||
|
for (_, advantage) in cheats {
|
||||||
|
counts.insert(advantage, counts.get(&advantage).unwrap_or(&0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for (x, c) in counts {
|
||||||
|
if x >= 100 {
|
||||||
|
count += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("there were {count} cheats worth more than 100");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_cheat_offsets() -> Vec<Coord> {
|
||||||
|
let mut all = vec![(0,0)];
|
||||||
|
|
||||||
|
for _ in 0..20 {
|
||||||
|
all = all.into_iter().flat_map(|x| neighbors(&x)).collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return all
|
||||||
|
}
|
||||||
|
|
||||||
|
fn offset_neighbors(start: &Coord, offsets: &Vec<Coord>) -> Vec<Coord> {
|
||||||
|
let mut v: Vec<Coord> = offsets.clone();
|
||||||
|
for x in v.iter_mut() {
|
||||||
|
x.0 = x.0 + start.0;
|
||||||
|
x.1 = x.1 + start.1;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn twenty_step_neighbors(start: &Coord) -> Vec<Coord> {
|
||||||
|
let mut v: Vec<Coord> = Vec::with_capacity(400);
|
||||||
|
for x in -20_i32..21 {
|
||||||
|
for y in -20_i32..21 {
|
||||||
|
if x.abs()+y.abs() <= 20 {
|
||||||
|
v.push(step(&step(start, North, y), East, x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
fn second_neighbors(start: &Coord) -> Vec<Coord> {
|
||||||
|
vec![
|
||||||
|
step(start, North, 2),
|
||||||
|
step(&step(start, North, 1), West, 1),
|
||||||
|
step(&step(start, North, 1), East, 1),
|
||||||
|
step(start, West, 2),
|
||||||
|
step(start, East, 2),
|
||||||
|
step(&step(start, West, 1), South, 1),
|
||||||
|
step(&step(start, East, 1), South, 1),
|
||||||
|
step(start, South, 2)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
fn neighbors(start: &Coord) -> Vec<Coord> {
|
||||||
|
vec![
|
||||||
|
step(start, North, 1),
|
||||||
|
step(start, West, 1),
|
||||||
|
step(start, East, 1),
|
||||||
|
step(start, South, 1)
|
||||||
|
]
|
||||||
|
}
|
6
day21/Cargo.toml
Normal file
6
day21/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
349
day21/src/main.rs
Normal file
349
day21/src/main.rs
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use crate::Dir::{North, South, East, West, Stay };
|
||||||
|
|
||||||
|
|
||||||
|
type Coord = (i32, i32);
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
|
||||||
|
enum Dir { North, South, East, West, Stay }
|
||||||
|
|
||||||
|
fn step(start: &Coord, d: Dir, steps: i32) -> Coord {
|
||||||
|
match d {
|
||||||
|
North => (start.0, start.1 - steps),
|
||||||
|
South => (start.0, start.1 + steps),
|
||||||
|
East => (start.0 + steps, start.1),
|
||||||
|
West => (start.0 - steps, start.1),
|
||||||
|
Stay => *start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_path(start: &Coord, path: &[Dir]) -> Coord {
|
||||||
|
let mut here = *start;
|
||||||
|
for d in path {
|
||||||
|
here = step(&here, *d, 1);
|
||||||
|
}
|
||||||
|
return here;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, AoC day 21!");
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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 door_map: HashMap<Coord, char> = HashMap::new();
|
||||||
|
for (key, loc) in &keypad_door { door_map.insert(*loc, *key); }
|
||||||
|
let mut directions_matrix: HashMap<(Coord, Coord), Vec<(Dir, i32)>> = HashMap::new();
|
||||||
|
for (_this, here) in &keypad_door {
|
||||||
|
for (_other, there) in &keypad_door {
|
||||||
|
let mut v = vec![];
|
||||||
|
if there.0 > here.0 {
|
||||||
|
v.push((East, there.0 - here.0));
|
||||||
|
}
|
||||||
|
if there.0 < here.0 {
|
||||||
|
v.push((West, here.0 - there.0));
|
||||||
|
}
|
||||||
|
if there.1 > here.1 {
|
||||||
|
v.push((South, there.1 - here.1));
|
||||||
|
}
|
||||||
|
if there.1 < here.1 {
|
||||||
|
v.push((North, here.1 - there.1));
|
||||||
|
}
|
||||||
|
if there == here {
|
||||||
|
v.push((Stay, 0));
|
||||||
|
}
|
||||||
|
directions_matrix.insert((*here, *there), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let keypad_arrows: HashMap<Dir, Coord> = HashMap::from([
|
||||||
|
(North, (1,0)), (Stay, (2,0)),
|
||||||
|
(West, (0,1)), (South, (1,1)), (East, (2,1)),
|
||||||
|
]);
|
||||||
|
let mut keypad_map: HashMap<Coord, Dir> = HashMap::new();
|
||||||
|
for (key, loc) in &keypad_arrows { keypad_map.insert(*loc, *key); }
|
||||||
|
let mut keypad_directions_matrix = HashMap::new();
|
||||||
|
for (_this, here) in &keypad_arrows {
|
||||||
|
for (_other, there) in &keypad_arrows {
|
||||||
|
let mut v = vec![];
|
||||||
|
if there.0 > here.0 {
|
||||||
|
v.push((East, there.0 - here.0));
|
||||||
|
}
|
||||||
|
if there.0 < here.0 {
|
||||||
|
v.push((West, here.0 - there.0));
|
||||||
|
}
|
||||||
|
if there.1 > here.1 {
|
||||||
|
v.push((South, there.1 - here.1));
|
||||||
|
}
|
||||||
|
if there.1 < here.1 {
|
||||||
|
v.push((North, here.1 - there.1));
|
||||||
|
}
|
||||||
|
if there == here {
|
||||||
|
v.push((Stay, 0));
|
||||||
|
}
|
||||||
|
keypad_directions_matrix.insert((*here, *there), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sum = 0;
|
||||||
|
for line in file.lines() {
|
||||||
|
let door_code: Vec<char> = line.chars().collect();
|
||||||
|
let num: i32 = line[..line.len()-1].parse().expect("failed to parse door code as number");
|
||||||
|
let mut complexity: i64 = 100000000000;
|
||||||
|
|
||||||
|
for x in &door_code {
|
||||||
|
print!("{}", x);
|
||||||
|
}
|
||||||
|
print!("\n");
|
||||||
|
|
||||||
|
let options_door = build_options(
|
||||||
|
&directions_matrix,
|
||||||
|
&keypad_door,
|
||||||
|
&door_code,
|
||||||
|
'A');
|
||||||
|
for arrow_code_1 in shortest_sequences(options_door, &door_map, keypad_door[&'A']) {
|
||||||
|
print_code(&arrow_code_1);
|
||||||
|
|
||||||
|
let options_arrow_1 = build_options(
|
||||||
|
&keypad_directions_matrix,
|
||||||
|
&keypad_arrows,
|
||||||
|
&arrow_code_1,
|
||||||
|
Stay);
|
||||||
|
for arrow_code_2 in shortest_sequences(options_arrow_1, &keypad_map, keypad_arrows[&Stay]) {
|
||||||
|
print_code(&arrow_code_2);
|
||||||
|
|
||||||
|
let options_arrow_2 = build_options(
|
||||||
|
&keypad_directions_matrix,
|
||||||
|
&keypad_arrows,
|
||||||
|
&arrow_code_2,
|
||||||
|
Stay);
|
||||||
|
for arrow_code_3 in shortest_sequences(options_arrow_2, &keypad_map, keypad_arrows[&Stay]) {
|
||||||
|
complexity = complexity.min(arrow_code_3.len() as i64);
|
||||||
|
print_code(&arrow_code_3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("shortest sequence is {} long", complexity);
|
||||||
|
sum += complexity * (num as i64);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("the sum of the complexity scores is {}", sum);
|
||||||
|
|
||||||
|
// println!("printing out the anomalous code");
|
||||||
|
|
||||||
|
// let code = "<<vAA>A>^AAvA<^A>AvA^A<<vA>>^AAvA^A<vA>^AA<A>A<<vA>A>^AAAvA<^A>A";
|
||||||
|
// let code_dirs = code.chars().map(|x| match x {
|
||||||
|
// '<' => West, '>' => East, '^' => North, 'v' => South, 'A' => Stay, _ => panic!()
|
||||||
|
// }).collect();
|
||||||
|
// print_code(&code_dirs);
|
||||||
|
// println!("resulting keypresses:");
|
||||||
|
// let code_2 = execute_code(&code_dirs, &keypad_map, keypad_arrows[&Stay]);
|
||||||
|
// print_code(&code_2);
|
||||||
|
// println!("resulting keypresses:");
|
||||||
|
// let code_3 = execute_code(&code_2, &keypad_map, keypad_arrows[&Stay]);
|
||||||
|
// print_code(&code_3);
|
||||||
|
// println!("resulting in:");
|
||||||
|
// let code_4 = execute_code(&code_3, &door_map, keypad_door[&'A']);
|
||||||
|
// print_code_door(&code_4);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_sequence<T>(options: Vec<Vec<(Dir, i32)>>, map: &HashMap<Coord, T>, start: Coord) -> Vec<Dir> {
|
||||||
|
let mut out = vec![];
|
||||||
|
let mut here = start;
|
||||||
|
|
||||||
|
for choices in options {
|
||||||
|
if choices.len() == 1 {
|
||||||
|
let (direction, times) = choices[0];
|
||||||
|
for _ in 0..times {
|
||||||
|
out.push(direction);
|
||||||
|
}
|
||||||
|
here = step(&here, direction, times)
|
||||||
|
} else if choices.len() == 2 {
|
||||||
|
let (d1, t1) = choices[0];
|
||||||
|
let (d2, t2) = choices[1];
|
||||||
|
if map.contains_key(&step(&here, d1, t1)) {
|
||||||
|
for _ in 0..t1 {
|
||||||
|
out.push(d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..t2 {
|
||||||
|
out.push(d2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _ in 0..t2 {
|
||||||
|
out.push(d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..t1 {
|
||||||
|
out.push(d1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
fn sequences<T>(options: Vec<Vec<(Dir, i32)>>, map: &HashMap<Coord, T>, start: Coord) -> Vec<Vec<Dir>> {
|
||||||
|
let mut out: Vec<(Vec<Dir>, Coord)> = vec![(vec![], start)];
|
||||||
|
|
||||||
|
for choices in options {
|
||||||
|
let mut new_out = vec![];
|
||||||
|
|
||||||
|
if choices.len() == 1 {
|
||||||
|
let (direction, times) = choices[0];
|
||||||
|
for (mut walk, mut here) in out {
|
||||||
|
for _ in 0..times {
|
||||||
|
walk.push(direction);
|
||||||
|
here = step(&here, direction, 1);
|
||||||
|
}
|
||||||
|
new_out.push((walk, here));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if choices.len() == 2 {
|
||||||
|
let (d1, t1) = choices[0];
|
||||||
|
let (d2, t2) = choices[1];
|
||||||
|
|
||||||
|
for (ref walk, here) in &mut out {
|
||||||
|
let end = step(&step(&here, d1, t1), d2, t2);
|
||||||
|
let candidate_here = step(&here, d1, t1);
|
||||||
|
if map.contains_key(&candidate_here) {
|
||||||
|
let mut ab_walk = walk.clone();
|
||||||
|
|
||||||
|
for _ in 0..t1 { ab_walk.push(d1); }
|
||||||
|
for _ in 0..t2 { ab_walk.push(d2); }
|
||||||
|
|
||||||
|
new_out.push((ab_walk, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
let candidate_there = step(&here, d2, t2);
|
||||||
|
if map.contains_key(&candidate_there) {
|
||||||
|
let mut ba_walk = walk.clone();
|
||||||
|
|
||||||
|
for _ in 0..t2 { ba_walk.push(d2); }
|
||||||
|
for _ in 0..t1 { ba_walk.push(d1); }
|
||||||
|
|
||||||
|
new_out.push((ba_walk, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("encountered a bad set of choices");
|
||||||
|
}
|
||||||
|
|
||||||
|
out = new_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut final_out = vec![];
|
||||||
|
for (walk, _) in out {
|
||||||
|
final_out.push(walk);
|
||||||
|
}
|
||||||
|
return final_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shortest_sequences<T>(
|
||||||
|
options: Vec<Vec<(Dir, i32)>>,
|
||||||
|
map: &HashMap<Coord, T>,
|
||||||
|
start: Coord
|
||||||
|
) -> Vec<Vec<Dir>> {
|
||||||
|
let mut short_length = None;
|
||||||
|
let mut shorts = vec![];
|
||||||
|
|
||||||
|
for seq in sequences(options.to_vec(), map, start) {
|
||||||
|
let my_len = seq.len();
|
||||||
|
if let Some(len) = short_length {
|
||||||
|
if my_len == len {
|
||||||
|
shorts.push(seq);
|
||||||
|
} else if my_len < len {
|
||||||
|
shorts = vec![seq];
|
||||||
|
short_length = Some(my_len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
short_length = Some(my_len);
|
||||||
|
shorts.push(seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_options<T: std::hash::Hash + std::cmp::Eq>(
|
||||||
|
routes: &HashMap<(Coord, Coord), Vec<(Dir, i32)>>,
|
||||||
|
map: &HashMap<T, Coord>,
|
||||||
|
sequence: &Vec<T>,
|
||||||
|
start: T,
|
||||||
|
) -> Vec<Vec<(Dir, i32)>> {
|
||||||
|
let mut here = map[&start];
|
||||||
|
let mut options: Vec<Vec<(Dir, i32)>> = Vec::new();
|
||||||
|
for button in sequence {
|
||||||
|
let there = map[&button];
|
||||||
|
options.push(routes[&(here, there)].clone());
|
||||||
|
options.push(vec![(Stay, 1)]);
|
||||||
|
here = there;
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn print_code(code: &Vec<Dir>) {
|
||||||
|
for x in code {
|
||||||
|
print!("{}", match x {
|
||||||
|
North => '^', South => 'v', East => '>', West => '<', Stay => 'A'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
print!("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_code_door(code: &Vec<char>) {
|
||||||
|
for x in code {
|
||||||
|
print!("{}", x);
|
||||||
|
}
|
||||||
|
print!("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn execute_code<T: Clone + Copy>(
|
||||||
|
code: &Vec<Dir>,
|
||||||
|
map: &HashMap<Coord, T>,
|
||||||
|
start: Coord
|
||||||
|
) -> Vec<T> {
|
||||||
|
|
||||||
|
let mut out = vec![];
|
||||||
|
let mut here = start;
|
||||||
|
for d in code {
|
||||||
|
if *d == Stay {
|
||||||
|
out.push(map[&here]);
|
||||||
|
} else {
|
||||||
|
here = step(&here, *d, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user