From 224001efc7aae4c5ec875f99c5f39e50c372c36a Mon Sep 17 00:00:00 2001 From: cos Date: Mon, 13 Dec 2021 07:46:50 +0100 Subject: Add day13, 2021 --- 2021/rust/Cargo.toml | 2 +- 2021/rust/day13/Cargo.toml | 9 +++ 2021/rust/day13/src/main.rs | 183 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 2021/rust/day13/Cargo.toml create mode 100644 2021/rust/day13/src/main.rs (limited to '2021') diff --git a/2021/rust/Cargo.toml b/2021/rust/Cargo.toml index 06ea192..8c18a33 100644 --- a/2021/rust/Cargo.toml +++ b/2021/rust/Cargo.toml @@ -12,7 +12,7 @@ members = [ "day10", "day11", "day12", -# "day13", + "day13", # "day14", # "day15", # "day16", diff --git a/2021/rust/day13/Cargo.toml b/2021/rust/day13/Cargo.toml new file mode 100644 index 0000000..8408975 --- /dev/null +++ b/2021/rust/day13/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day13" +version = "0.1.0" +authors = ["cos "] +edition = "2021" + +[dependencies] +aoc = { path = "../../../common/rust/aoc" } +anyhow = "1.0" diff --git a/2021/rust/day13/src/main.rs b/2021/rust/day13/src/main.rs new file mode 100644 index 0000000..c87373c --- /dev/null +++ b/2021/rust/day13/src/main.rs @@ -0,0 +1,183 @@ +use { + anyhow::{ + anyhow, + Context, + Result, + }, + std::{ + collections::BTreeSet, + env::args, + fmt::{ + Display, + Error as FmtError, + Formatter, + Result as FmtResult, + }, + fs::File, + io::{ + BufRead, + BufReader, + }, + path::Path, + }, +}; + +#[derive(Clone,Copy,Debug,Eq,Ord,PartialEq,PartialOrd)] +struct Point { + y: usize, // Please note that ordering is derived with y prior to x, as required for the + x: usize, // Display trait to work as currently implemented. +} + +impl Point { + fn fold(&self, fold: Fold) -> Self { + match fold { + Fold::X(num) => { + if self.x > num { + return Point{x: num - (self.x - num), y: self.y}; + } + } + Fold::Y(num) => { + if self.y > num { + return Point{x: self.x, y: num-(self.y - num)}; + } + } + } + *self + } +} + +#[derive(Clone,Copy)] +enum Fold { + X(usize), + Y(usize), +} + +struct Paper { + dots: BTreeSet, +} + +impl Paper { + fn fold(&self, fold: &Fold) -> Result { + let mut folded = Paper { + dots: BTreeSet::new(), + }; + + for point in &self.dots { + let mirror = point.fold(*fold); + if self.dots.contains(point) { + folded.dots.insert(mirror); + } + } + + Ok(folded) + } + + fn dot_count(&self) -> usize { + self.dots.len() + } +} + +impl Display for Paper { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let mut s = String::new(); + let (mut x, mut y) = (0, 0); + let max_x = self.dots.iter().map(|p| p.x).max().ok_or(FmtError)?; + for p in self.dots.iter() { + if p.y == y { + (x..p.x).for_each(|_| s += "." ); + } else { + (x..=max_x).for_each(|_| s += "." ); + s += "\n"; + for _ in y..(p.y-1) { + (0..=max_x).for_each(|_| s += "." ); + s += "\n"; + } + (0..p.x).for_each(|_| s += "." ); + } + s += "#"; + + x = p.x+1; + y = p.y; + if x > max_x { + x = 0; + y += 1; + s += "\n"; + } + } + (x..=max_x).for_each(|_| s += "." ); + write!(f, "{}", s) + } +} + +fn read_input>(filename: T) -> Result<(Paper, Vec)> { + let reader = BufReader::new(File::open(filename)?); + let mut lines = reader.lines(); + let mut dots: BTreeSet = BTreeSet::new(); + + for line in lines.by_ref() { + let l = line.map_err(|err| anyhow!("Failed reading from file: {}", err))?; + if l.is_empty() { + break; + } + + let values: Vec<_> = l.split(',') + .map(|v| v.parse().map_err(|err| anyhow!("{}: {}", l, err))).collect::>()?; + if values.len() != 2 { + return Err(anyhow!("Failed parsing coordinates from line: {}", l)); + } + let (x, y) = match (values.get(0), values.get(1)) { + (Some(parsed_x), Some(parsed_y)) => Ok((parsed_x, parsed_y)), + (_, _) => Err(anyhow!("Invalid coordinates: {}", l)), + }?; + dots.insert(Point{x: *x, y: *y}); + } + + let folds = lines.map(|line| { + let l = line?; + let s = l.strip_prefix("fold along ") + .ok_or_else(|| anyhow!("Could not find fold: {}", l))?; + let (axis, position) = s.split_once('=') + .ok_or_else(|| anyhow!("Could not parse fold: {}", l))?; + let num = position.parse() + .map_err(|err| anyhow!("Invalid fold position: {}, {}", l, err))?; + let fold = match axis { + "x" => Ok(Fold::X(num)), + "y" => Ok(Fold::Y(num)), + _ => Err(anyhow!("Invalid fold axis: {}", axis)), + }?; + + Ok(fold) + }).collect::>>()?; + + Ok((Paper { dots, }, folds)) +} + +fn part1(paper: &Paper, folds: &[Fold]) -> Result { + let fold = folds.get(0).ok_or_else(|| anyhow!("Could not find any fold"))?; + let folded = paper.fold(fold)?; + Ok(folded.dot_count()) +} + +fn part2(paper: Paper, folds: &[Fold]) -> Result { + let folded = folds.iter().fold(Ok(paper), |p: Result, fold| { + let folded = p?.fold(fold)?; + Ok(folded) + })?; + Ok(format!("{}", folded)) +} + +fn main() -> Result<()> { + let ( do_part_1, do_part_2 ) = aoc::do_parts(); + + let filename = args().nth(1).ok_or(anyhow!("Missing input filename"))?; + let (paper, folds) = read_input(filename).context("Could not read input")?; + if do_part_1 { + let solution = part1(&paper, &folds).context("No solution for part 1")?; + println!("Part1, solution found to be: {}", solution); + } + if do_part_2 { + let solution = part2(paper, &folds).context("No solution for part 2")?; + println!("Part2, solution found to be:\n{}", solution); + } + Ok(()) +} -- cgit v1.2.3