Compare commits
9 Commits
1686c8a28c
...
79ea3c29d0
| Author | SHA1 | Date | |
|---|---|---|---|
| 79ea3c29d0 | |||
| e87d31c941 | |||
| 6e06599c33 | |||
| 3b829649f3 | |||
| 922f2a483c | |||
| 4002297ede | |||
| 9a34cca688 | |||
| 358e185501 | |||
| eeda13a0d6 |
109
input/day20.txt
Normal file
109
input/day20.txt
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
V W A S Q A K
|
||||||
|
D V A H R Y N
|
||||||
|
#################################.#########.###.#.###.#########.#####.#################################
|
||||||
|
#...........#.#...#...#.#...#...........#.....#.....#.........#.....#...............#.......#.........#
|
||||||
|
#.###.#.###.#.###.#.###.###.###.#.#.#####.###.#####.#######.#######.#######.#########.#.#####.#.#####.#
|
||||||
|
#.#...#.#.#...#...#...#.#.......#.#...#.....#.#.....#.......#.....#.#.#...#.#...#.#.#.#.#.#.#.#...#...#
|
||||||
|
#########.#.#####.#.###.###.#.#####.###.#.#######.###.#.#####.###.#.#.#.#.#.#.###.#.###.#.#.###.#####.#
|
||||||
|
#...#...#...#.#.#.....#.....#.....#...#.#.....#.....#.#...#.#...#.#.#...#...#.#...............#.#.#.#.#
|
||||||
|
#.#.###.###.#.#.#.#####.###.#.#.#######.#######.#####.#####.#.#.#.#.#.#######.#.#######.###.#.#.#.#.###
|
||||||
|
#.#.......................#.#.#...#.....#...#.....#.......#...#.#...#.............#.#.....#.#.#.....#.#
|
||||||
|
#.###.#####.#####.#####.#####.#########.#.###.###.###.#.#######.###########.###.###.###.#.#####.###.#.#
|
||||||
|
#.#...#.....#.#...#.....#.#...#...#.......#...#...#.#.#...#.#...#...#.....#.#.#.......#.#.#.......#...#
|
||||||
|
#.###########.###########.###.#.#######.#.###.###.#.###.###.#.###.#.#.###.#.#.#####.###.#.#.###.#######
|
||||||
|
#.#.#...#.#.#...#.#.............#.#...#.#...#.#.#.....#.#.#.......#.#.#.......#.#...#...#.#.#...#.....#
|
||||||
|
###.#.###.#.#.###.#.###.###.#.#.#.#.###.#######.#.#.###.#.#.#.#.###.#.###.#.###.###.#.###.#####.#####.#
|
||||||
|
#...............#.#.#...#...#.#.....#...#...#...#.#.#.....#.#.#.#.#.#.#.#.#.......#.#.#.#.#.#...#.....#
|
||||||
|
#.#######.###.###.#########.#.#.#####.###.#####.###.#.###########.#.#.#.#.#.#.###.#####.###.###.###.###
|
||||||
|
#.#.#.#.#...#...#.#.#.......#.#.....#.......#...#.#.#.#.....#...#.#.#...#.#.#...#.#...#.....#.#.......#
|
||||||
|
###.#.#.#####.#.#.#.#####.#########.#####.#####.#.#.#.###.#.###.#.#.#.#####.#.#######.###.###.#.#.#####
|
||||||
|
#.#.....#.#.#.#.....#.#.....#.......#...#...#.....#.#...#.#.#.....#.#...#...#.#.........#.#...#.#.#.#.#
|
||||||
|
#.#.#####.#.###.#####.#######.#######.#.###.#.#.#.#.###.#.#.#.###.#.#.###########.#.#####.###.#.###.#.#
|
||||||
|
#.....#.#.#.......#...#.#...#.......#.#...#.#.#.#.#.#.#...#.#...#...#...#...#.#...#.#.#.#.#.#.#...#.#.#
|
||||||
|
###.###.#.#####.#####.#.#.#.#.#######.###.#.#.#.###.#.#####.###.#.###.###.###.#.###.#.#.#.#.#.#.###.#.#
|
||||||
|
#.....#...#.#...#...#.#.#.#.......#.....#...#.#.....#...#...#...#.#.#.#.#.#.......#...#...............#
|
||||||
|
###.#.###.#.###.#.###.#.#######.#.###.#.#####.#######.#.#.#.#.###.#.#.#.#.###.###############.#.###.###
|
||||||
|
#...#.#.............#.#.#.......#...#.#.....#.....#...#...#.#...#.#.........#...#.....#.#.#.#.#...#.#.#
|
||||||
|
###.#######.#.###.###.#.#####.#########.#####.#######.#######.#########.#######.###.###.#.#.###.#####.#
|
||||||
|
#.....#...#.#...#.#.....# E O X A X L #.#...#...#.#.....#...#.#
|
||||||
|
#.#.###.#####.###.#####.# N C E Y B O #.###.###.#.#.#####.###.#
|
||||||
|
#.#.....#.#.#.#...#.....# #.#.#.#.#.#.#...#...#...#
|
||||||
|
#.#.###.#.#.###.#.#.###.# #.#.#.#.#.#.#.#####.###.#
|
||||||
|
#.#.#.#...#.#...#...#...# #...............#.#.#.#.#
|
||||||
|
#####.#.#.#.###.#####.### #.#.#.#.#.#.###.#.#.#.#.#
|
||||||
|
#.#.....#.....#...#...#.# #.#.#.#.#.#.#...#.....#..UW
|
||||||
|
#.###.###.#.#.###.#.###.# #.###.#####.#.###.#.#.#.#
|
||||||
|
DK......#.#.#.#.....#......VG EJ....#.#.....#.#...#.#...#
|
||||||
|
#####.#.###.###.###.##### #############.#.#.#####.#
|
||||||
|
#.....#...#.#...#...#....SY #...#...#...#...#.#.#...#
|
||||||
|
#########.#####.#####.### #.###.#####.#####.#.#####
|
||||||
|
LO......#.....#.#.#...#...# #.........#.....#.#.....#
|
||||||
|
#.###.#####.#.###.#####.# #.#.###.###.###.###.###.#
|
||||||
|
#.#.....................# #.#.#.......#.#...#.#.#..XJ
|
||||||
|
#.#########.###.######### #.#####.#.###.###.#.#.###
|
||||||
|
#.#.#.....#...#.#.......# VD....#...#.#.......#.....#
|
||||||
|
#.#.###.#.#########.###.# #.#.###.#####.#####.###.#
|
||||||
|
#.#.#...#.........#...#..WV #.#.#...#.#...........#.#
|
||||||
|
###.###.#####.###.###.### #####.###.###############
|
||||||
|
XE........#...#.#.........# HX....#...#...#...#.....#.#
|
||||||
|
###########.############# #.###.#####.#.###.###.#.#
|
||||||
|
#...#.#...#.........#...# #...#.#.#.#...#.....#.#..XB
|
||||||
|
#.#.#.#.#.#.###.###.###.# #.#####.#.###.###.#.#.#.#
|
||||||
|
#.#.....#...#.#.#.......# #.#.#.....#.#...#.#.#.#.#
|
||||||
|
#.#####.#####.#########.# #.#.#####.#.#.#.###.#.#.#
|
||||||
|
#.#.....#.......#.#.....# #.............#.....#...#
|
||||||
|
#.#########.###.#.#.##### ###.#.#.###.#.#######.###
|
||||||
|
HX..#.#.#...#...#.#........OW XY..#.#.#.#...#.#.....#.#.#
|
||||||
|
###.#.###.#.############# #.#######.#.###.###.###.#
|
||||||
|
#.#.....#.#.#.#.#.#...#.# #...#.....#.#...#...#...#
|
||||||
|
#.#.#####.#.#.#.#.#.#.#.# ###.###########.#.###.#.#
|
||||||
|
#...#.......#.....#.#....QR #.#.#.#.#.......#.#...#..AG
|
||||||
|
#.#.###.#.#######.#.##### #.#.#.#.#####.###.#.###.#
|
||||||
|
WB..#.#...#...#.....#...#.# #...............#...#...#
|
||||||
|
###.#.#.#######.#.###.#.# #.###.###.#.#######.#####
|
||||||
|
#.#...#.........#.....#.# #.#...#...#.#.#...#.#...#
|
||||||
|
#.#####################.# #########.###.###.###.#.#
|
||||||
|
#.......................# #...#...#.#.#...#.....#..DF
|
||||||
|
#.###.#.#.#####.#######.# ###.#.#.###.###.#.###.#.#
|
||||||
|
EN..#...#.#...#...#.#...#.# ZH......#.............#.#.#
|
||||||
|
#######.#.#.#.###.#.#.#.# ###.###.#######.#.###.###
|
||||||
|
#...#.#.#.#.#.#.....#...# DF..#.#.....#.....#.#...#.#
|
||||||
|
###.#.###.###.###.#.##### #.#####.###############.#
|
||||||
|
#.......#...#.#...#......KN #.#...#.#...#.....#.#...#
|
||||||
|
###.#.#########.######### #.###.###.#######.#.#.#.#
|
||||||
|
#...#.#.#.#...#.#.......# #.....................#..GL
|
||||||
|
#.#.###.#.###.#####.#.### #########################
|
||||||
|
#.#...#.......#...#.#....AG WW..#.................#...#
|
||||||
|
#.#.#.#.#########.#.#.### #.#.###.###.#.#####.#.#.#
|
||||||
|
ZH..#.#.#.#.#...#.....#.#.# #.....#...#.#...#.....#..RP
|
||||||
|
#####.#.#.#.###.#.#.#.#.# ###.###.#####.#.###.###.#
|
||||||
|
#...............#.#.#...# #...#.#...#...#.#.....#.#
|
||||||
|
###.###.###.#.#.#.###.### X S U R W D G ###.#.#.#.###.###.###.###
|
||||||
|
#...#.#...#.#.#.#.#...#.# J H W P B K L #.#...#.#.#.#.#.#.#.....#
|
||||||
|
#####.#.###.#.###.#####.#######.#######.#####.###.#####.###########.#.#########.#.#.###.#.#.#.#####.#.#
|
||||||
|
#.#.....#.#.#...#...#.#.....#.#.....#...#.........#.........#.......#.........#...#...#.#.#.......#.#.#
|
||||||
|
#.###.#.#.#.#########.#.#####.#.#######.#####.###.#.#.#.#####.#####.#.###.#######.#####.#.###.###.#.#.#
|
||||||
|
#.#...#.#.......#...............#.#...#.....#.#.#.#.#.#.#...#.#...#.#.#...#...#.#.....#...#.....#.#.#.#
|
||||||
|
#.###.###.#########.#.#.#####.###.#.###.#.###.#.#####.#####.#.#.#.#######.###.#.###.#####.###.#########
|
||||||
|
#.......#.#.#.....#.#.#.#.............#.#.#.........#...#.....#.#.....#.........#...#.#...#...........#
|
||||||
|
#.###.###.#.#.#########.#####.#####.#####.###.#######.###.#.#.#.###.###.###.###.#####.#####.#.#.#####.#
|
||||||
|
#.#.....#.....#.....#...#.#.#.....#.#.......#.#.#...#...#.#.#...#...#.....#.#...........#.#.#.#.....#.#
|
||||||
|
#######.###.###.#######.#.#.#.#.#######.###.#.#.#.###.###########.#######.###########.#.#.#####.#####.#
|
||||||
|
#.......#...........#.#.#.....#.#.#...#.#...#.....#.......#.#...#.#...#.........#...#.#.....#.......#.#
|
||||||
|
#.#.#####.#.#.#.#.#.#.###.###.###.#.###.#.#.#.#######.#####.###.#.#.#.#.#########.###########.###.#####
|
||||||
|
#.#.#.#...#.#.#.#.#.#.#.#.#.#.........#.#.#.#.#.#.#.....#...#.......#.#...#.................#.#.......#
|
||||||
|
###.#.###.###.###.#.#.#.###.#.#.###########.#.#.#.###.###.###.###.#######.#.#####.#.#.###.#######.#.###
|
||||||
|
#.......#...#...#.#.......#...#.#.......#...#.....#.#.....#.#.#.....#...........#.#.#...#.....#...#.#.#
|
||||||
|
###.#####.#####.#.#.#.#####.#.#####.###.###.###.###.#.#####.#######.#.###.###.###.#######.###.###.###.#
|
||||||
|
#.....#...#.....#.#.#.#...#.#.....#.#...#.#.#.....#.....#.....#.....#.#...#...#.......#...#.....#.....#
|
||||||
|
###.#####.###.###########.#####.#######.#.#.#.#.#####.#######.#.#####.#####.#######.###.#.#####.###.###
|
||||||
|
#...#.#.....#.#.#.......#.......#...#.#.....#.#.#...#.....#.#.......#...#.#.#.#.#.#...#.#.#.#.#...#...#
|
||||||
|
#####.#########.###.###.#####.#####.#.###.###.#####.#.#####.#######.#.###.###.#.#.#.#######.#.#########
|
||||||
|
#.#.......#.#.#.....#.#.............#.....#.#.....#.#...#.....#.....#.#...#.#.#.#.#...#...#...........#
|
||||||
|
#.###.#####.#.#.#####.#####.#.#.###.#.#####.#.#.#.#.#.###.#.#####.###.#.#.#.#.#.#.#####.#####.#####.###
|
||||||
|
#...............#.#.#.......#.#...#.#.......#.#.#...#.#...#.#.#.#...#...#.................#.......#...#
|
||||||
|
#.#.#.#.#.#####.#.#.#.#.#.#.#.#####.#.#.###.#.#####.#.#.###.#.#.###.#.###.#.#.###.#.#.#.#####.#########
|
||||||
|
#.#.#.#.#.#.....#.....#.#.#.#.#.....#.#.#...#.#.....#...#...#.......#.#...#.#.#...#.#.#...............#
|
||||||
|
###############################.###.#####.#####.#.#######.###.#########.###############################
|
||||||
|
X Z V O O S W E
|
||||||
|
Y Z G C W Y W J
|
||||||
19
input/day20_example1.txt
Normal file
19
input/day20_example1.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
A
|
||||||
|
A
|
||||||
|
#######.#########
|
||||||
|
#######.........#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
#######.#######.#
|
||||||
|
##### B ###.#
|
||||||
|
BC...## C ###.#
|
||||||
|
##.## ###.#
|
||||||
|
##...DE F ###.#
|
||||||
|
##### G ###.#
|
||||||
|
#########.#####.#
|
||||||
|
DE..#######...###.#
|
||||||
|
#.#########.###.#
|
||||||
|
FG..#########.....#
|
||||||
|
###########.#####
|
||||||
|
Z
|
||||||
|
Z
|
||||||
37
input/day20_example2.txt
Normal file
37
input/day20_example2.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Z L X W C
|
||||||
|
Z P Q B K
|
||||||
|
###########.#.#.#.#######.###############
|
||||||
|
#...#.......#.#.......#.#.......#.#.#...#
|
||||||
|
###.#.#.#.#.#.#.#.###.#.#.#######.#.#.###
|
||||||
|
#.#...#.#.#...#.#.#...#...#...#.#.......#
|
||||||
|
#.###.#######.###.###.#.###.###.#.#######
|
||||||
|
#...#.......#.#...#...#.............#...#
|
||||||
|
#.#########.#######.#.#######.#######.###
|
||||||
|
#...#.# F R I Z #.#.#.#
|
||||||
|
#.###.# D E C H #.#.#.#
|
||||||
|
#.#...# #...#.#
|
||||||
|
#.###.# #.###.#
|
||||||
|
#.#....OA WB..#.#..ZH
|
||||||
|
#.###.# #.#.#.#
|
||||||
|
CJ......# #.....#
|
||||||
|
####### #######
|
||||||
|
#.#....CK #......IC
|
||||||
|
#.###.# #.###.#
|
||||||
|
#.....# #...#.#
|
||||||
|
###.### #.#.#.#
|
||||||
|
XF....#.# RF..#.#.#
|
||||||
|
#####.# #######
|
||||||
|
#......CJ NM..#...#
|
||||||
|
###.#.# #.###.#
|
||||||
|
RE....#.# #......RF
|
||||||
|
###.### X X L #.#.#.#
|
||||||
|
#.....# F Q P #.#.#.#
|
||||||
|
###.###########.###.#######.#########.###
|
||||||
|
#.....#...#.....#.......#...#.....#.#...#
|
||||||
|
#####.#.###.#######.#######.###.###.#.#.#
|
||||||
|
#.......#.......#.#.#.#.#...#...#...#.#.#
|
||||||
|
#####.###.#####.#.#.#.#.###.###.#.###.###
|
||||||
|
#.......#.....#.#...#...............#...#
|
||||||
|
#############.#.#.###.###################
|
||||||
|
A O F N
|
||||||
|
A A D M
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
extern crate core;
|
||||||
|
|
||||||
mod tasks;
|
mod tasks;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tasks::day19::run();
|
tasks::day20::run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use super::day05::{IntCodeComputer, RAM};
|
use super::day05::{IntCodeComputer, RAM};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let program = super::day05::load_ram("input/day19.txt");
|
let program = super::day05::load_ram("input/day19.txt");
|
||||||
part1(&program, 50);
|
part1(&program, 50);
|
||||||
@@ -12,9 +13,7 @@ fn part1(program: &RAM, max_perimeter: i128) {
|
|||||||
let result = (0..max_perimeter)
|
let result = (0..max_perimeter)
|
||||||
.flat_map(|x| {
|
.flat_map(|x| {
|
||||||
(0..max_perimeter)
|
(0..max_perimeter)
|
||||||
.map(|y| {
|
.map(|y| read_coordinate(program, x, y))
|
||||||
read_coordinate(program, x, y)
|
|
||||||
})
|
|
||||||
.collect_vec()
|
.collect_vec()
|
||||||
})
|
})
|
||||||
.filter(|v| *v)
|
.filter(|v| *v)
|
||||||
@@ -27,13 +26,11 @@ const SHIP_SIZE: i128 = 100;
|
|||||||
|
|
||||||
fn part2(program: &RAM) {
|
fn part2(program: &RAM) {
|
||||||
let mut map: HashMap<(i128, i128), bool> = HashMap::new();
|
let mut map: HashMap<(i128, i128), bool> = HashMap::new();
|
||||||
(0..SHIP_SIZE)
|
(0..SHIP_SIZE).for_each(|x| {
|
||||||
.for_each(|x| {
|
(0..SHIP_SIZE).for_each(|y| {
|
||||||
(0..SHIP_SIZE)
|
map.insert((x, y), read_coordinate(program, x, y));
|
||||||
.for_each(|y| {
|
})
|
||||||
map.insert((x, y), read_coordinate(program, x, y));
|
});
|
||||||
})
|
|
||||||
});
|
|
||||||
for perimeter in 0.. {
|
for perimeter in 0.. {
|
||||||
extend_horizon(program, &mut map, perimeter);
|
extend_horizon(program, &mut map, perimeter);
|
||||||
if let Some((x, y)) = check_all_squares_starting_at(&map, perimeter) {
|
if let Some((x, y)) = check_all_squares_starting_at(&map, perimeter) {
|
||||||
@@ -44,7 +41,10 @@ fn part2(program: &RAM) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_all_squares_starting_at(map: &HashMap<(i128, i128), bool>, perimeter: i128) -> Option<(i128, i128)> {
|
fn check_all_squares_starting_at(
|
||||||
|
map: &HashMap<(i128, i128), bool>,
|
||||||
|
perimeter: i128,
|
||||||
|
) -> Option<(i128, i128)> {
|
||||||
for i in 0..=perimeter {
|
for i in 0..=perimeter {
|
||||||
if let Some(point) = check_fits(map, i, perimeter) {
|
if let Some(point) = check_fits(map, i, perimeter) {
|
||||||
return Some(point);
|
return Some(point);
|
||||||
@@ -79,4 +79,4 @@ fn read_coordinate(program: &RAM, x: i128, y: i128) -> bool {
|
|||||||
let mut computer = IntCodeComputer::new(vec![x, y], program.clone());
|
let mut computer = IntCodeComputer::new(vec![x, y], program.clone());
|
||||||
computer.run_until_end();
|
computer.run_until_end();
|
||||||
*computer.get_output().first().unwrap() == 1
|
*computer.get_output().first().unwrap() == 1
|
||||||
}
|
}
|
||||||
|
|||||||
363
src/tasks/day20.rs
Normal file
363
src/tasks/day20.rs
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
let input = std::fs::read_to_string("input/day20.txt").unwrap();
|
||||||
|
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||||
|
let part1 = maze.shortest_path();
|
||||||
|
println!("Part 1: {}", part1);
|
||||||
|
|
||||||
|
let maze = Maze::from(&input, DimensionField::curried_factory);
|
||||||
|
let part1 = maze.shortest_path();
|
||||||
|
println!("Part 2: {}", part1);
|
||||||
|
}
|
||||||
|
|
||||||
|
type C = i32;
|
||||||
|
type FieldFactory = Box<dyn Fn(&MapPoint) -> Box<dyn Field>>;
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
|
struct MapPoint {
|
||||||
|
x: C,
|
||||||
|
y: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapPoint {
|
||||||
|
fn of(x: C, y: C) -> Self {
|
||||||
|
MapPoint { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neighbors(self) -> Vec<MapPoint> {
|
||||||
|
vec![
|
||||||
|
MapPoint::of(self.x + 1, self.y),
|
||||||
|
MapPoint::of(self.x, self.y + 1),
|
||||||
|
MapPoint::of(self.x - 1, self.y),
|
||||||
|
MapPoint::of(self.x, self.y - 1),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
|
struct RealPoint {
|
||||||
|
x: C,
|
||||||
|
y: C,
|
||||||
|
level: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RealPoint {
|
||||||
|
fn map_point(&self) -> MapPoint {
|
||||||
|
MapPoint {
|
||||||
|
x: self.x,
|
||||||
|
y: self.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RealPoint {
|
||||||
|
fn from(map_point: MapPoint, level: usize) -> Self {
|
||||||
|
RealPoint {
|
||||||
|
x: map_point.x,
|
||||||
|
y: map_point.y,
|
||||||
|
level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Field {
|
||||||
|
fn neighbors(&self, at_level: usize) -> Vec<RealPoint>;
|
||||||
|
fn set_label_partner(&mut self, point: MapPoint);
|
||||||
|
fn set_neighbors(&mut self, neighbors: Vec<MapPoint>);
|
||||||
|
fn curried_factory(width: C, height: C) -> FieldFactory
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PortalField {
|
||||||
|
neighbors: Vec<MapPoint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortalField {
|
||||||
|
fn new() -> Self {
|
||||||
|
PortalField { neighbors: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field for PortalField {
|
||||||
|
fn neighbors(&self, _: usize) -> Vec<RealPoint> {
|
||||||
|
self.neighbors
|
||||||
|
.iter()
|
||||||
|
.map(|p| RealPoint::from(*p, 0))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_label_partner(&mut self, point: MapPoint) {
|
||||||
|
self.neighbors.push(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_neighbors(&mut self, neighbors: Vec<MapPoint>) {
|
||||||
|
self.neighbors = neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn curried_factory(_: C, _: C) -> FieldFactory {
|
||||||
|
Box::new(|_| Box::new(PortalField::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DimensionField {
|
||||||
|
point: MapPoint,
|
||||||
|
neighbors: Vec<MapPoint>,
|
||||||
|
jump: Option<MapPoint>,
|
||||||
|
map_width: C,
|
||||||
|
map_height: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DimensionField {
|
||||||
|
fn is_inward(&self) -> bool {
|
||||||
|
let p = self.point;
|
||||||
|
p.x > 2 && p.x < self.map_width - 3 && p.y > 2 && p.y < self.map_height - 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field for DimensionField {
|
||||||
|
fn neighbors(&self, at_level: usize) -> Vec<RealPoint> {
|
||||||
|
let mut result: Vec<RealPoint> = self
|
||||||
|
.neighbors
|
||||||
|
.iter()
|
||||||
|
.map(|n| RealPoint::from(*n, at_level))
|
||||||
|
.collect();
|
||||||
|
if let Some(destination) = self.jump {
|
||||||
|
if self.is_inward() {
|
||||||
|
result.push(RealPoint::from(destination, at_level + 1));
|
||||||
|
} else if at_level > 0 {
|
||||||
|
result.push(RealPoint::from(destination, at_level - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_label_partner(&mut self, point: MapPoint) {
|
||||||
|
self.jump = Some(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_neighbors(&mut self, neighbors: Vec<MapPoint>) {
|
||||||
|
self.neighbors = neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn curried_factory(width: C, height: C) -> FieldFactory {
|
||||||
|
Box::new(move |point: &MapPoint| {
|
||||||
|
Box::new(Self {
|
||||||
|
point: *point,
|
||||||
|
neighbors: vec![],
|
||||||
|
jump: None,
|
||||||
|
map_width: width,
|
||||||
|
map_height: height,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldMap = HashMap<MapPoint, Box<dyn Field>>;
|
||||||
|
|
||||||
|
struct Maze {
|
||||||
|
map: FieldMap,
|
||||||
|
start: RealPoint,
|
||||||
|
finish: RealPoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Maze {
|
||||||
|
fn from(input: &String, factory: fn(C, C) -> FieldFactory) -> Self {
|
||||||
|
let (moc, width, height) = Self::map_of_chars(input);
|
||||||
|
|
||||||
|
let mut map = Self::create_map_of_free_spots(&moc, factory(width, height));
|
||||||
|
Self::add_physical_neighbors(&mut map);
|
||||||
|
let labels = Self::labels(&moc, width, height);
|
||||||
|
Self::process_labels(&mut map, &labels);
|
||||||
|
let start = labels["AA"][0];
|
||||||
|
let finish = labels["ZZ"][0];
|
||||||
|
|
||||||
|
Maze {
|
||||||
|
map,
|
||||||
|
start: RealPoint::from(start, 0),
|
||||||
|
finish: RealPoint::from(finish, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shortest_path(&self) -> usize {
|
||||||
|
bfs(&self.map, self.start, self.finish)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_labels(map: &mut FieldMap, labels: &HashMap<String, Vec<MapPoint>>) {
|
||||||
|
for (label, points) in labels {
|
||||||
|
if label == "AA" || label == "ZZ" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.get_mut(&points[0])
|
||||||
|
.unwrap()
|
||||||
|
.set_label_partner(points[1]);
|
||||||
|
map.get_mut(&points[1])
|
||||||
|
.unwrap()
|
||||||
|
.set_label_partner(points[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn labels(
|
||||||
|
moc: &HashMap<MapPoint, char>,
|
||||||
|
width: C,
|
||||||
|
height: C,
|
||||||
|
) -> HashMap<String, Vec<MapPoint>> {
|
||||||
|
let horizontal: Vec<(String, MapPoint)> = (0..width - 2)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|x| {
|
||||||
|
(0..height).into_iter().flat_map(move |y| {
|
||||||
|
let mut triple = [
|
||||||
|
moc[&MapPoint::of(x, y)],
|
||||||
|
moc[&MapPoint::of(x + 1, y)],
|
||||||
|
moc[&MapPoint::of(x + 2, y)],
|
||||||
|
];
|
||||||
|
let left = Self::label(triple).map(|label| (label, MapPoint::of(x, y)));
|
||||||
|
triple.reverse();
|
||||||
|
let right = Self::label(triple).map(|label| (label, MapPoint::of(x + 2, y)));
|
||||||
|
vec![left, right]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vertical: Vec<(String, MapPoint)> = (0..width)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|x| {
|
||||||
|
(0..height - 2).into_iter().flat_map(move |y| {
|
||||||
|
let mut triple = [
|
||||||
|
moc[&MapPoint::of(x, y)],
|
||||||
|
moc[&MapPoint::of(x, y + 1)],
|
||||||
|
moc[&MapPoint::of(x, y + 2)],
|
||||||
|
];
|
||||||
|
let left = Self::label(triple).map(|label| (label, MapPoint::of(x, y)));
|
||||||
|
triple.reverse();
|
||||||
|
let right = Self::label(triple).map(|label| (label, MapPoint::of(x, y + 2)));
|
||||||
|
vec![left, right]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
for (s, p) in horizontal.into_iter().chain(vertical.into_iter()) {
|
||||||
|
if !result.contains_key(&s) {
|
||||||
|
result.insert(s.clone(), vec![]);
|
||||||
|
}
|
||||||
|
result.get_mut(&s).unwrap().push(p);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label(chars: [char; 3]) -> Option<String> {
|
||||||
|
if chars[0] == '.' && chars[1].is_alphabetic() && chars[2].is_alphabetic() {
|
||||||
|
let label = if chars[1] < chars[2] {
|
||||||
|
format!("{}{}", chars[1], chars[2])
|
||||||
|
} else {
|
||||||
|
format!("{}{}", chars[2], chars[1])
|
||||||
|
};
|
||||||
|
Some(label)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_physical_neighbors(map: &mut FieldMap) {
|
||||||
|
let points: HashSet<MapPoint> = map.keys().map(|p| *p).collect();
|
||||||
|
map.iter_mut().for_each(|(p, f)| {
|
||||||
|
let neighbors = p
|
||||||
|
.neighbors()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|neighbor| points.contains(neighbor))
|
||||||
|
.collect();
|
||||||
|
f.set_neighbors(neighbors);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_map_of_free_spots(
|
||||||
|
moc: &HashMap<MapPoint, char>,
|
||||||
|
field_factory: FieldFactory,
|
||||||
|
) -> FieldMap {
|
||||||
|
moc.keys()
|
||||||
|
.filter(|p| moc[p] == '.')
|
||||||
|
.map(|p| (*p, field_factory(p)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_of_chars(input: &String) -> (HashMap<MapPoint, char>, C, C) {
|
||||||
|
let mut map: HashMap<MapPoint, char> = input
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(y, line)| {
|
||||||
|
line.chars()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(x, c)| (MapPoint::of(x as C, y as C), c))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let width = map.keys().map(|p| p.x).max().unwrap() + 1;
|
||||||
|
let height = map.keys().map(|p| p.y).max().unwrap() + 1;
|
||||||
|
|
||||||
|
for x in 0..width {
|
||||||
|
for y in 0..height {
|
||||||
|
if !map.contains_key(&MapPoint::of(x, y)) {
|
||||||
|
map.insert(MapPoint::of(x, y), ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(map, width, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bfs(map: &FieldMap, start: RealPoint, finish: RealPoint) -> usize {
|
||||||
|
let mut open: VecDeque<(RealPoint, usize)> = VecDeque::new();
|
||||||
|
let mut seen: HashSet<RealPoint> = HashSet::new();
|
||||||
|
|
||||||
|
open.push_back((start, 0));
|
||||||
|
seen.insert(start);
|
||||||
|
|
||||||
|
while let Some((p, d)) = open.pop_front() {
|
||||||
|
if p == finish {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
for neighbor in map[&p.map_point()].neighbors(p.level) {
|
||||||
|
if !seen.contains(&neighbor) {
|
||||||
|
open.push_back((neighbor, d + 1));
|
||||||
|
seen.insert(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("no path found")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::tasks::day20::{DimensionField, Field, Maze, PortalField};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_part1() {
|
||||||
|
let input = std::fs::read_to_string("input/day20_example1.txt").unwrap();
|
||||||
|
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||||
|
assert_eq!(maze.shortest_path(), 23);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_part2() {
|
||||||
|
let input = std::fs::read_to_string("input/day20_example2.txt").unwrap();
|
||||||
|
let maze = Maze::from(&input, DimensionField::curried_factory);
|
||||||
|
assert_eq!(maze.shortest_path(), 396);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn result() {
|
||||||
|
let input = std::fs::read_to_string("input/day20.txt").unwrap();
|
||||||
|
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||||
|
assert_eq!(maze.shortest_path(), 454);
|
||||||
|
|
||||||
|
let maze = Maze::from(&input, DimensionField::curried_factory);
|
||||||
|
assert_eq!(maze.shortest_path(), 5744);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ pub mod day16;
|
|||||||
pub mod day17;
|
pub mod day17;
|
||||||
pub mod day18;
|
pub mod day18;
|
||||||
pub mod day19;
|
pub mod day19;
|
||||||
|
pub mod day20;
|
||||||
pub mod day21;
|
pub mod day21;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod day22;
|
pub mod day22;
|
||||||
|
|||||||
Reference in New Issue
Block a user