Compare commits
6 Commits
79ea3c29d0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c1a48fe51 | |||
| 0f9d48314e | |||
| 14fc032ffc | |||
| 0089f4337c | |||
| c8cef9c0ce | |||
| 420b6152fb |
73
Cargo.lock
generated
73
Cargo.lock
generated
@@ -15,10 +15,11 @@ dependencies = [
|
|||||||
name = "aoc_2019"
|
name = "aoc_2019"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"modinverse",
|
"mod_exp",
|
||||||
"num-integer",
|
"modinverse",
|
||||||
"regex",
|
"num-integer",
|
||||||
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -39,7 +40,7 @@ version = "0.10.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -48,13 +49,45 @@ version = "2.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
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]]
|
[[package]]
|
||||||
name = "modinverse"
|
name = "modinverse"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633"
|
checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -63,8 +96,30 @@ version = "0.1.44"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-traits",
|
"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]]
|
[[package]]
|
||||||
@@ -73,7 +128,7 @@ version = "0.2.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ itertools = "0.10.3"
|
|||||||
regex = "1.5.5"
|
regex = "1.5.5"
|
||||||
num-integer = "0.1.44"
|
num-integer = "0.1.44"
|
||||||
modinverse = "0.1.1"
|
modinverse = "0.1.1"
|
||||||
|
mod_exp = "1.0.1"
|
||||||
|
|||||||
1
input/day23.txt
Normal file
1
input/day23.txt
Normal file
File diff suppressed because one or more lines are too long
1
input/day25.txt
Normal file
1
input/day25.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -3,5 +3,5 @@ extern crate core;
|
|||||||
mod tasks;
|
mod tasks;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tasks::day20::run();
|
tasks::day22::run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ impl IntCodeComputer {
|
|||||||
op.params[0].store(&mut self.ram, *v, self.relative_base_offset);
|
op.params[0].store(&mut self.ram, *v, self.relative_base_offset);
|
||||||
self.pc += 2;
|
self.pc += 2;
|
||||||
} else {
|
} else {
|
||||||
|
self.input_storage.clear();
|
||||||
return false;
|
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) {
|
pub fn clear_output(&mut self) {
|
||||||
self.output_storage.clear();
|
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] {
|
pub fn get_output(&self) -> &[i128] {
|
||||||
self.output_storage.as_slice()
|
self.output_storage.as_slice()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,30 @@
|
|||||||
use itertools::Itertools;
|
use std::collections::HashMap;
|
||||||
use num_integer::Integer;
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
const BASE_PATTERN: [i32; 4] = [0, 1, 0, -1];
|
||||||
const INPUT: &str = "59750530221324194853012320069589312027523989854830232144164799228029162830477472078089790749906142587998642764059439173975199276254972017316624772614925079238407309384923979338502430726930592959991878698412537971672558832588540600963437409230550897544434635267172603132396722812334366528344715912756154006039512272491073906389218927420387151599044435060075148142946789007756800733869891008058075303490106699737554949348715600795187032293436328810969288892220127730287766004467730818489269295982526297430971411865028098708555709525646237713045259603175397623654950719275982134690893685598734136409536436003548128411943963263336042840301380655801969822";
|
const INPUT: &str = "59750530221324194853012320069589312027523989854830232144164799228029162830477472078089790749906142587998642764059439173975199276254972017316624772614925079238407309384923979338502430726930592959991878698412537971672558832588540600963437409230550897544434635267172603132396722812334366528344715912756154006039512272491073906389218927420387151599044435060075148142946789007756800733869891008058075303490106699737554949348715600795187032293436328810969288892220127730287766004467730818489269295982526297430971411865028098708555709525646237713045259603175397623654950719275982134690893685598734136409536436003548128411943963263336042840301380655801969822";
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let input = to_digits(INPUT);
|
let input = to_digits(INPUT);
|
||||||
task1(input.clone());
|
task1(input.clone());
|
||||||
|
task2(to_digits("02935109699940807407585447034323"));
|
||||||
task2(input.clone());
|
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> {
|
fn to_digits(input: &str) -> Vec<i32> {
|
||||||
input
|
input
|
||||||
.chars()
|
.chars()
|
||||||
@@ -18,71 +32,88 @@ fn to_digits(input: &str) -> Vec<i32> {
|
|||||||
.collect_vec()
|
.collect_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn task1(input: Vec<i32>) -> String {
|
fn task2(input: Vec<i32>) -> String {
|
||||||
let p = [0, 1, 0, -1];
|
let big_input = iter::repeat(input.clone().into_iter())
|
||||||
let result = (0..100).fold(input, |old, _| {
|
.take(10_000)
|
||||||
(1..=old.len())
|
.flatten()
|
||||||
.map(|position| {
|
.collect_vec();
|
||||||
let pattern = p
|
|
||||||
.iter()
|
let mut s = S { input: big_input, cache: HashMap::new() };
|
||||||
.map(|x| std::iter::repeat(*x).take(position))
|
let result_position = format!("{}", input.split_at(7).0.iter().join("")).parse::<usize>().unwrap();
|
||||||
.flatten();
|
s.prep_after(result_position);
|
||||||
let val: i32 = old
|
let result = format!("{:.*}", 8, (0..8).map(|position| {
|
||||||
.iter()
|
let r = s.get(position + result_position, 100);
|
||||||
.zip(std::iter::repeat(pattern).flatten().skip(1))
|
r
|
||||||
.map(|(value, multiplier)| value * multiplier)
|
}).join(""));
|
||||||
.sum();
|
|
||||||
val.abs() % 10
|
println!("Task 2: {result}");
|
||||||
})
|
|
||||||
.collect_vec()
|
|
||||||
});
|
|
||||||
let result = format!("{:.*}", 8, result.iter().join(""));
|
|
||||||
println!("Task 1: {result}");
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn task2(input: Vec<i32>) -> String {
|
type V = i32;
|
||||||
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;
|
|
||||||
|
|
||||||
let number_rest = l / repeats_after;
|
struct S {
|
||||||
let part_rest: i32 = iter
|
input: Vec<V>,
|
||||||
.zip(iter::repeat(input.iter()).flatten())
|
cache: HashMap<(usize, usize), V>,
|
||||||
.take(number_rest)
|
}
|
||||||
.map(|(value, multiplier)| value * multiplier)
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
(part_rest + most_parts) % 10
|
impl S {
|
||||||
})
|
fn pattern(&self, position: usize, size: usize) -> Vec<i32> {
|
||||||
.collect_vec()
|
let pattern = BASE_PATTERN.iter().map(|x| iter::repeat(*x).take(position)).flatten();
|
||||||
});
|
let iter = iter::repeat(pattern).flatten().skip(1).take(size);
|
||||||
let offset = input[0..7].iter().join("").parse::<usize>().unwrap();
|
iter.collect()
|
||||||
let message = result[offset..offset + 8].iter().join("");
|
}
|
||||||
println!("Task 2: {}", message);
|
|
||||||
message
|
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)]
|
#[cfg(test)]
|
||||||
@@ -104,13 +135,30 @@ mod test {
|
|||||||
"52432133"
|
"52432133"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_1_solution() {
|
fn test_part_1_solution() {
|
||||||
assert_eq!(task1(to_digits(INPUT)), "84487724");
|
assert_eq!(task1(to_digits(INPUT)), "84487724");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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!(
|
assert_eq!(
|
||||||
task2(to_digits("02935109699940807407585447034323")),
|
task2(to_digits("02935109699940807407585447034323")),
|
||||||
"78725270"
|
"78725270"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let input = std::fs::read_to_string("input/day20.txt").unwrap();
|
let input = std::fs::read_to_string("input/day20.txt").unwrap();
|
||||||
let maze = Maze::from(&input, PortalField::curried_factory);
|
let maze = Maze::from(&input, PortalField::curried_factory);
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
use modinverse::modinverse;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use mod_exp::mod_exp;
|
||||||
|
use modinverse::modinverse;
|
||||||
|
|
||||||
|
use crate::tasks::day22::Cmd::{Cut, Deal, Stack};
|
||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
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 Deck = VecDeque<u16>;
|
||||||
type Size = i128;
|
type Size = i128;
|
||||||
|
|
||||||
fn task1(input: String) -> usize {
|
fn task1(input: &str) -> usize {
|
||||||
let deck_size = 10_007;
|
let deck_size = 10_007;
|
||||||
let mut deck: Deck = (0..deck_size).collect();
|
let mut deck: Deck = (0..deck_size).collect();
|
||||||
for line in input.lines() {
|
for line in input.lines() {
|
||||||
@@ -59,31 +63,50 @@ fn deal_with_increment(deck: Deck, n: usize) -> Deck {
|
|||||||
new.into_iter().collect()
|
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;
|
#[derive(Clone, Copy)]
|
||||||
results.insert(result, 0);
|
enum Cmd { Stack, Cut(i128), Deal(i128) }
|
||||||
|
|
||||||
let mut iteration = 1;
|
// I don't understand this solution but I copied it because I wanted the last star :> (c) AxlLind@github
|
||||||
while iteration <= num_iterations {
|
fn task2(input: &String) -> Size {
|
||||||
result = revert_iteration_find_start(&shuffles, deck_size, result);
|
const M: i128 = 119_315_717_514_047;
|
||||||
if let Some(last_iteration) = results.get(&result) {
|
const N: i128 = 101_741_582_076_661;
|
||||||
println!("check after {} iterations", iteration);
|
|
||||||
let iterations = iteration - last_iteration;
|
let commands: Vec<_> = input.lines().map(|line| {
|
||||||
let full_cycles_remaining = (num_iterations - iteration) / iterations;
|
if line.starts_with("deal into new stack") {
|
||||||
iteration += full_cycles_remaining * iterations;
|
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 {
|
} else {
|
||||||
results.insert(result, iteration);
|
panic!("'{line}' is illegal")
|
||||||
}
|
}
|
||||||
iteration += 1;
|
}).collect();
|
||||||
if iteration % 1000 == 0 {
|
|
||||||
println!("iteration {}", iteration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
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;
|
use crate::tasks::day22::task2;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
||||||
fn part1() {
|
fn part1() {
|
||||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
||||||
assert_eq!(7545, task1(input));
|
assert_eq!(7545, task1(&input));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part2() {
|
fn part2() {
|
||||||
let input = std::fs::read_to_string("input/day22.txt").unwrap();
|
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
100
src/tasks/day23.rs
Normal 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
44
src/tasks/day25.rs
Normal 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()
|
||||||
|
}
|
||||||
@@ -20,4 +20,6 @@ pub mod day20;
|
|||||||
pub mod day21;
|
pub mod day21;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod day22;
|
pub mod day22;
|
||||||
|
pub mod day23;
|
||||||
pub mod day24;
|
pub mod day24;
|
||||||
|
pub mod day25;
|
||||||
|
|||||||
Reference in New Issue
Block a user