From 9892e3ebde304726903a1e5c358d05c2e343ea5e Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Tue, 19 Apr 2022 20:26:36 +0200 Subject: Refile for merging repos --- 2019/src/bin/day_16.rs | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 2019/src/bin/day_16.rs (limited to '2019/src/bin/day_16.rs') 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::() + ); + }); +} + +fn exit_on_failed_assertion(data: Result, message: &str) -> A { + match data { + Ok(data) => data, + Err(e) => { + eprintln!("{}: {}", message, e); + process::exit(1); + } + } +} + +fn parse(s: &str) -> Result, ParseIntError> { + s.chars().map(|c| c.to_string().parse::()).collect() +} + +fn transform(input: Vec, input_repeats: usize, fft_repeats: usize, offset: usize) -> Vec { + iter::successors( + Some( + input + .iter() + .cycle() + .take(input.len() * input_repeats) + .cloned() + .collect::>(), + ), + |input| Some(next_phase(input, offset)), + ) + .nth(fft_repeats) + .unwrap() + .into_iter() + .skip(offset) + .take(8) + .collect() +} + +fn next_phase(input: &Vec, offset: usize) -> Vec { + if offset > input.len() / 2 { + (0..input.len()) + .into_par_iter() + .map(|digit| { + if digit < offset { + 0 + } else { + input.iter().skip(digit).sum::().abs() % 10 + } + }) + .collect() + } else { + (0..input.len()) + .into_par_iter() + .map(|digit| { + input + .iter() + .zip(pattern(digit)) + .map(|(x, y)| x * y) + .sum::() + .abs() + % 10 + }) + .collect() + } +} + +fn pattern(digit: usize) -> impl Iterator { + 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) +} -- cgit v1.2.3