summaryrefslogtreecommitdiff
path: root/2019/src/bin/day_16.rs
diff options
context:
space:
mode:
Diffstat (limited to '2019/src/bin/day_16.rs')
-rw-r--r--2019/src/bin/day_16.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/2019/src/bin/day_16.rs b/2019/src/bin/day_16.rs
new file mode 100644
index 0000000..aa53127
--- /dev/null
+++ b/2019/src/bin/day_16.rs
@@ -0,0 +1,112 @@
+use rayon::prelude::*;
+use std::io;
+use std::io::prelude::*;
+use std::iter;
+use std::num::ParseIntError;
+use std::process;
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "Day 16: Flawed Frequency Transmission")]
+/// Performs the flawed frequency transform of a number.
+///
+/// See https://adventofcode.com/2019/day/16 for details.
+struct Opt {
+ /// the offset after which you start reading output
+ #[structopt(short = "o", long = "offset", default_value = "0")]
+ offset: usize,
+ input_repeats: usize,
+ fft_repeats: usize,
+}
+
+fn main() {
+ let stdin = io::stdin();
+ let opt = Opt::from_args();
+
+ stdin
+ .lock()
+ .lines()
+ .map(|x| exit_on_failed_assertion(x, "Error reading input"))
+ .map(|x| exit_on_failed_assertion(parse(&x), "Input was not a valid recipe"))
+ .for_each(|input| {
+ println!(
+ "{}",
+ transform(input, opt.input_repeats, opt.fft_repeats, opt.offset)
+ .into_iter()
+ .map(|c| c.to_string())
+ .collect::<String>()
+ );
+ });
+}
+
+fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A {
+ match data {
+ Ok(data) => data,
+ Err(e) => {
+ eprintln!("{}: {}", message, e);
+ process::exit(1);
+ }
+ }
+}
+
+fn parse(s: &str) -> Result<Vec<i32>, ParseIntError> {
+ s.chars().map(|c| c.to_string().parse::<i32>()).collect()
+}
+
+fn transform(input: Vec<i32>, input_repeats: usize, fft_repeats: usize, offset: usize) -> Vec<i32> {
+ iter::successors(
+ Some(
+ input
+ .iter()
+ .cycle()
+ .take(input.len() * input_repeats)
+ .cloned()
+ .collect::<Vec<i32>>(),
+ ),
+ |input| Some(next_phase(input, offset)),
+ )
+ .nth(fft_repeats)
+ .unwrap()
+ .into_iter()
+ .skip(offset)
+ .take(8)
+ .collect()
+}
+
+fn next_phase(input: &Vec<i32>, offset: usize) -> Vec<i32> {
+ if offset > input.len() / 2 {
+ (0..input.len())
+ .into_par_iter()
+ .map(|digit| {
+ if digit < offset {
+ 0
+ } else {
+ input.iter().skip(digit).sum::<i32>().abs() % 10
+ }
+ })
+ .collect()
+ } else {
+ (0..input.len())
+ .into_par_iter()
+ .map(|digit| {
+ input
+ .iter()
+ .zip(pattern(digit))
+ .map(|(x, y)| x * y)
+ .sum::<i32>()
+ .abs()
+ % 10
+ })
+ .collect()
+ }
+}
+
+fn pattern(digit: usize) -> impl Iterator<Item = i32> {
+ iter::repeat(0)
+ .take(digit + 1)
+ .chain(iter::repeat(1).take(digit + 1))
+ .chain(iter::repeat(0).take(digit + 1))
+ .chain(iter::repeat(-1).take(digit + 1))
+ .cycle()
+ .skip(1)
+}