Compare commits

...

15 Commits

Author SHA1 Message Date
3c1a48fe51 Day 22 part 2 2022-10-08 17:05:14 +02:00
0f9d48314e Day 16 part 2 2022-10-08 15:47:26 +02:00
14fc032ffc Day 25 part 1 2022-10-08 12:47:58 +02:00
0089f4337c Day 23 part 2 2022-10-03 09:04:41 +02:00
c8cef9c0ce Extended IntCodeComputer. 2022-10-03 09:03:31 +02:00
420b6152fb day 23 part 1 2022-10-02 19:57:00 +02:00
79ea3c29d0 day20 format 2022-10-02 17:49:00 +02:00
e87d31c941 day20 cleanup 2022-10-02 17:48:35 +02:00
6e06599c33 day20 part 2 2022-10-02 17:46:33 +02:00
3b829649f3 day20 refactored for part 2 - currying 2022-10-02 16:54:45 +02:00
922f2a483c day20 refactored for part 2 2022-10-02 14:17:08 +02:00
4002297ede day20 refactored for part 2 2022-10-02 14:05:24 +02:00
9a34cca688 day20 part 1 2022-10-02 13:19:36 +02:00
358e185501 day20 shortest path to come 2022-10-02 11:28:33 +02:00
eeda13a0d6 day19 format 2022-10-02 11:06:40 +02:00
16 changed files with 934 additions and 113 deletions

73
Cargo.lock generated
View File

@@ -15,10 +15,11 @@ dependencies = [
name = "aoc_2019"
version = "0.1.0"
dependencies = [
"itertools",
"modinverse",
"num-integer",
"regex",
"itertools",
"mod_exp",
"modinverse",
"num-integer",
"regex",
]
[[package]]
@@ -39,7 +40,7 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
"either",
]
[[package]]
@@ -48,13 +49,45 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "mod_exp"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb4a3fad6af79fcf8d1417b2f6359d814a173fb413a1bd48ba04208b42b0d8b0"
dependencies = [
"num",
]
[[package]]
name = "modinverse"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633"
dependencies = [
"num-integer",
"num-integer",
]
[[package]]
name = "num"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36"
dependencies = [
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
@@ -63,8 +96,30 @@ version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
@@ -73,7 +128,7 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
"autocfg",
]
[[package]]

View File

@@ -11,3 +11,4 @@ itertools = "0.10.3"
regex = "1.5.5"
num-integer = "0.1.44"
modinverse = "0.1.1"
mod_exp = "1.0.1"

109
input/day20.txt Normal file
View 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
View File

@@ -0,0 +1,19 @@
A
A
#######.#########
#######.........#
#######.#######.#
#######.#######.#
#######.#######.#
##### B ###.#
BC...## C ###.#
##.## ###.#
##...DE F ###.#
##### G ###.#
#########.#####.#
DE..#######...###.#
#.#########.###.#
FG..#########.....#
###########.#####
Z
Z

37
input/day20_example2.txt Normal file
View 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
input/day23.txt Normal file

File diff suppressed because one or more lines are too long

1
input/day25.txt Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,7 @@
extern crate core;
mod tasks;
fn main() {
tasks::day19::run();
tasks::day22::run();
}

View File

@@ -217,6 +217,7 @@ impl IntCodeComputer {
op.params[0].store(&mut self.ram, *v, self.relative_base_offset);
self.pc += 2;
} else {
self.input_storage.clear();
return false;
}
}
@@ -282,10 +283,24 @@ impl IntCodeComputer {
}
}
pub fn add_input(&mut self, input: &[i128]) {
for x in input {
self.input_storage.push(*x);
}
}
pub fn get_input(&self) -> &[i128] {
self.input_storage.as_slice()
}
pub fn clear_output(&mut self) {
self.output_storage.clear();
}
pub fn clear_n_output(&mut self, n: usize) {
self.output_storage = Vec::from(self.output_storage.split_at(n).1);
}
pub fn get_output(&self) -> &[i128] {
self.output_storage.as_slice()
}

View File

@@ -1,16 +1,30 @@
use itertools::Itertools;
use num_integer::Integer;
use std::collections::HashMap;
use std::iter;
use itertools::Itertools;
const BASE_PATTERN: [i32; 4] = [0, 1, 0, -1];
const INPUT: &str = "59750530221324194853012320069589312027523989854830232144164799228029162830477472078089790749906142587998642764059439173975199276254972017316624772614925079238407309384923979338502430726930592959991878698412537971672558832588540600963437409230550897544434635267172603132396722812334366528344715912756154006039512272491073906389218927420387151599044435060075148142946789007756800733869891008058075303490106699737554949348715600795187032293436328810969288892220127730287766004467730818489269295982526297430971411865028098708555709525646237713045259603175397623654950719275982134690893685598734136409536436003548128411943963263336042840301380655801969822";
#[allow(dead_code)]
pub fn run() {
let input = to_digits(INPUT);
task1(input.clone());
task2(to_digits("02935109699940807407585447034323"));
task2(input.clone());
}
fn task1(input: Vec<V>) -> String {
let mut s = S { input, cache: HashMap::new() };
s.prep();
let result = format!("{:.*}", 8, (0..8).map(|position| {
let r = s.get(position, 100);
r
}).join(""));
println!("Task 1: {result}");
result
}
fn to_digits(input: &str) -> Vec<i32> {
input
.chars()
@@ -18,71 +32,88 @@ fn to_digits(input: &str) -> Vec<i32> {
.collect_vec()
}
fn task1(input: Vec<i32>) -> String {
let p = [0, 1, 0, -1];
let result = (0..100).fold(input, |old, _| {
(1..=old.len())
.map(|position| {
let pattern = p
.iter()
.map(|x| std::iter::repeat(*x).take(position))
.flatten();
let val: i32 = old
.iter()
.zip(std::iter::repeat(pattern).flatten().skip(1))
.map(|(value, multiplier)| value * multiplier)
.sum();
val.abs() % 10
})
.collect_vec()
});
let result = format!("{:.*}", 8, result.iter().join(""));
println!("Task 1: {result}");
fn task2(input: Vec<i32>) -> String {
let big_input = iter::repeat(input.clone().into_iter())
.take(10_000)
.flatten()
.collect_vec();
let mut s = S { input: big_input, cache: HashMap::new() };
let result_position = format!("{}", input.split_at(7).0.iter().join("")).parse::<usize>().unwrap();
s.prep_after(result_position);
let result = format!("{:.*}", 8, (0..8).map(|position| {
let r = s.get(position + result_position, 100);
r
}).join(""));
println!("Task 2: {result}");
result
}
fn task2(input: Vec<i32>) -> String {
let l = input.len() * 10_000;
let big_input = iter::repeat(input.clone().into_iter())
.flatten()
.take(l)
.collect_vec();
let p = [0, 1, 0, -1];
let result = (0..100).fold(big_input, |old, _| {
(1..=old.len())
.map(|position| {
let pattern = p.iter().map(|x| iter::repeat(*x).take(position)).flatten();
let iter = iter::repeat(pattern).flatten().skip(1);
let repeats_after = (4 * position).lcm(&input.len());
if repeats_after > l {
l
} else {
repeats_after
};
let part: i32 = iter::repeat(input.iter())
.flatten()
.zip(iter.clone())
.take(repeats_after)
.map(|(value, multiplier)| value * multiplier)
.sum();
let part_fits = l / repeats_after;
let most_parts = part * part_fits as i32;
type V = i32;
let number_rest = l / repeats_after;
let part_rest: i32 = iter
.zip(iter::repeat(input.iter()).flatten())
.take(number_rest)
.map(|(value, multiplier)| value * multiplier)
.sum();
struct S {
input: Vec<V>,
cache: HashMap<(usize, usize), V>,
}
(part_rest + most_parts) % 10
})
.collect_vec()
});
let offset = input[0..7].iter().join("").parse::<usize>().unwrap();
let message = result[offset..offset + 8].iter().join("");
println!("Task 2: {}", message);
message
impl S {
fn pattern(&self, position: usize, size: usize) -> Vec<i32> {
let pattern = BASE_PATTERN.iter().map(|x| iter::repeat(*x).take(position)).flatten();
let iter = iter::repeat(pattern).flatten().skip(1).take(size);
iter.collect()
}
fn get(&mut self, index: usize, phase: usize) -> V {
if phase == 0 {
return self.input[index];
}
if self.cache.contains_key(&(phase, index)) {
return self.cache[&(phase, index)];
}
if index == self.input.len() - 1 {
let v = self.get(index, phase - 1);
self.cache.insert((phase, index), v);
return v;
}
if index > (self.input.len() / 2 + 1) {
let v = self.get(index + 1, phase) + self.get(index, phase - 1);
let v = v.abs() % 10;
self.cache.insert((phase, index), v);
return v;
}
let pattern = self.pattern(index + 1, self.input.len());
let val: i32 = pattern
.iter()
.enumerate()
.map(|(i, p)| if *p == 0 { 0 } else { *p * self.get(i, phase - 1) })
.sum();
let result = val.abs() % 10;
self.cache.insert((phase, index), result);
result
}
fn prep(&mut self) {
for phase in 1..=100 {
for i in 1..self.input.len() / 2 {
self.get(self.input.len() - i, phase);
}
}
println!("preparation done")
}
fn prep_after(&mut self, start: usize) {
for phase in 1..=100 {
for i in (start..self.input.len()).rev() {
self.get(i, phase);
}
}
println!("preparation done")
}
}
#[cfg(test)]
@@ -104,13 +135,30 @@ mod test {
"52432133"
);
}
#[test]
fn test_part_1_solution() {
assert_eq!(task1(to_digits(INPUT)), "84487724");
}
#[test]
fn test_part_2() {
fn test_part_2_solution() {
assert_eq!(task2(to_digits(INPUT)), "84692524");
}
#[test]
fn test_trivial() {
let mut s = S { input: to_digits("12345678"), cache: HashMap::new() };
s.prep();
let result = format!("{:.*}", 8, (0..8).map(|position| {
let r = s.get(position, 1);
r
}).join(""));
assert_eq!(result, "48226158");
}
#[test]
fn test_part_2_examples() {
assert_eq!(
task2(to_digits("02935109699940807407585447034323")),
"78725270"

View File

@@ -1,7 +1,8 @@
use std::collections::HashMap;
use super::day05::{IntCodeComputer, RAM};
use itertools::Itertools;
use std::collections::HashMap;
#[allow(dead_code)]
pub fn run() {
let program = super::day05::load_ram("input/day19.txt");
part1(&program, 50);
@@ -12,9 +13,7 @@ fn part1(program: &RAM, max_perimeter: i128) {
let result = (0..max_perimeter)
.flat_map(|x| {
(0..max_perimeter)
.map(|y| {
read_coordinate(program, x, y)
})
.map(|y| read_coordinate(program, x, y))
.collect_vec()
})
.filter(|v| *v)
@@ -27,13 +26,11 @@ const SHIP_SIZE: i128 = 100;
fn part2(program: &RAM) {
let mut map: HashMap<(i128, i128), bool> = HashMap::new();
(0..SHIP_SIZE)
.for_each(|x| {
(0..SHIP_SIZE)
.for_each(|y| {
map.insert((x, y), read_coordinate(program, x, y));
})
});
(0..SHIP_SIZE).for_each(|x| {
(0..SHIP_SIZE).for_each(|y| {
map.insert((x, y), read_coordinate(program, x, y));
})
});
for perimeter in 0.. {
extend_horizon(program, &mut 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 {
if let Some(point) = check_fits(map, i, perimeter) {
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());
computer.run_until_end();
*computer.get_output().first().unwrap() == 1
}
}

364
src/tasks/day20.rs Normal file
View File

@@ -0,0 +1,364 @@
use std::collections::{HashMap, HashSet, VecDeque};
#[allow(dead_code)]
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);
}
}

View File

@@ -1,16 +1,20 @@
use modinverse::modinverse;
use std::collections::HashMap;
use std::collections::VecDeque;
use mod_exp::mod_exp;
use modinverse::modinverse;
use crate::tasks::day22::Cmd::{Cut, Deal, Stack};
pub fn run() {
let input = std::fs::read_to_string("input/day22.txt").unwrap();
println!("{}", task2(input, 119315717514047, 2020, 101741582076661));
println!("Task 1: {}", task1(&input));
println!("Task 2: {}", task2(&input));
}
type Deck = VecDeque<u16>;
type Size = i128;
fn task1(input: String) -> usize {
fn task1(input: &str) -> usize {
let deck_size = 10_007;
let mut deck: Deck = (0..deck_size).collect();
for line in input.lines() {
@@ -59,31 +63,50 @@ fn deal_with_increment(deck: Deck, n: usize) -> Deck {
new.into_iter().collect()
}
fn task2(input: String, deck_size: Size, field_after: Size, num_iterations: usize) -> Size {
let shuffles: Vec<String> = input.trim().lines().rev().map(|it| it.into()).collect();
let mut results: HashMap<Size, usize> = HashMap::new();
let mut result = field_after;
results.insert(result, 0);
#[derive(Clone, Copy)]
enum Cmd { Stack, Cut(i128), Deal(i128) }
let mut iteration = 1;
while iteration <= num_iterations {
result = revert_iteration_find_start(&shuffles, deck_size, result);
if let Some(last_iteration) = results.get(&result) {
println!("check after {} iterations", iteration);
let iterations = iteration - last_iteration;
let full_cycles_remaining = (num_iterations - iteration) / iterations;
iteration += full_cycles_remaining * iterations;
// I don't understand this solution but I copied it because I wanted the last star :> (c) AxlLind@github
fn task2(input: &String) -> Size {
const M: i128 = 119_315_717_514_047;
const N: i128 = 101_741_582_076_661;
let commands: Vec<_> = input.lines().map(|line| {
if line.starts_with("deal into new stack") {
Stack
} else if line.starts_with("cut") {
let s = line.split("cut ").collect::<Vec<_>>();
let n = s[1].parse::<i128>().unwrap();
Cut(n)
} else if line.starts_with("deal with increment") {
let s = line.split("deal with increment ").collect::<Vec<_>>();
let n = s[1].parse::<i128>().unwrap();
Deal(n)
} else {
results.insert(result, iteration);
panic!("'{line}' is illegal")
}
iteration += 1;
if iteration % 1000 == 0 {
println!("iteration {}", iteration);
}
}
}).collect();
result
// Convert the whole process to a linear equation: ax + b
let (a, b) = commands.iter().rev().fold((1, 0), |(a, b), &cmd| {
let (a_new, b_new) = match cmd {
Stack => (-a, -b - 1),
Cut(n) => (a, b + n),
Deal(n) => {
let n = mod_exp(n, M - 2, M);
(a * n, b * n)
}
};
(a_new % M, b_new % M)
});
// Applying the function n times simplifies to:
// x * a^n + b * (a^n - 1) / (a-1)
let term1 = 2020 * mod_exp(a, N, M) % M;
let tmp = (mod_exp(a, N, M) - 1) * mod_exp(a - 1, M - 2, M) % M;
let term2 = b * tmp % M;
(term1 + term2) % M
}
fn revert_iteration_find_start(shuffles: &Vec<String>, deck_size: Size, field_after: Size) -> Size {
@@ -123,15 +146,14 @@ mod test {
use crate::tasks::day22::task2;
#[test]
fn part1() {
let input = std::fs::read_to_string("input/day22.txt").unwrap();
assert_eq!(7545, task1(input));
assert_eq!(7545, task1(&input));
}
#[test]
fn part2() {
let input = std::fs::read_to_string("input/day22.txt").unwrap();
assert_eq!(2019, task2(input, 10007, 7545, 1));
assert_eq!(2019, task2(&input));
}
}

100
src/tasks/day23.rs Normal file
View File

@@ -0,0 +1,100 @@
use std::collections::VecDeque;
use crate::tasks::day05::{IntCodeComputer, load_ram, RAM};
#[allow(dead_code)]
pub fn run() {
let ram = load_ram("input/day23.txt");
part1(ram.clone());
part2(ram.clone());
}
fn part1(ram: RAM) {
let mut computers: Vec<IntCodeComputer> = (0..50).map(|address| IntCodeComputer::new(vec![address], ram.clone())).collect();
let mut buffer: VecDeque<Packet> = VecDeque::new();
loop {
for computer in &mut computers {
computer.add_input(&[-1]);
computer.run_until_input_empty();
if computer.get_output().len() >= 3 {
buffer.push_back(Packet::from(&computer.get_output()[0..3]));
computer.clear_n_output(3);
}
}
while let Some(packet) = buffer.pop_front() {
if packet.destination == 255 {
println!("Part 1: Finished with first y={} to 255", packet.y);
return;
}
computers[packet.destination].add_input(packet.to_input().as_slice());
}
}
}
fn part2(ram: RAM) {
let mut computers: Vec<IntCodeComputer> = (0..50).map(|address| IntCodeComputer::new(vec![address], ram.clone())).collect();
let mut buffer: VecDeque<Packet> = VecDeque::new();
let mut rounds_without_packets = 0;
let mut nat_content: Option<Packet> = None;
let mut pushed_to_first: Vec<Packet> = Vec::new();
loop {
for computer in &mut computers {
if computer.get_input().is_empty() {
computer.add_input(&[-1, -1, -1]);
}
computer.run_until_input_empty();
while computer.get_output().len() >= 3 {
buffer.push_back(Packet::from(&computer.get_output()[0..3]));
computer.clear_n_output(3);
}
}
if buffer.is_empty() {
rounds_without_packets += 1;
}
if let Some(ref energy_packet) = nat_content {
if rounds_without_packets > 5 {
if let Some(last) = pushed_to_first.last() {
if last == energy_packet {
println!("Part 2: Got the same packet twice. Y was {}", last.y);
return;
}
}
pushed_to_first.push(energy_packet.clone());
buffer.push_back(energy_packet.clone());
rounds_without_packets = 0;
}
}
while let Some(packet) = buffer.pop_front() {
if packet.destination == 255 {
nat_content = Some(Packet { destination: 0, x: packet.x, y: packet.y });
continue;
}
computers[packet.destination].add_input(packet.to_input().as_slice());
}
}
}
#[derive(Clone, PartialEq, Debug)]
struct Packet {
destination: usize,
x: i128,
y: i128,
}
impl Packet {
fn from(slice: &[i128]) -> Packet {
if slice.len() != 3 {
panic!("not enough for a packet")
}
Packet { destination: slice[0] as usize, x: slice[1], y: slice[2] }
}
fn to_input(&self) -> Vec<i128> {
vec![self.x, self.y]
}
}

44
src/tasks/day25.rs Normal file
View File

@@ -0,0 +1,44 @@
use std::io;
use crate::tasks::day05::{IntCodeComputer, load_ram};
#[allow(dead_code)]
pub fn run() {
let ram = load_ram("input/day25.txt");
let mut computer = IntCodeComputer::new(vec![], ram);
loop {
let done = computer.run_until_input_empty();
println!("{}", to_ascii(computer.get_output()));
computer.clear_output();
if done {
println!("Game Over");
return;
}
let input = read_line();
computer.set_input(&input);
}
// needed items:
// fixed point
// polygon
// candy cane
// shell
// result: 136839232
}
fn to_ascii(output: &[i128]) -> String {
output.iter().map(|i| (*i as u8) as char).collect()
}
fn read_line() -> Vec<i128> {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).unwrap();
if !buffer.is_ascii() {
panic!("'{}' is not ascii input", buffer);
}
buffer.chars().map(|c| c as i128).collect()
}

View File

@@ -16,7 +16,10 @@ pub mod day16;
pub mod day17;
pub mod day18;
pub mod day19;
pub mod day20;
pub mod day21;
#[allow(dead_code)]
pub mod day22;
pub mod day23;
pub mod day24;
pub mod day25;