summaryrefslogtreecommitdiff
path: root/2020
diff options
context:
space:
mode:
authorcos <cos>2020-12-03 08:04:08 +0100
committercos <cos>2020-12-04 10:25:55 +0100
commit31c4288918624c5af2adbe642e578d2cb70a0fe0 (patch)
tree527f6ea078647bf8a1f715cb238dbc5ed19a4524 /2020
parent616e32ade5e53fc2388fb942c5b2202f5f0b333b (diff)
downloadadventofcode-31c4288918624c5af2adbe642e578d2cb70a0fe0.zip
Add day03, 2020
Diffstat (limited to '2020')
-rw-r--r--2020/rust/Cargo.toml2
-rw-r--r--2020/rust/day03/Cargo.toml10
-rw-r--r--2020/rust/day03/src/main.rs151
3 files changed, 162 insertions, 1 deletions
diff --git a/2020/rust/Cargo.toml b/2020/rust/Cargo.toml
index febab99..6ecd67b 100644
--- a/2020/rust/Cargo.toml
+++ b/2020/rust/Cargo.toml
@@ -3,7 +3,7 @@ members = [
"aoc",
"day01",
"day02",
-# "day03",
+ "day03",
# "day04",
# "day05",
# "day06",
diff --git a/2020/rust/day03/Cargo.toml b/2020/rust/day03/Cargo.toml
new file mode 100644
index 0000000..e34114a
--- /dev/null
+++ b/2020/rust/day03/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day03"
+version = "0.1.0"
+authors = ["cos <cos>"]
+edition = "2018"
+
+[dependencies]
+aoc = { path = "../aoc" }
+anyhow = "1.0"
+thiserror = "1.0"
diff --git a/2020/rust/day03/src/main.rs b/2020/rust/day03/src/main.rs
new file mode 100644
index 0000000..900bd8a
--- /dev/null
+++ b/2020/rust/day03/src/main.rs
@@ -0,0 +1,151 @@
+use anyhow::{Result, anyhow};
+use std::env::args;
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::ops::AddAssign;
+use std::path::Path;
+use thiserror::Error;
+
+#[derive(Clone,Copy)]
+struct CoordPair {
+ x: usize,
+ y: usize,
+}
+
+impl AddAssign for CoordPair {
+ fn add_assign(&mut self, other: Self) {
+ *self = Self {
+ x: self.x + other.x,
+ y: self.y + other.y,
+ };
+ }
+}
+
+#[derive(Debug)]
+struct TreeMap {
+ width: usize,
+ height: usize,
+ map: Vec<bool>,
+}
+
+#[derive(Error, Debug)]
+pub enum TreeError {
+ #[error("Could not access TreeMap")]
+ Invalid,
+}
+
+impl TreeMap {
+ fn is_tree(&self, pos: CoordPair) -> Result<bool, TreeError> {
+ let mut p = pos;
+ p.x %= self.width;
+ self.map.get(p.y * self.width + p.x).copied().ok_or(TreeError::Invalid)
+ }
+}
+
+fn read_input<T: AsRef<Path>>(filename: T) -> Result<TreeMap> {
+ let f = File::open(filename)?;
+ let reader = BufReader::new(f);
+
+ let tree_map = reader.lines()
+ .fold(Ok(TreeMap { width: 0, height: 0, map: vec![] }), |acc, l| {
+ let line = l?;
+ let row: Result<Vec<bool>> = line.chars().map(|c| match c {
+ '#' => Ok(true),
+ '.' => Ok(false),
+ _ => Err(anyhow!("Invalid map character: '{}'", c)),
+ }).collect();
+
+ match acc {
+ Ok(mut a) => {
+ a.map.append(&mut row?);
+ a.height += 1;
+ Ok(a)
+ },
+ Err(err) => Err(err)
+ }
+ });
+ match tree_map {
+ Ok(mut tm) => {
+ tm.width = tm.map.len()/tm.height;
+ Ok(tm)
+ },
+ err => err,
+ }
+}
+
+fn part1(input: &TreeMap) -> Result<usize> {
+ let mut pos = CoordPair { x: 0, y: 0, };
+ let slope = CoordPair { x: 3, y: 1, };
+ let mut collision_count = 0;
+
+ while pos.y < input.height {
+ if input.is_tree(pos)? {
+ collision_count += 1;
+ }
+ pos += slope;
+ }
+
+ Ok(collision_count)
+}
+
+fn part2(input: &TreeMap) -> Result<usize> {
+ let slopes = vec![
+ CoordPair { x: 1, y: 1, },
+ CoordPair { x: 3, y: 1, },
+ CoordPair { x: 5, y: 1, },
+ CoordPair { x: 7, y: 1, },
+ CoordPair { x: 1, y: 2, },
+ ];
+
+ let res = slopes.iter().map(|slope| {
+ let mut pos = CoordPair { x: 0, y: 0, };
+ let mut collision_count = 0;
+
+ while pos.y < input.height {
+ if input.is_tree(pos)? {
+ collision_count += 1;
+ }
+ pos += *slope;
+ }
+
+ Ok(collision_count)
+ }).product();
+
+ res
+}
+
+fn main() {
+ let ( do_part_1, do_part_2 ) = aoc::do_parts();
+
+ let filename = match args().nth(1) {
+ Some(f) => f,
+ None => {
+ eprintln!("Missing input filename");
+ std::process::exit(1);
+ },
+ };
+ match read_input(filename) {
+ Ok(input) => {
+ if do_part_1 {
+ match part1(&input) {
+ Ok(solution) => println!("Part1: would encounter {} trees", solution),
+ Err(err) => {
+ eprintln!("Part1, no solution found: {}", err);
+ std::process::exit(1);
+ }
+ };
+ }
+ if do_part_2 {
+ match part2(&input) {
+ Ok(solution) => println!("Part2: {} is the product of all tree collisions", solution),
+ Err(err) => {
+ eprintln!("Part2, no solution found: {}", err);
+ std::process::exit(1);
+ }
+ };
+ }
+ },
+ Err(err) => eprintln!("Could not read input: {}", err),
+ }
+}
+