2020: switch to anyhow

This commit is contained in:
Antoine Martin 2020-12-14 18:08:16 +01:00
parent f148347e5b
commit d91165207f
18 changed files with 161 additions and 179 deletions

3
Cargo.lock generated
View file

@ -9,6 +9,9 @@ checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4"
[[package]]
name = "aoc"
version = "0.1.0"
dependencies = [
"anyhow",
]
[[package]]
name = "aoc2015"

View file

@ -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"

View file

@ -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);
}
}

View file

@ -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)]

View file

@ -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

View file

@ -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())

View file

@ -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| {

View file

@ -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),
}
}

View file

@ -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

View file

@ -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![

View file

@ -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),
})
}
}

View file

@ -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)?;

View file

@ -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

View file

@ -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();

View file

@ -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 })
}

View file

@ -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;

View file

@ -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,

View file

@ -1,5 +1,6 @@
use anyhow::Result;
use aoc::DayFunc;
use aoc::Result;
use aoc2020::day01;
use aoc2020::day02;