From c99848b907d2d63577ffdc81fc11a77e4d328a92 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Tue, 19 Apr 2022 20:24:37 +0200 Subject: Refile for merging repos --- 2017/src/lib.rs | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 2017/src/lib.rs (limited to '2017/src/lib.rs') diff --git a/2017/src/lib.rs b/2017/src/lib.rs new file mode 100644 index 0000000..53d7d20 --- /dev/null +++ b/2017/src/lib.rs @@ -0,0 +1,225 @@ +extern crate structopt; +#[macro_use] +extern crate structopt_derive; +use structopt::StructOpt; + +use std::path::PathBuf; +use std::io::BufReader; +use std::io::prelude::*; +use std::fs::File; +use std::process; + +#[derive(StructOpt, Debug)] +#[structopt(name = "AOC2017", about = "An Advent of Code CLI arguments object.")] +struct AdventCli { + #[structopt(help = "Which part of the puzzle you are solving")] + part: u32, + + #[structopt(help = "Input file", parse(from_os_str))] + input: PathBuf +} + +pub struct AdventArgs { + pub part: u32, + pub input: Vec +} + +impl AdventArgs { + pub fn init() -> AdventArgs { + let opt = AdventCli::from_args(); + let input = match AdventArgs::read_file(&opt.input) { + Ok(input) => input, + Err(error) => { + // Typically I would think of exiting the program like + // this to be bad form, but in this case I'm matching the + // interface of StructOpt: if the input parameters were + // invalid, just quit now with a nice message. + eprintln!("Error reading file: {}", error); + process::exit(1); + } + }; + AdventArgs { + part: opt.part, + input: input + } + } + + fn read_file(file: &PathBuf) -> Result, std::io::Error> { + let file = File::open(file)?; + let file_reader = BufReader::new(file); + file_reader.lines() + .collect::, _>>() + .map(AdventArgs::preprocess_file_lines) + } + + fn preprocess_file_lines(lines: Vec) -> Vec { + lines.iter() + .filter(|line| line.len() > 0) + .map(|line| line.trim_right().to_string()) + .collect() + } + + pub fn one_number_input(&self) -> Result { + self.input[0].parse() + } + pub fn number_per_line_input(&self) -> Result, std::num::ParseIntError> { + self.input.iter().map(|line| line.parse()).collect() + } +} + +pub fn parse_space_separated_ints(line: &String) -> Result, std::num::ParseIntError> { + line.split_whitespace() + .map(|x| x.parse::()) + .collect() +} + + +#[derive(Hash, Eq, PartialEq, Debug, Clone, Copy)] +pub struct Point { + pub x: i32, + pub y: i32 +} + +impl Point { + pub fn up(&self) -> Point { + Point { + y: self.y-1, + ..*self + } + } + + pub fn down(&self) -> Point { + Point { + y: self.y+1, + ..*self + } + } + + pub fn left(&self) -> Point { + Point { + x: self.x-1, + ..*self + } + } + + pub fn right(&self) -> Point { + Point { + x: self.x+1, + ..*self + } + } + + pub fn shift(&self, dir: &Direction) -> Point { + use Direction::*; + + match *dir { + Right => self.right(), + Left => self.left(), + Up => self.up(), + Down => self.down() + } + } +} + +#[derive(Debug)] +pub enum Direction { + Left, + Up, + Down, + Right +} + +impl Direction { + pub fn rotate_left(&self) -> Direction { + use Direction::*; + match *self { + Right => Up, + Up => Left, + Left => Down, + Down => Right + } + } + + pub fn rotate_right(&self) -> Direction { + use Direction::*; + match *self { + Right => Down, + Up => Right, + Left => Up, + Down => Left + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Point3d { + pub x: i32, + pub y: i32, + pub z: i32 +} + +impl std::ops::Add for Point3d { + type Output = Point3d; + + fn add(self, other: Point3d) -> Point3d { + Point3d { + x: self.x + other.x, + y: self.y + other.y, + z: self.z + other.z + } + } + +} + +impl Point3d { + pub fn manhattan_distance(&self) -> i32 { + self.x.abs() + self.y.abs() + self.z.abs() + } +} + +pub fn knot_hash(input: &String) -> String { + let suffix: [usize; 5] = [17, 31, 73, 47, 23]; + let lengths: Vec = input.as_bytes() + .iter().map(|&x| x as usize) + .chain(suffix.iter().cloned()) + .collect(); + + let mut position = 0; + let mut list: Vec = (0..256).collect(); + + for i in 0..64 { + let skip = lengths.len() * i; + knot_hash_round(&mut list, &lengths, &mut position, skip); + } + + let mut current_char = 0; + let mut result = String::new(); + for (i, l) in list.iter().enumerate() { + current_char = current_char ^ l; + if i % 16 == 15 { + result.push_str(&format!("{:02x}", current_char)); + current_char = 0; + } + } + result +} + +fn knot_hash_round(list: &mut Vec, lengths: &Vec, position: &mut usize, skip: usize) { + for (inner_skip, &length) in lengths.iter().enumerate() { + knot_hash_reverse_segment(list, *position, length); + *position = (*position + length + skip + inner_skip) % list.len(); + } +} + +fn knot_hash_reverse_segment(list: &mut Vec, position: usize, length: usize) { + let mut a = position; + let mut b = position + length - 1; + let len = list.len(); + while a < b { + list.swap(a%len, b%len); + + a += 1; + b -= 1; + } +} + -- cgit v1.2.3