2020: switch to anyhow
This commit is contained in:
parent
f148347e5b
commit
d91165207f
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -9,6 +9,9 @@ checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4"
|
|||
[[package]]
|
||||
name = "aoc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aoc2015"
|
||||
|
|
|
@ -7,3 +7,4 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
use std::env;
|
||||
|
||||
pub type Error = Box<dyn std::error::Error>;
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! err {
|
||||
($($string:expr),+) => (Box::<dyn std::error::Error>::from(format!($($string),+)))
|
||||
}
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
pub type DayFunc = fn() -> Result<String>;
|
||||
|
||||
|
@ -16,15 +10,15 @@ pub fn run(days: &[DayFunc]) -> Result<()> {
|
|||
|
||||
match args.next() {
|
||||
Some(arg) => {
|
||||
let day: usize = arg.parse().expect("Please provide a day number");
|
||||
let res = days[day - 1]().map_err(|e| err!("error running day specified: {}", e))?;
|
||||
let day: usize = arg.parse().context("couldn't parse day number")?;
|
||||
let res = days[day - 1]().context("error running day specified")?;
|
||||
println!("{}", res);
|
||||
}
|
||||
None => {
|
||||
for (i, day) in days.iter().enumerate() {
|
||||
let i = i + 1;
|
||||
println!("day{}: ", i);
|
||||
let res = day().map_err(|e| err!("error running day {}: {}", i, e))?;
|
||||
let res = day().with_context(|| format!("error running day {}", i))?;
|
||||
println!("{}", res);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashSet;
|
||||
use std::fmt::Write;
|
||||
|
||||
use aoc::{err, Result};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day01.txt");
|
||||
|
||||
|
@ -17,7 +17,7 @@ pub fn run() -> Result<String> {
|
|||
fn part1(input: &str) -> Result<i64> {
|
||||
let entries = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<i64>().map_err(|e| err!("{}", e)))
|
||||
.map(|line| line.parse::<i64>().map_err(anyhow::Error::new))
|
||||
.collect::<Result<Vec<i64>>>()?;
|
||||
|
||||
let (a, b) = find_2020_2_sum(&entries)?;
|
||||
|
@ -28,8 +28,8 @@ fn part1(input: &str) -> Result<i64> {
|
|||
fn part2(input: &str) -> Result<i64> {
|
||||
let entries = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<i64>().map_err(|e| err!("{}", e)))
|
||||
.collect::<Result<Vec<i64>>>()?;
|
||||
.map(|line| line.parse::<i64>().map_err(anyhow::Error::new))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let (a, b, c) = find_2020_3_sum(&entries)?;
|
||||
|
||||
|
@ -47,7 +47,7 @@ fn find_2020_2_sum(entries: &[i64]) -> Result<(i64, i64)> {
|
|||
}
|
||||
}
|
||||
|
||||
Err(err!("couldn't find 2 elements that sum to 2020"))
|
||||
Err(anyhow!("couldn't find 2 elements that sum to 2020"))
|
||||
}
|
||||
|
||||
fn find_2020_3_sum(entries: &[i64]) -> Result<(i64, i64, i64)> {
|
||||
|
@ -70,7 +70,7 @@ fn find_2020_3_sum(entries: &[i64]) -> Result<(i64, i64, i64)> {
|
|||
}
|
||||
}
|
||||
|
||||
Err(err!("couldn't find 2 elements that sum to 2020"))
|
||||
Err(anyhow!("couldn't find 2 elements that sum to 2020"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use aoc::{err, Result};
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day02.txt");
|
||||
|
||||
|
@ -44,28 +44,28 @@ impl PassPolicy {
|
|||
}
|
||||
|
||||
impl FromStr for PassPolicy {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let s = s.trim_end();
|
||||
|
||||
let space = s
|
||||
.find(' ')
|
||||
.ok_or_else(|| err!("couldn't parse password policy: didn't find space"))?;
|
||||
.context("couldn't parse password policy: didn't find space")?;
|
||||
let dash = s
|
||||
.find('-')
|
||||
.ok_or_else(|| err!("couldn't parse password policy: didn't find dash"))?;
|
||||
.context("couldn't parse password policy: didn't find dash")?;
|
||||
|
||||
let min_bound = s[..dash]
|
||||
.parse::<usize>()
|
||||
.map_err(|e| err!("couldn't parse range: {}", e))?;
|
||||
.context("couldn't parse range")?;
|
||||
let max_bound = s[(dash + 1)..space]
|
||||
.parse::<usize>()
|
||||
.map_err(|e| err!("couldn't parse range: {}", e))?;
|
||||
.context("couldn't parse range")?;
|
||||
|
||||
let colon = s
|
||||
.find(':')
|
||||
.ok_or_else(|| err!("couldn't parse password policy: didn't find colon"))?;
|
||||
.context("couldn't parse password policy: didn't find colon")?;
|
||||
|
||||
let letter = s.as_bytes()[colon - 1];
|
||||
|
||||
|
@ -92,7 +92,7 @@ pub fn run() -> Result<String> {
|
|||
fn part1(input: &str) -> Result<usize> {
|
||||
let policies = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<PassPolicy>().map_err(|e| err!("{}", e)))
|
||||
.map(|line| line.parse::<PassPolicy>())
|
||||
.collect::<Result<Vec<PassPolicy>>>()?;
|
||||
|
||||
Ok(policies
|
||||
|
@ -104,7 +104,7 @@ fn part1(input: &str) -> Result<usize> {
|
|||
fn part2(input: &str) -> Result<usize> {
|
||||
let policies = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<PassPolicy>().map_err(|e| err!("{}", e)))
|
||||
.map(|line| line.parse::<PassPolicy>())
|
||||
.collect::<Result<Vec<PassPolicy>>>()?;
|
||||
|
||||
Ok(policies
|
||||
|
|
|
@ -3,9 +3,11 @@ use std::iter::FromIterator;
|
|||
use std::ops::Index;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
const INPUT: &str = include_str!("../input/day03.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -14,13 +16,13 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let forest = input.parse()?;
|
||||
|
||||
Ok(count_trees(&forest, (3, 1)))
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let forest = input.parse()?;
|
||||
|
||||
let slopes = &[(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)];
|
||||
|
@ -89,9 +91,9 @@ impl Index<usize> for Forest {
|
|||
}
|
||||
|
||||
impl FromStr for Forest {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let trees = s
|
||||
.lines()
|
||||
.map(|line| line.chars().map(|c| matches!(c, '#')).collect())
|
||||
|
|
|
@ -3,9 +3,11 @@ use std::fmt::Write;
|
|||
use std::ops::RangeInclusive;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
const INPUT: &str = include_str!("../input/day04.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -14,7 +16,7 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_passports(input: &str) -> aoc::Result<Vec<Passport>> {
|
||||
fn get_passports(input: &str) -> Result<Vec<Passport>> {
|
||||
let mut passports: Vec<Passport> = Vec::new();
|
||||
|
||||
let mut passport = String::new();
|
||||
|
@ -35,13 +37,13 @@ fn get_passports(input: &str) -> aoc::Result<Vec<Passport>> {
|
|||
Ok(passports)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let passports = get_passports(input)?;
|
||||
|
||||
Ok(passports.iter().filter(|p| p.is_complete()).count())
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let passports = get_passports(input)?;
|
||||
|
||||
Ok(passports
|
||||
|
@ -89,9 +91,9 @@ impl Passport {
|
|||
}
|
||||
|
||||
impl FromStr for Passport {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let mut fields: HashMap<&str, String> = s
|
||||
.split_whitespace()
|
||||
.map(|f| {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::fmt::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day05.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -14,26 +14,24 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let seats = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<Seat>>>()
|
||||
.map_err(|e| err!("{}", e))?;
|
||||
.collect::<Result<Vec<Seat>>>()?;
|
||||
|
||||
seats
|
||||
.iter()
|
||||
.map(|seat| seat.id())
|
||||
.max()
|
||||
.ok_or_else(|| err!("0 seats processed"))
|
||||
.context("0 seats processed")
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let mut seats = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<Seat>>>()
|
||||
.map_err(|e| err!("{}", e))?;
|
||||
.collect::<Result<Vec<Seat>>>()?;
|
||||
|
||||
// Seats will be sorted by lexicographical order of fields thanks to `derive(PartialOrd, Ord)`,
|
||||
// which should produce the same result as a manual implementation of `Ord` and `PartialOrd`
|
||||
|
@ -49,7 +47,7 @@ fn part2(input: &str) -> aoc::Result<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
Err(err!("didn't find missing seat"))
|
||||
Err(anyhow!("didn't find missing seat"))
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -65,11 +63,11 @@ impl Seat {
|
|||
}
|
||||
|
||||
impl FromStr for Seat {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
if s.len() != 10 {
|
||||
return Err(err!("Seat encoding must be 10 chars long: {}", s));
|
||||
bail!("Seat encoding must be 10 chars long: {}", s);
|
||||
}
|
||||
|
||||
let (mut row_begin, mut row_end) = (0, 128);
|
||||
|
@ -90,7 +88,7 @@ impl FromStr for Seat {
|
|||
'R' => {
|
||||
col_begin += col_range;
|
||||
}
|
||||
_ => return Err(err!("Wrong char while decoding seat: `{}`", c)),
|
||||
_ => bail!("Wrong char while decoding seat: `{}`", c),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use std::collections::HashSet;
|
||||
use std::fmt::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
const INPUT: &str = include_str!("../input/day06.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -12,7 +14,7 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_groups(input: &str) -> aoc::Result<Vec<Group>> {
|
||||
fn get_groups(input: &str) -> Result<Vec<Group>> {
|
||||
let mut groups = Vec::new();
|
||||
|
||||
let mut answers = Vec::new();
|
||||
|
@ -36,7 +38,7 @@ fn get_groups(input: &str) -> aoc::Result<Vec<Group>> {
|
|||
Ok(groups)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let groups = get_groups(input)?;
|
||||
|
||||
Ok(groups
|
||||
|
@ -45,7 +47,7 @@ fn part1(input: &str) -> aoc::Result<usize> {
|
|||
.sum())
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let groups = get_groups(input)?;
|
||||
|
||||
Ok(groups
|
||||
|
|
|
@ -2,11 +2,11 @@ use std::collections::HashMap;
|
|||
use std::fmt::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day07.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -15,11 +15,11 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let bag_rules = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<BagRule>>>()
|
||||
.collect::<Result<Vec<BagRule>>>()
|
||||
.unwrap();
|
||||
|
||||
// create map with Key = color, Value = BagRule
|
||||
|
@ -39,11 +39,11 @@ fn part1(input: &str) -> aoc::Result<usize> {
|
|||
.count())
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let bag_rules = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<BagRule>>>()
|
||||
.collect::<Result<Vec<BagRule>>>()
|
||||
.unwrap();
|
||||
|
||||
// create map with Key = color, Value = BagRule
|
||||
|
@ -102,9 +102,9 @@ impl BagRule {
|
|||
}
|
||||
|
||||
impl FromStr for BagRule {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let words: Vec<&str> = s.split(' ').collect();
|
||||
|
||||
// let's assume our input is always valid for now
|
||||
|
@ -130,7 +130,7 @@ impl FromStr for BagRule {
|
|||
number => {
|
||||
let n = number
|
||||
.parse()
|
||||
.map_err(|e| err!("couldn't parse number `{}` in bag rule", e))?;
|
||||
.context("couldn't parse number in bag rule")?;
|
||||
|
||||
let adjective = words[1];
|
||||
let color = words[2];
|
||||
|
@ -169,7 +169,7 @@ mod tests {
|
|||
let bag_rules = PROVIDED1
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<BagRule>>>()
|
||||
.collect::<Result<Vec<BagRule>>>()
|
||||
.unwrap();
|
||||
|
||||
let expected = vec![
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::HashSet;
|
||||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day08.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -14,25 +14,25 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<i64> {
|
||||
fn part1(input: &str) -> Result<i64> {
|
||||
let instructions = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<Instruction>>>()?;
|
||||
.collect::<Result<Vec<Instruction>>>()?;
|
||||
|
||||
let mut interpreter = Interpreter::new(instructions);
|
||||
|
||||
Ok(match interpreter.run() {
|
||||
ExitStatus::InfiniteLoop(value) => value,
|
||||
ExitStatus::End(_) => return Err(err!("interpreter doesn't have an infinite loop")),
|
||||
ExitStatus::End(_) => bail!("interpreter doesn't have an infinite loop"),
|
||||
})
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<i64> {
|
||||
fn part2(input: &str) -> Result<i64> {
|
||||
let instructions = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<Vec<Instruction>>>()?;
|
||||
.collect::<Result<Vec<Instruction>>>()?;
|
||||
|
||||
for idx in 0..instructions.len() {
|
||||
let mut instructions = instructions.clone();
|
||||
|
@ -51,7 +51,7 @@ fn part2(input: &str) -> aoc::Result<i64> {
|
|||
}
|
||||
}
|
||||
|
||||
Err(err!(
|
||||
Err(anyhow!(
|
||||
"interpreter always had an infinite loop, no solution found"
|
||||
))
|
||||
}
|
||||
|
@ -110,21 +110,21 @@ enum Instruction {
|
|||
}
|
||||
|
||||
impl std::str::FromStr for Instruction {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
let space = s.find(' ').ok_or_else(|| err!("couldn't split on space"))?;
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let space = s.find(' ').context("couldn't split on space")?;
|
||||
|
||||
let inst = &s[..space];
|
||||
let arg = s[(space + 1)..]
|
||||
.parse()
|
||||
.map_err(|e| err!("couldn't parse argument for instruction: {}", e))?;
|
||||
.context("couldn't parse argument for instruction")?;
|
||||
|
||||
Ok(match inst {
|
||||
"acc" => Self::Acc(arg),
|
||||
"jmp" => Self::Jmp(arg),
|
||||
"nop" => Self::Nop(arg),
|
||||
_ => return Err(err!("unrecognized instruction `{}`", inst)),
|
||||
_ => bail!("unrecognized instruction `{}`", inst),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day09.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -27,7 +27,7 @@ fn find_pair_sum(data: &[u64], total: u64) -> Option<(u64, u64)> {
|
|||
None
|
||||
}
|
||||
|
||||
fn find_outlier(numbers: &[u64], preamble_size: usize) -> aoc::Result<(u64, usize)> {
|
||||
fn find_outlier(numbers: &[u64], preamble_size: usize) -> Result<(u64, usize)> {
|
||||
// start checking numbers after the preamble only
|
||||
for i in preamble_size..numbers.len() {
|
||||
let preamble = &numbers[(i - preamble_size)..i];
|
||||
|
@ -39,22 +39,21 @@ fn find_outlier(numbers: &[u64], preamble_size: usize) -> aoc::Result<(u64, usiz
|
|||
}
|
||||
}
|
||||
|
||||
Err(err!("couldn't find number with that property"))
|
||||
Err(anyhow!("couldn't find number with that property"))
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<u64> {
|
||||
fn part1(input: &str) -> Result<u64> {
|
||||
let numbers = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<u64>())
|
||||
.collect::<Result<Vec<u64>, _>>()
|
||||
.map_err(|e| err!("couldn't parse number: {}", e))?;
|
||||
.map(|line| line.parse::<u64>().map_err(anyhow::Error::new))
|
||||
.collect::<Result<Vec<u64>, _>>()?;
|
||||
|
||||
let (solution, _) = find_outlier(&numbers, 25)?;
|
||||
|
||||
Ok(solution)
|
||||
}
|
||||
|
||||
fn find_contiguous_range(numbers: &[u64], total: u64) -> aoc::Result<(u64, u64)> {
|
||||
fn find_contiguous_range(numbers: &[u64], total: u64) -> Result<(u64, u64)> {
|
||||
// compute cumulated sums for the whole range
|
||||
let (sums, _) = numbers.iter().fold((vec![0], 0), |(mut vec, acc), n| {
|
||||
let acc = acc + n;
|
||||
|
@ -74,15 +73,14 @@ fn find_contiguous_range(numbers: &[u64], total: u64) -> aoc::Result<(u64, u64)>
|
|||
}
|
||||
}
|
||||
|
||||
Err(err!("couldn't find number with that property"))
|
||||
Err(anyhow!("couldn't find number with that property"))
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<u64> {
|
||||
fn part2(input: &str) -> Result<u64> {
|
||||
let numbers = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<u64>())
|
||||
.collect::<Result<Vec<u64>, _>>()
|
||||
.map_err(|e| err!("couldn't parse number: {}", e))?;
|
||||
.map(|line| line.parse::<u64>().map_err(anyhow::Error::new))
|
||||
.collect::<Result<Vec<u64>, _>>()?;
|
||||
|
||||
let (outlier, idx) = find_outlier(&numbers, 25)?;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day10.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -14,17 +14,14 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let mut jolts = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
line.parse()
|
||||
.map_err(|e| err!("couldn't parse joltage: {}", e))
|
||||
})
|
||||
.collect::<aoc::Result<Vec<u64>>>()?;
|
||||
.map(|line| line.parse().map_err(anyhow::Error::new))
|
||||
.collect::<Result<Vec<u64>>>()?;
|
||||
|
||||
if jolts.is_empty() {
|
||||
return Err(err!("input was empty!"));
|
||||
bail!("input was empty!");
|
||||
}
|
||||
|
||||
// charging outlet can be added
|
||||
|
@ -80,17 +77,14 @@ fn find_possibilities(jolts: &[u64], possibilities: &mut HashMap<u64, usize>) ->
|
|||
possibilities_from_here
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let mut jolts = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
line.parse()
|
||||
.map_err(|e| err!("couldn't parse joltage: {}", e))
|
||||
})
|
||||
.collect::<aoc::Result<Vec<u64>>>()?;
|
||||
.map(|line| line.parse().map_err(anyhow::Error::new))
|
||||
.collect::<Result<Vec<u64>>>()?;
|
||||
|
||||
if jolts.is_empty() {
|
||||
return Err(err!("input was empty!"));
|
||||
bail!("input was empty!");
|
||||
}
|
||||
|
||||
// charging outlet can be added
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day11.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -13,7 +13,7 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<usize> {
|
||||
fn part1(input: &str) -> Result<usize> {
|
||||
let mut layout: Layout = input.parse()?;
|
||||
|
||||
let occupied_threshold = 4;
|
||||
|
@ -22,7 +22,7 @@ fn part1(input: &str) -> aoc::Result<usize> {
|
|||
Ok(layout.occupied_seats())
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<usize> {
|
||||
fn part2(input: &str) -> Result<usize> {
|
||||
let mut layout: Layout = input.parse()?;
|
||||
|
||||
let occupied_threshold = 5;
|
||||
|
@ -177,9 +177,9 @@ impl std::ops::IndexMut<usize> for Layout {
|
|||
}
|
||||
|
||||
impl std::str::FromStr for Layout {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let grid = s
|
||||
.lines()
|
||||
.map(|line| {
|
||||
|
@ -188,11 +188,11 @@ impl std::str::FromStr for Layout {
|
|||
'.' => Ok(Cell::Floor),
|
||||
'L' => Ok(Cell::EmptySeat),
|
||||
'#' => Ok(Cell::OccupiedSeat),
|
||||
_ => Err(err!("unknown char `{}`", c)),
|
||||
_ => Err(anyhow!("unknown char `{}`", c)),
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect::<aoc::Result<Grid>>()?;
|
||||
.collect::<Result<Grid>>()?;
|
||||
|
||||
let height = grid.len();
|
||||
let width = grid[0].len();
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day12.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -13,11 +13,11 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<i64> {
|
||||
fn part1(input: &str) -> Result<i64> {
|
||||
let actions: Vec<Action> = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<_>>()?;
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let mut ship = Ship::new();
|
||||
|
||||
|
@ -28,11 +28,11 @@ fn part1(input: &str) -> aoc::Result<i64> {
|
|||
Ok(ship.manhattan_distance())
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<i64> {
|
||||
fn part2(input: &str) -> Result<i64> {
|
||||
let actions: Vec<Action> = input
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<_>>()?;
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let mut ship = Ship::new();
|
||||
|
||||
|
@ -118,9 +118,9 @@ struct Action {
|
|||
}
|
||||
|
||||
impl std::str::FromStr for Action {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
debug_assert!(
|
||||
s.len() >= 2,
|
||||
"tried to parse action but it is too short: `{}`",
|
||||
|
@ -129,7 +129,7 @@ impl std::str::FromStr for Action {
|
|||
let letter = s
|
||||
.chars()
|
||||
.next()
|
||||
.ok_or_else(|| err!("couldn't parse action: empty string"))?;
|
||||
.context("couldn't parse action: empty string")?;
|
||||
|
||||
let kind = match letter {
|
||||
'N' => ActionKind::Move(Direction::North),
|
||||
|
@ -142,12 +142,10 @@ impl std::str::FromStr for Action {
|
|||
|
||||
'F' => ActionKind::Forward,
|
||||
|
||||
_ => return Err(err!("couldn't parse action with letter `{}`", letter)),
|
||||
_ => bail!("couldn't parse action with letter `{}`", letter),
|
||||
};
|
||||
|
||||
let arg = s[1..]
|
||||
.parse()
|
||||
.map_err(|e| err!("couldn't parse action arg: {}", e))?;
|
||||
let arg = s[1..].parse().context("couldn't parse action arg")?;
|
||||
|
||||
Ok(Self { kind, arg })
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day13.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -13,27 +13,27 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<u64> {
|
||||
fn part1(input: &str) -> Result<u64> {
|
||||
let mut lines = input.lines();
|
||||
|
||||
let earliest_timestamp = lines
|
||||
.next()
|
||||
.ok_or_else(|| err!("input was empty"))?
|
||||
.context("input was empty")?
|
||||
.parse::<u64>()
|
||||
.map_err(|e| err!("couldn't parse first line: {}", e))?;
|
||||
.context("couldn't parse first line")?;
|
||||
|
||||
let bus_ids = lines
|
||||
.next()
|
||||
.ok_or_else(|| err!("no second line"))?
|
||||
.context("no second line")?
|
||||
.split(',')
|
||||
.filter_map(|num| {
|
||||
if num == "x" {
|
||||
None
|
||||
} else {
|
||||
Some(num.parse::<u64>().map_err(|e| err!("{}", e)))
|
||||
Some(num.parse::<u64>().map_err(anyhow::Error::new))
|
||||
}
|
||||
})
|
||||
.collect::<aoc::Result<Vec<_>>>()?;
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let (bus_id, earliest_departure) = bus_ids
|
||||
.iter()
|
||||
|
@ -47,16 +47,16 @@ fn part1(input: &str) -> aoc::Result<u64> {
|
|||
Ok(bus_id * (earliest_departure - earliest_timestamp))
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<u64> {
|
||||
fn part2(input: &str) -> Result<u64> {
|
||||
let mut lines = input.lines();
|
||||
|
||||
// we don't need the first line anymore, skip it
|
||||
lines.next().ok_or_else(|| err!("input was empty"))?;
|
||||
lines.next().context("input was empty")?;
|
||||
|
||||
find_timestamp(lines.next().ok_or_else(|| err!("no second line"))?)
|
||||
find_timestamp(lines.next().context("no second line")?)
|
||||
}
|
||||
|
||||
fn find_timestamp(input: &str) -> aoc::Result<u64> {
|
||||
fn find_timestamp(input: &str) -> Result<u64> {
|
||||
let bus_ids: Vec<(u64, u64)> = input
|
||||
.split(',')
|
||||
.enumerate()
|
||||
|
@ -64,14 +64,14 @@ fn find_timestamp(input: &str) -> aoc::Result<u64> {
|
|||
if num == "x" {
|
||||
None
|
||||
} else {
|
||||
Some((idx as u64, num.parse::<u64>().map_err(|e| err!("{}", e))))
|
||||
Some((idx as u64, num.parse::<u64>().map_err(anyhow::Error::new)))
|
||||
}
|
||||
})
|
||||
.map(|(idx, res)| match res {
|
||||
Ok(num) => Ok((idx, num)),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.collect::<aoc::Result<_>>()?;
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
// previous constraints is empty for now
|
||||
let mut current_solution = 0;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
|
||||
use aoc::err;
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
|
||||
const INPUT: &str = include_str!("../input/day14.txt");
|
||||
|
||||
pub fn run() -> aoc::Result<String> {
|
||||
pub fn run() -> Result<String> {
|
||||
let mut res = String::with_capacity(128);
|
||||
|
||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||
|
@ -14,7 +14,7 @@ pub fn run() -> aoc::Result<String> {
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> aoc::Result<u64> {
|
||||
fn part1(input: &str) -> Result<u64> {
|
||||
let mut program: Program = input.parse()?;
|
||||
|
||||
program.run_part1()?;
|
||||
|
@ -22,7 +22,7 @@ fn part1(input: &str) -> aoc::Result<u64> {
|
|||
Ok(program.memory_sum())
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> aoc::Result<u64> {
|
||||
fn part2(input: &str) -> Result<u64> {
|
||||
let mut program: Program = input.parse()?;
|
||||
|
||||
program.run_part2()?;
|
||||
|
@ -175,9 +175,9 @@ impl BitMask {
|
|||
}
|
||||
|
||||
impl std::str::FromStr for BitMask {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let masks = s
|
||||
.chars()
|
||||
.rev()
|
||||
|
@ -187,10 +187,10 @@ impl std::str::FromStr for BitMask {
|
|||
'1' => Ok(Mask::One),
|
||||
'0' => Ok(Mask::Zero),
|
||||
'X' => Ok(Mask::Floating),
|
||||
_ => Err(err!("unknown character in mask: `{}`", c)),
|
||||
_ => Err(anyhow!("unknown character in mask: `{}`", c)),
|
||||
}
|
||||
})
|
||||
.collect::<aoc::Result<_>>()?;
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
Ok(BitMask { masks })
|
||||
}
|
||||
|
@ -203,23 +203,17 @@ enum Instruction {
|
|||
}
|
||||
|
||||
impl std::str::FromStr for Instruction {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let mut words = s.split(' ');
|
||||
|
||||
let first = words
|
||||
.next()
|
||||
.ok_or_else(|| err!("missing first word in instruction"))?;
|
||||
let second = words
|
||||
.next()
|
||||
.ok_or_else(|| err!("missing second word in instruction"))?;
|
||||
let third = words
|
||||
.next()
|
||||
.ok_or_else(|| err!("missing third word in instruction"))?;
|
||||
let first = words.next().context("missing first word in instruction")?;
|
||||
let second = words.next().context("missing second word in instruction")?;
|
||||
let third = words.next().context("missing third word in instruction")?;
|
||||
|
||||
if second != "=" {
|
||||
return Err(err!("expected `=` as second word in instruction: `{}`", s));
|
||||
bail!("expected `=` as second word in instruction: `{}`", s);
|
||||
}
|
||||
|
||||
if first == "mask" {
|
||||
|
@ -227,18 +221,16 @@ impl std::str::FromStr for Instruction {
|
|||
} else {
|
||||
let left_bracket = first
|
||||
.find('[')
|
||||
.ok_or_else(|| err!("couldn't find bracket in memory instruction"))?;
|
||||
.context("couldn't find bracket in memory instruction")?;
|
||||
let right_bracket = first
|
||||
.find(']')
|
||||
.ok_or_else(|| err!("couldn't find bracket in memory instruction"))?;
|
||||
.context("couldn't find bracket in memory instruction")?;
|
||||
|
||||
let offset = first[(left_bracket + 1)..right_bracket]
|
||||
.parse()
|
||||
.map_err(|e| err!("couldn't parse memory offset: `{}`", e))?;
|
||||
.context("couldn't parse memory offset")?;
|
||||
|
||||
let value = third
|
||||
.parse()
|
||||
.map_err(|e| err!("couldn't parse memory offset: `{}`", e))?;
|
||||
let value = third.parse().context("couldn't parse memory offset")?;
|
||||
|
||||
Ok(Self::MemWrite { offset, value })
|
||||
}
|
||||
|
@ -252,7 +244,7 @@ struct Program {
|
|||
}
|
||||
|
||||
impl Program {
|
||||
fn run_part1(&mut self) -> aoc::Result<()> {
|
||||
fn run_part1(&mut self) -> Result<()> {
|
||||
for inst in &self.instructions {
|
||||
match inst {
|
||||
Instruction::ChangeMask(bitmask) => self.current_mask = Some(bitmask.clone()),
|
||||
|
@ -263,7 +255,7 @@ impl Program {
|
|||
.insert(*offset, bitmask.apply_no_floating(*value));
|
||||
}
|
||||
None => {
|
||||
return Err(err!("tried to execute MemWrite but mask isn't initialized"))
|
||||
bail!("tried to execute MemWrite but mask isn't initialized")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -272,7 +264,7 @@ impl Program {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn run_part2(&mut self) -> aoc::Result<()> {
|
||||
fn run_part2(&mut self) -> Result<()> {
|
||||
for inst in &self.instructions {
|
||||
match inst {
|
||||
Instruction::ChangeMask(bitmask) => self.current_mask = Some(bitmask.clone()),
|
||||
|
@ -284,7 +276,7 @@ impl Program {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
return Err(err!("tried to execute MemWrite but mask isn't initialized"))
|
||||
bail!("tried to execute MemWrite but mask isn't initialized")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -299,13 +291,10 @@ impl Program {
|
|||
}
|
||||
|
||||
impl std::str::FromStr for Program {
|
||||
type Err = aoc::Error;
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> aoc::Result<Self> {
|
||||
let instructions = s
|
||||
.lines()
|
||||
.map(|line| line.parse())
|
||||
.collect::<aoc::Result<_>>()?;
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let instructions = s.lines().map(|line| line.parse()).collect::<Result<_>>()?;
|
||||
|
||||
Ok(Program {
|
||||
instructions,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use aoc::DayFunc;
|
||||
use aoc::Result;
|
||||
|
||||
use aoc2020::day01;
|
||||
use aoc2020::day02;
|
||||
|
|
Loading…
Reference in a new issue