summaryrefslogtreecommitdiffstats
path: root/src/2020
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-12-18 13:21:42 -0500
committerJesse Luehrs <doy@tozt.net>2021-12-18 13:21:42 -0500
commitd16795e44aeac17bee08363bd08c1a9672edf3d4 (patch)
tree3f70ddaf74b10db3f0e38c8a81838607f4e26a2c /src/2020
parentd1cacab50a8cab269da867ae900e903648b42cff (diff)
downloadadvent-of-code-d16795e44aeac17bee08363bd08c1a9672edf3d4.tar.gz
advent-of-code-d16795e44aeac17bee08363bd08c1a9672edf3d4.zip
factor out parsing
Diffstat (limited to 'src/2020')
-rw-r--r--src/2020/1/mod.rs20
-rw-r--r--src/2020/2/mod.rs35
-rw-r--r--src/2020/3/mod.rs26
-rw-r--r--src/2020/4/mod.rs82
-rw-r--r--src/2020/5/mod.rs26
-rw-r--r--src/2020/6/mod.rs26
-rw-r--r--src/2020/7/mod.rs37
-rw-r--r--src/2020/8/mod.rs30
-rw-r--r--src/2020/9/mod.rs24
-rw-r--r--src/2020/mod.rs36
10 files changed, 200 insertions, 142 deletions
diff --git a/src/2020/1/mod.rs b/src/2020/1/mod.rs
index 8ac5e14..31c4c5d 100644
--- a/src/2020/1/mod.rs
+++ b/src/2020/1/mod.rs
@@ -1,5 +1,8 @@
-pub fn part1() -> anyhow::Result<i64> {
- let ints: Vec<_> = data_ints!()?.collect();
+pub fn parse(fh: std::fs::File) -> anyhow::Result<Vec<i64>> {
+ Ok(crate::util::parse::ints(crate::util::parse::lines(fh)).collect())
+}
+
+pub fn part1(ints: Vec<i64>) -> anyhow::Result<i64> {
for i in &ints {
for j in &ints {
if i + j == 2020 {
@@ -10,8 +13,7 @@ pub fn part1() -> anyhow::Result<i64> {
Err(anyhow::anyhow!("no numbers summing to 2020 found"))
}
-pub fn part2() -> anyhow::Result<i64> {
- let ints: Vec<_> = data_ints!()?.collect();
+pub fn part2(ints: Vec<i64>) -> anyhow::Result<i64> {
for i in &ints {
for j in &ints {
for k in &ints {
@@ -26,6 +28,12 @@ pub fn part2() -> anyhow::Result<i64> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 445536);
- assert_eq!(part2().unwrap(), 138688160);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 1).unwrap()).unwrap()).unwrap(),
+ 445536
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 1).unwrap()).unwrap()).unwrap(),
+ 138688160
+ );
}
diff --git a/src/2020/2/mod.rs b/src/2020/2/mod.rs
index af82ff4..31dfeb5 100644
--- a/src/2020/2/mod.rs
+++ b/src/2020/2/mod.rs
@@ -1,8 +1,7 @@
use anyhow::Context as _;
use std::convert::TryInto as _;
-use std::io::BufRead as _;
-struct Line {
+pub struct Line {
c: char,
n1: usize,
n2: usize,
@@ -52,28 +51,30 @@ impl Line {
}
}
-pub fn part1() -> anyhow::Result<i64> {
- let lines = read_lines()?;
- let count = lines.iter().filter(|l| l.valid_part_1()).count();
- Ok(count.try_into()?)
+pub fn parse(
+ fh: std::fs::File,
+) -> anyhow::Result<impl Iterator<Item = Line>> {
+ Ok(crate::util::parse::lines(fh).map(|line| Line::parse(&line).unwrap()))
}
-pub fn part2() -> anyhow::Result<i64> {
- let lines = read_lines()?;
- let count = lines.iter().filter(|l| l.valid_part_2()).count();
+pub fn part1(lines: impl Iterator<Item = Line>) -> anyhow::Result<i64> {
+ let count = lines.filter(|l| l.valid_part_1()).count();
Ok(count.try_into()?)
}
-fn read_lines() -> anyhow::Result<Vec<Line>> {
- let f = data!()?;
- let f = std::io::BufReader::new(f);
- f.lines()
- .map(|l| Line::parse(&l.context("failed to read a line")?))
- .collect()
+pub fn part2(lines: impl Iterator<Item = Line>) -> anyhow::Result<i64> {
+ let count = lines.filter(|l| l.valid_part_2()).count();
+ Ok(count.try_into()?)
}
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 638);
- assert_eq!(part2().unwrap(), 699);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 2).unwrap()).unwrap()).unwrap(),
+ 638
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 2).unwrap()).unwrap()).unwrap(),
+ 699
+ );
}
diff --git a/src/2020/3/mod.rs b/src/2020/3/mod.rs
index fb4e93d..03ddfce 100644
--- a/src/2020/3/mod.rs
+++ b/src/2020/3/mod.rs
@@ -1,6 +1,6 @@
use crate::util::grid::*;
-struct Map {
+pub struct Map {
grid: Grid<bool>,
}
@@ -35,13 +35,19 @@ impl Map {
}
}
-pub fn part1() -> anyhow::Result<i64> {
- let map = Map::new(data_bool_grid!(b'#', b'.'));
+pub fn parse(fh: std::fs::File) -> anyhow::Result<Map> {
+ Ok(Map::new(crate::util::parse::bool_grid(
+ crate::util::parse::lines(fh),
+ b'#',
+ b'.',
+ )))
+}
+
+pub fn part1(map: Map) -> anyhow::Result<i64> {
map.trees_for_slope(1, 3)
}
-pub fn part2() -> anyhow::Result<i64> {
- let map = Map::new(data_bool_grid!(b'#', b'.'));
+pub fn part2(map: Map) -> anyhow::Result<i64> {
Ok(map.trees_for_slope(1, 1)?
* map.trees_for_slope(1, 3)?
* map.trees_for_slope(1, 5)?
@@ -51,6 +57,12 @@ pub fn part2() -> anyhow::Result<i64> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 292);
- assert_eq!(part2().unwrap(), 9354744432);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 3).unwrap()).unwrap()).unwrap(),
+ 292
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 3).unwrap()).unwrap()).unwrap(),
+ 9354744432
+ );
}
diff --git a/src/2020/4/mod.rs b/src/2020/4/mod.rs
index 5eace5a..f89993e 100644
--- a/src/2020/4/mod.rs
+++ b/src/2020/4/mod.rs
@@ -3,10 +3,40 @@ use anyhow::Context as _;
const REQUIRED_KEYS: &[&str] =
&["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"];
-pub fn part1() -> anyhow::Result<i64> {
- let batch = data_str!()?;
+pub fn parse(
+ fh: std::fs::File,
+) -> anyhow::Result<Vec<std::collections::HashMap<String, String>>> {
+ let mut res = vec![];
+ let mut cur = std::collections::HashMap::new();
+ for line in crate::util::parse::lines(fh) {
+ if line.is_empty() {
+ res.push(cur);
+ cur = std::collections::HashMap::new();
+ continue;
+ }
+
+ for field in line.split(' ') {
+ let mut parts = field.split(':');
+ let key = parts.next().with_context(|| {
+ format!("failed to parse field '{}'", field)
+ })?;
+ let value = parts.next().with_context(|| {
+ format!("failed to parse field '{}'", field)
+ })?;
+ cur.insert(key.to_string(), value.to_string());
+ }
+ }
+ if !cur.is_empty() {
+ res.push(cur);
+ }
+ Ok(res)
+}
+
+pub fn part1(
+ passports: Vec<std::collections::HashMap<String, String>>,
+) -> anyhow::Result<i64> {
let mut valid = 0;
- for passport in parse(&batch)? {
+ for passport in passports {
let mut cur_valid = true;
for key in REQUIRED_KEYS {
if !passport.contains_key(&key.to_string()) {
@@ -21,10 +51,11 @@ pub fn part1() -> anyhow::Result<i64> {
Ok(valid)
}
-pub fn part2() -> anyhow::Result<i64> {
- let batch = data_str!()?;
+pub fn part2(
+ passports: Vec<std::collections::HashMap<String, String>>,
+) -> anyhow::Result<i64> {
let mut valid = 0;
- for passport in parse(&batch)? {
+ for passport in passports {
let mut cur_valid = true;
for key in REQUIRED_KEYS {
match passport.get(&key.to_string()) {
@@ -47,35 +78,6 @@ pub fn part2() -> anyhow::Result<i64> {
Ok(valid)
}
-fn parse(
- batch: &str,
-) -> anyhow::Result<Vec<std::collections::HashMap<String, String>>> {
- let mut res = vec![];
- let mut cur = std::collections::HashMap::new();
- for line in batch.lines() {
- if line.is_empty() {
- res.push(cur);
- cur = std::collections::HashMap::new();
- continue;
- }
-
- for field in line.split(' ') {
- let mut parts = field.split(':');
- let key = parts.next().with_context(|| {
- format!("failed to parse field '{}'", field)
- })?;
- let value = parts.next().with_context(|| {
- format!("failed to parse field '{}'", field)
- })?;
- cur.insert(key.to_string(), value.to_string());
- }
- }
- if !cur.is_empty() {
- res.push(cur);
- }
- Ok(res)
-}
-
fn validate(key: &str, val: &str) -> anyhow::Result<bool> {
match key {
"byr" => match val.parse::<i32>() {
@@ -131,6 +133,12 @@ fn validate(key: &str, val: &str) -> anyhow::Result<bool> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 247);
- assert_eq!(part2().unwrap(), 145);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 4).unwrap()).unwrap()).unwrap(),
+ 247
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 4).unwrap()).unwrap()).unwrap(),
+ 145
+ );
}
diff --git a/src/2020/5/mod.rs b/src/2020/5/mod.rs
index e7c0f6e..b824e60 100644
--- a/src/2020/5/mod.rs
+++ b/src/2020/5/mod.rs
@@ -1,11 +1,13 @@
use anyhow::Context as _;
use std::convert::TryInto as _;
-pub fn part1() -> anyhow::Result<i64> {
- let input = data_str!()?;
+pub fn parse(fh: std::fs::File) -> anyhow::Result<impl Iterator<Item = i64>> {
+ Ok(crate::util::parse::lines(fh).map(|line| seat_id(&line).unwrap()))
+}
+
+pub fn part1(ids: impl Iterator<Item = i64>) -> anyhow::Result<i64> {
let mut max = 0;
- for line in input.lines() {
- let id = seat_id(line)?;
+ for id in ids {
if id > max {
max = id;
}
@@ -13,11 +15,9 @@ pub fn part1() -> anyhow::Result<i64> {
Ok(max)
}
-pub fn part2() -> anyhow::Result<i64> {
+pub fn part2(ids: impl Iterator<Item = i64>) -> anyhow::Result<i64> {
let mut seats = vec![false; 1024];
- let input = data_str!()?;
- for line in input.lines() {
- let id = seat_id(line)?;
+ for id in ids {
seats[id as usize] = true;
}
let first = seats
@@ -86,6 +86,12 @@ fn seat_id(desc: &str) -> anyhow::Result<i64> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 978);
- assert_eq!(part2().unwrap(), 727);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 5).unwrap()).unwrap()).unwrap(),
+ 978
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 5).unwrap()).unwrap()).unwrap(),
+ 727
+ );
}
diff --git a/src/2020/6/mod.rs b/src/2020/6/mod.rs
index 5e918d7..21279af 100644
--- a/src/2020/6/mod.rs
+++ b/src/2020/6/mod.rs
@@ -1,8 +1,13 @@
-pub fn part1() -> anyhow::Result<i64> {
- let input = data_str!()?;
+pub fn parse(
+ fh: std::fs::File,
+) -> anyhow::Result<impl Iterator<Item = String>> {
+ Ok(crate::util::parse::lines(fh))
+}
+
+pub fn part1(lines: impl Iterator<Item = String>) -> anyhow::Result<i64> {
let mut yes = std::collections::HashSet::new();
let mut total = 0;
- for line in input.lines() {
+ for line in lines {
if line.is_empty() {
total += yes.len() as i64;
yes = std::collections::HashSet::new();
@@ -16,14 +21,13 @@ pub fn part1() -> anyhow::Result<i64> {
Ok(total)
}
-pub fn part2() -> anyhow::Result<i64> {
- let input = data_str!()?;
+pub fn part2(lines: impl Iterator<Item = String>) -> anyhow::Result<i64> {
let mut yes = std::collections::HashSet::new();
for c in 'a'..='z' {
yes.insert(c);
}
let mut total = 0;
- for line in input.lines() {
+ for line in lines {
if line.is_empty() {
total += yes.len() as i64;
yes = std::collections::HashSet::new();
@@ -44,6 +48,12 @@ pub fn part2() -> anyhow::Result<i64> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 6930);
- assert_eq!(part2().unwrap(), 3585);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 6).unwrap()).unwrap()).unwrap(),
+ 6930
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 6).unwrap()).unwrap()).unwrap(),
+ 3585
+ );
}
diff --git a/src/2020/7/mod.rs b/src/2020/7/mod.rs
index b293f28..fbf2c43 100644
--- a/src/2020/7/mod.rs
+++ b/src/2020/7/mod.rs
@@ -2,9 +2,17 @@ use anyhow::Context as _;
type Graph = std::collections::HashMap<String, Vec<(i64, String)>>;
-pub fn part1() -> anyhow::Result<i64> {
- let input = data_str!()?;
- let graph = parse(&input)?;
+pub fn parse(fh: std::fs::File) -> anyhow::Result<Graph> {
+ let input = crate::util::parse::string(fh);
+ let mut graph = Graph::new();
+ for line in input.lines() {
+ let (k, v) = parse_line(line)?;
+ graph.insert(k, v);
+ }
+ Ok(graph)
+}
+
+pub fn part1(graph: Graph) -> anyhow::Result<i64> {
let mut colors = 0;
for color in graph.keys() {
if bag_contains(&graph, color, "shiny gold")? {
@@ -14,22 +22,11 @@ pub fn part1() -> anyhow::Result<i64> {
Ok(colors)
}
-pub fn part2() -> anyhow::Result<i64> {
- let input = data_str!()?;
- let graph = parse(&input)?;
+pub fn part2(graph: Graph) -> anyhow::Result<i64> {
// subtract 1 to not count the shiny gold bag itself
count_bags(&graph, "shiny gold").map(|i| i - 1)
}
-fn parse(input: &str) -> anyhow::Result<Graph> {
- let mut graph = Graph::new();
- for line in input.lines() {
- let (k, v) = parse_line(line)?;
- graph.insert(k, v);
- }
- Ok(graph)
-}
-
fn parse_line(line: &str) -> anyhow::Result<(String, Vec<(i64, String)>)> {
let main_rx = regex::Regex::new(r"^(.*) bags contain (.*)\.$").unwrap();
let contents_rx = regex::Regex::new(r"^([0-9]+) (.*) bags?").unwrap();
@@ -102,6 +99,12 @@ fn count_bags(graph: &Graph, color: &str) -> anyhow::Result<i64> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 169);
- assert_eq!(part2().unwrap(), 82372);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 7).unwrap()).unwrap()).unwrap(),
+ 169
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 7).unwrap()).unwrap()).unwrap(),
+ 82372
+ );
}
diff --git a/src/2020/8/mod.rs b/src/2020/8/mod.rs
index 0756fe5..052538e 100644
--- a/src/2020/8/mod.rs
+++ b/src/2020/8/mod.rs
@@ -21,7 +21,7 @@ impl std::str::FromStr for OpType {
}
#[derive(Clone, Copy)]
-struct Op {
+pub struct Op {
ty: OpType,
arg: i64,
}
@@ -43,9 +43,13 @@ impl std::str::FromStr for Op {
}
}
-pub fn part1() -> anyhow::Result<i64> {
- let input = data_str!()?;
- let opcodes = parse(&input)?;
+pub fn parse(fh: std::fs::File) -> anyhow::Result<Vec<Op>> {
+ crate::util::parse::lines(fh)
+ .map(|line| line.parse())
+ .collect()
+}
+
+pub fn part1(opcodes: Vec<Op>) -> anyhow::Result<i64> {
let (acc, success) = run(&opcodes)?;
if success {
return Err(anyhow::anyhow!("unexpectedly succeeded"));
@@ -53,9 +57,7 @@ pub fn part1() -> anyhow::Result<i64> {
Ok(acc)
}
-pub fn part2() -> anyhow::Result<i64> {
- let input = data_str!()?;
- let opcodes = parse(&input)?;
+pub fn part2(opcodes: Vec<Op>) -> anyhow::Result<i64> {
for i in 0..opcodes.len() {
match opcodes[i].ty {
OpType::Nop => {
@@ -80,10 +82,6 @@ pub fn part2() -> anyhow::Result<i64> {
Err(anyhow::anyhow!("failed to find corrupted opcode"))
}
-fn parse(input: &str) -> anyhow::Result<Vec<Op>> {
- input.lines().map(|line| line.parse()).collect()
-}
-
fn run(opcodes: &[Op]) -> anyhow::Result<(i64, bool)> {
let mut seen = vec![false; opcodes.len()];
let mut pc = 0;
@@ -126,6 +124,12 @@ fn run(opcodes: &[Op]) -> anyhow::Result<(i64, bool)> {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 1928);
- assert_eq!(part2().unwrap(), 1319);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 8).unwrap()).unwrap()).unwrap(),
+ 1928
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 8).unwrap()).unwrap()).unwrap(),
+ 1319
+ );
}
diff --git a/src/2020/9/mod.rs b/src/2020/9/mod.rs
index 9d1bc9f..c067ca0 100644
--- a/src/2020/9/mod.rs
+++ b/src/2020/9/mod.rs
@@ -1,7 +1,10 @@
-pub fn part1() -> anyhow::Result<i64> {
- const WINDOW: usize = 25;
+const WINDOW: usize = 25;
- let list: Vec<_> = data_ints!()?.collect();
+pub fn parse(fh: std::fs::File) -> anyhow::Result<Vec<i64>> {
+ Ok(crate::util::parse::ints(crate::util::parse::lines(fh)).collect())
+}
+
+pub fn part1(list: Vec<i64>) -> anyhow::Result<i64> {
for i in 0..(list.len() - WINDOW) {
let set = &list[i..i + WINDOW];
let n = list[i + WINDOW];
@@ -13,10 +16,7 @@ pub fn part1() -> anyhow::Result<i64> {
Err(anyhow::anyhow!("failed to find invalid number"))
}
-pub fn part2() -> anyhow::Result<i64> {
- const WINDOW: usize = 25;
-
- let list: Vec<_> = data_ints!()?.collect();
+pub fn part2(list: Vec<i64>) -> anyhow::Result<i64> {
let mut invalid = None;
for i in 0..(list.len() - WINDOW) {
let set = &list[i..i + WINDOW];
@@ -63,6 +63,12 @@ fn valid(set: &[i64], n: i64) -> bool {
#[test]
fn test() {
- assert_eq!(part1().unwrap(), 373803594);
- assert_eq!(part2().unwrap(), 51152360);
+ assert_eq!(
+ part1(parse(crate::util::data(2020, 9).unwrap()).unwrap()).unwrap(),
+ 373803594
+ );
+ assert_eq!(
+ part2(parse(crate::util::data(2020, 9).unwrap()).unwrap()).unwrap(),
+ 51152360
+ );
}
diff --git a/src/2020/mod.rs b/src/2020/mod.rs
index 7a41d7c..b4ea179 100644
--- a/src/2020/mod.rs
+++ b/src/2020/mod.rs
@@ -20,24 +20,24 @@ mod day9;
pub fn run(day: u8, puzzle: u8) -> anyhow::Result<i64> {
match (day, puzzle) {
- (1, 1) => day1::part1(),
- (1, 2) => day1::part2(),
- (2, 1) => day2::part1(),
- (2, 2) => day2::part2(),
- (3, 1) => day3::part1(),
- (3, 2) => day3::part2(),
- (4, 1) => day4::part1(),
- (4, 2) => day4::part2(),
- (5, 1) => day5::part1(),
- (5, 2) => day5::part2(),
- (6, 1) => day6::part1(),
- (6, 2) => day6::part2(),
- (7, 1) => day7::part1(),
- (7, 2) => day7::part2(),
- (8, 1) => day8::part1(),
- (8, 2) => day8::part2(),
- (9, 1) => day9::part1(),
- (9, 2) => day9::part2(),
+ (1, 1) => day1::part1(day1::parse(crate::util::data(2020, 1)?)?),
+ (1, 2) => day1::part2(day1::parse(crate::util::data(2020, 1)?)?),
+ (2, 1) => day2::part1(day2::parse(crate::util::data(2020, 2)?)?),
+ (2, 2) => day2::part2(day2::parse(crate::util::data(2020, 2)?)?),
+ (3, 1) => day3::part1(day3::parse(crate::util::data(2020, 3)?)?),
+ (3, 2) => day3::part2(day3::parse(crate::util::data(2020, 3)?)?),
+ (4, 1) => day4::part1(day4::parse(crate::util::data(2020, 4)?)?),
+ (4, 2) => day4::part2(day4::parse(crate::util::data(2020, 4)?)?),
+ (5, 1) => day5::part1(day5::parse(crate::util::data(2020, 5)?)?),
+ (5, 2) => day5::part2(day5::parse(crate::util::data(2020, 5)?)?),
+ (6, 1) => day6::part1(day6::parse(crate::util::data(2020, 6)?)?),
+ (6, 2) => day6::part2(day6::parse(crate::util::data(2020, 6)?)?),
+ (7, 1) => day7::part1(day7::parse(crate::util::data(2020, 7)?)?),
+ (7, 2) => day7::part2(day7::parse(crate::util::data(2020, 7)?)?),
+ (8, 1) => day8::part1(day8::parse(crate::util::data(2020, 8)?)?),
+ (8, 2) => day8::part2(day8::parse(crate::util::data(2020, 8)?)?),
+ (9, 1) => day9::part1(day9::parse(crate::util::data(2020, 9)?)?),
+ (9, 2) => day9::part2(day9::parse(crate::util::data(2020, 9)?)?),
// NEXT PART
_ => Err(anyhow::anyhow!("unknown puzzle {}-{}", day, puzzle)),
}