2019: switch to anyhow
This commit is contained in:
parent
d91165207f
commit
deb808faf3
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -34,6 +34,7 @@ dependencies = [
|
||||||
name = "aoc2019"
|
name = "aoc2019"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"aoc",
|
"aoc",
|
||||||
"criterion",
|
"criterion",
|
||||||
]
|
]
|
||||||
|
|
|
@ -13,6 +13,7 @@ criterion = "0.3"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
aoc = { path = "../aoc" }
|
aoc = { path = "../aoc" }
|
||||||
|
anyhow = "1.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day01.txt");
|
const INPUT: &str = include_str!("../input/day01.txt");
|
||||||
|
|
||||||
|
@ -21,10 +21,7 @@ fn part1(input: &str) -> Result<u64> {
|
||||||
input
|
input
|
||||||
.lines()
|
.lines()
|
||||||
.map(|line| line.parse::<u64>())
|
.map(|line| line.parse::<u64>())
|
||||||
.map(|w| match w {
|
.map(|w| w.map(fuel_needed).map_err(anyhow::Error::new))
|
||||||
Ok(w) => Ok(fuel_needed(w)),
|
|
||||||
Err(e) => Err(Box::from(e)),
|
|
||||||
})
|
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +41,7 @@ fn part2(input: &str) -> Result<u64> {
|
||||||
input
|
input
|
||||||
.lines()
|
.lines()
|
||||||
.map(|line| line.parse::<u64>())
|
.map(|line| line.parse::<u64>())
|
||||||
.map(|w| match w {
|
.map(|w| w.map(cumulated_fuel_needed).map_err(anyhow::Error::new))
|
||||||
Ok(w) => Ok(cumulated_fuel_needed(w)),
|
|
||||||
Err(e) => Err(Box::from(e)),
|
|
||||||
})
|
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use crate::intcode::{parse_memory, Intcode};
|
use crate::intcode::{parse_memory, Intcode};
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ fn part1(mut input: Vec<i64>) -> Result<i64> {
|
||||||
|
|
||||||
intcode
|
intcode
|
||||||
.get_day02_output()
|
.get_day02_output()
|
||||||
.ok_or_else(|| err!("intcode memory was empty!"))
|
.context("intcode memory was empty!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(input: &[i64], res: i64) -> Result<i64> {
|
fn part2(input: &[i64], res: i64) -> Result<i64> {
|
||||||
|
@ -46,11 +45,11 @@ fn part2(input: &[i64], res: i64) -> Result<i64> {
|
||||||
return Ok(noun * 100 + verb);
|
return Ok(noun * 100 + verb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => return Err(err!("intcode memory was empty!")),
|
None => bail!("intcode memory was empty!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(err!(
|
Err(anyhow!(
|
||||||
"couldn't find noun/verb combination that produces {}",
|
"couldn't find noun/verb combination that produces {}",
|
||||||
res
|
res
|
||||||
))
|
))
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{bail, Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day03.txt");
|
const INPUT: &str = include_str!("../input/day03.txt");
|
||||||
|
|
||||||
|
@ -39,7 +37,7 @@ fn part1(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
|
||||||
})
|
})
|
||||||
.map(|inter| manhattan_distance(&inter, &Point { x: 0, y: 0 }))
|
.map(|inter| manhattan_distance(&inter, &Point { x: 0, y: 0 }))
|
||||||
.min()
|
.min()
|
||||||
.ok_or_else(|| err!("wire was empty"))
|
.context("wire was empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
|
fn part2(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
|
||||||
|
@ -72,19 +70,13 @@ fn part2(first_wire: &Wire, second_wire: &Wire) -> Result<u64> {
|
||||||
first_length += manhattan_distance(&seg1.begin, &seg1.end);
|
first_length += manhattan_distance(&seg1.begin, &seg1.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
min_dist.ok_or_else(|| err!("wire was empty"))
|
min_dist.context("wire was empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_wires(input: &str) -> Result<(Wire, Wire)> {
|
fn parse_wires(input: &str) -> Result<(Wire, Wire)> {
|
||||||
let mut lines = input.lines();
|
let mut lines = input.lines();
|
||||||
let first = lines
|
let first = lines.next().context("input missing a line")?.parse()?;
|
||||||
.next()
|
let second = lines.next().context("input missing a line")?.parse()?;
|
||||||
.ok_or_else(|| err!("input missing a line"))?
|
|
||||||
.parse()?;
|
|
||||||
let second = lines
|
|
||||||
.next()
|
|
||||||
.ok_or_else(|| err!("input missing a line"))?
|
|
||||||
.parse()?;
|
|
||||||
|
|
||||||
Ok((first, second))
|
Ok((first, second))
|
||||||
}
|
}
|
||||||
|
@ -93,15 +85,14 @@ fn parse_wires(input: &str) -> Result<(Wire, Wire)> {
|
||||||
struct Wire(Vec<Segment>);
|
struct Wire(Vec<Segment>);
|
||||||
|
|
||||||
impl FromStr for Wire {
|
impl FromStr for Wire {
|
||||||
type Err = Box<dyn Error>;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Wire> {
|
fn from_str(s: &str) -> Result<Wire> {
|
||||||
let moves = s
|
let moves = s
|
||||||
.trim_end()
|
.trim_end()
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(|m| m.parse())
|
.map(|m| m.parse().context("failed to parse wire"))
|
||||||
.collect::<Result<Vec<Move>>>()
|
.collect::<Result<Vec<Move>>>()?;
|
||||||
.map_err(|e| err!("failed to parse wire: {}", e))?;
|
|
||||||
|
|
||||||
let mut pos = Point { x: 0, y: 0 };
|
let mut pos = Point { x: 0, y: 0 };
|
||||||
|
|
||||||
|
@ -194,17 +185,15 @@ struct Move {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Move {
|
impl FromStr for Move {
|
||||||
type Err = Box<dyn Error>;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
let direction = s
|
let direction = s
|
||||||
.chars()
|
.chars()
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.ok_or_else(|| err!("couldn't get direction char in move: {}", s))?;
|
.context("couldn't get direction char in move")?;
|
||||||
|
|
||||||
let s = s
|
let s = s.get(1..).context("move missing length")?;
|
||||||
.get(1..)
|
|
||||||
.ok_or_else(|| err!("move missing length: {}", s))?;
|
|
||||||
|
|
||||||
let length = s.parse()?;
|
let length = s.parse()?;
|
||||||
|
|
||||||
|
@ -213,7 +202,7 @@ impl FromStr for Move {
|
||||||
'D' => Direction::Down,
|
'D' => Direction::Down,
|
||||||
'L' => Direction::Left,
|
'L' => Direction::Left,
|
||||||
'R' => Direction::Right,
|
'R' => Direction::Right,
|
||||||
_ => return Err(err!("couldn't parse direction: {}", direction)),
|
_ => bail!("couldn't parse direction: {}", direction),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Move { direction, length })
|
Ok(Move { direction, length })
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day04.txt");
|
const INPUT: &str = include_str!("../input/day04.txt");
|
||||||
|
|
||||||
|
@ -20,11 +19,11 @@ fn range(input: &str) -> Result<(usize, usize)> {
|
||||||
let mut range = input.trim_end().split('-');
|
let mut range = input.trim_end().split('-');
|
||||||
let begin = range
|
let begin = range
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| err!("invalid input: {}", input))?
|
.with_context(|| format!("invalid input: {}", input))?
|
||||||
.parse()?;
|
.parse()?;
|
||||||
let end = range
|
let end = range
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| err!("invalid input: {}", input))?
|
.with_context(|| format!("invalid input: {}", input))?
|
||||||
.parse()?;
|
.parse()?;
|
||||||
|
|
||||||
Ok((begin, end))
|
Ok((begin, end))
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use crate::intcode::Intcode;
|
use crate::intcode::Intcode;
|
||||||
|
|
||||||
|
@ -20,18 +19,14 @@ fn part1(input: &str) -> Result<i64> {
|
||||||
let mut intcode = Intcode::new(input)?;
|
let mut intcode = Intcode::new(input)?;
|
||||||
intcode.add_input(1);
|
intcode.add_input(1);
|
||||||
intcode.run()?;
|
intcode.run()?;
|
||||||
intcode
|
intcode.get_last_output().context("intcode gave no output")
|
||||||
.get_last_output()
|
|
||||||
.ok_or_else(|| err!("intcode gave no output"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(input: &str) -> Result<i64> {
|
fn part2(input: &str) -> Result<i64> {
|
||||||
let mut intcode = Intcode::new(input)?;
|
let mut intcode = Intcode::new(input)?;
|
||||||
intcode.add_input(5);
|
intcode.add_input(5);
|
||||||
intcode.run()?;
|
intcode.run()?;
|
||||||
intcode
|
intcode.get_last_output().context("intcode gave no output")
|
||||||
.get_last_output()
|
|
||||||
.ok_or_else(|| err!("intcode gave no output"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -3,8 +3,7 @@ use std::collections::HashSet;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day06.txt");
|
const INPUT: &str = include_str!("../input/day06.txt");
|
||||||
|
|
||||||
|
@ -42,7 +41,7 @@ fn part1(input: &str) -> Result<u64> {
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
let paren = line
|
let paren = line
|
||||||
.find(')')
|
.find(')')
|
||||||
.ok_or_else(|| err!("couldn't find `)` in line: {}", line))?;
|
.with_context(|| format!("couldn't find `)` in line: {}", line))?;
|
||||||
Ok((line[paren + 1..].to_string(), line[..paren].to_string()))
|
Ok((line[paren + 1..].to_string(), line[..paren].to_string()))
|
||||||
})
|
})
|
||||||
.collect::<Result<HashMap<String, String>>>()?;
|
.collect::<Result<HashMap<String, String>>>()?;
|
||||||
|
@ -61,7 +60,7 @@ fn part2(input: &str) -> Result<usize> {
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
let paren = line
|
let paren = line
|
||||||
.find(')')
|
.find(')')
|
||||||
.ok_or_else(|| err!("couldn't find `)` in line: {}", line))?;
|
.with_context(|| format!("couldn't find `)` in line: {}", line))?;
|
||||||
Ok((line[paren + 1..].to_string(), line[..paren].to_string()))
|
Ok((line[paren + 1..].to_string(), line[..paren].to_string()))
|
||||||
})
|
})
|
||||||
.collect::<Result<HashMap<String, String>>>()?;
|
.collect::<Result<HashMap<String, String>>>()?;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{bail, Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use crate::intcode::{parse_memory, Intcode};
|
use crate::intcode::{parse_memory, Intcode};
|
||||||
|
|
||||||
|
@ -59,7 +58,7 @@ fn part1(input: &str) -> Result<i64> {
|
||||||
|
|
||||||
output = intcode
|
output = intcode
|
||||||
.get_last_output()
|
.get_last_output()
|
||||||
.ok_or_else(|| err!("no output at end of pipeline!"))?;
|
.context("no output at end of pipeline!")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = std::cmp::max(res, output);
|
res = std::cmp::max(res, output);
|
||||||
|
@ -114,7 +113,7 @@ fn part2(input: &str) -> Result<i64> {
|
||||||
res = std::cmp::max(res, signal);
|
res = std::cmp::max(res, signal);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
None => return Err(err!("last amplifier halted without output")),
|
None => bail!("last amplifier halted without output"),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
for out in last.output.iter() {
|
for out in last.output.iter() {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const IMG_WIDTH: usize = 25;
|
const IMG_WIDTH: usize = 25;
|
||||||
const IMG_HEIGHT: usize = 6;
|
const IMG_HEIGHT: usize = 6;
|
||||||
|
@ -27,7 +25,7 @@ fn part1(image: &Image) -> Result<usize> {
|
||||||
.layers
|
.layers
|
||||||
.iter()
|
.iter()
|
||||||
.min_by_key(|l| l.pixels.iter().flatten().filter(|d| **d == 0).count())
|
.min_by_key(|l| l.pixels.iter().flatten().filter(|d| **d == 0).count())
|
||||||
.ok_or_else(|| err!("image had 0 layers..."))?;
|
.context("image had 0 layers...")?;
|
||||||
|
|
||||||
let one_count = most_zero_layer
|
let one_count = most_zero_layer
|
||||||
.pixels
|
.pixels
|
||||||
|
@ -74,7 +72,7 @@ impl fmt::Display for Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Image {
|
impl FromStr for Image {
|
||||||
type Err = Box<dyn Error>;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
let s = s.trim_end();
|
let s = s.trim_end();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use crate::intcode::{parse_memory, Intcode};
|
use crate::intcode::{parse_memory, Intcode};
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ fn part1(memory: Vec<i64>) -> Result<i64> {
|
||||||
intcode.run()?;
|
intcode.run()?;
|
||||||
intcode
|
intcode
|
||||||
.get_last_output()
|
.get_last_output()
|
||||||
.ok_or_else(|| err!("intcode output was empty!"))
|
.context("intcode output was empty!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(memory: Vec<i64>) -> Result<i64> {
|
fn part2(memory: Vec<i64>) -> Result<i64> {
|
||||||
|
@ -35,7 +34,7 @@ fn part2(memory: Vec<i64>) -> Result<i64> {
|
||||||
intcode.run()?;
|
intcode.run()?;
|
||||||
intcode
|
intcode
|
||||||
.get_last_output()
|
.get_last_output()
|
||||||
.ok_or_else(|| err!("intcode output was empty!"))
|
.context("intcode output was empty!")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day10.txt");
|
const INPUT: &str = include_str!("../input/day10.txt");
|
||||||
|
|
||||||
|
@ -85,7 +84,7 @@ fn part1(input: &str) -> Result<usize> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let best = best.ok_or_else(|| err!("zero asteroid provided"))?;
|
let best = best.context("zero asteroid provided")?;
|
||||||
Ok(best.len())
|
Ok(best.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{bail, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use crate::intcode::Intcode;
|
use crate::intcode::Intcode;
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@ fn part2(input: &str, res: &mut String) -> Result<()> {
|
||||||
|
|
||||||
fn write_board(res: &mut String, board: HashMap<Position, bool>) -> Result<()> {
|
fn write_board(res: &mut String, board: HashMap<Position, bool>) -> Result<()> {
|
||||||
if board.is_empty() {
|
if board.is_empty() {
|
||||||
return Err(err!("board was empty"));
|
bail!("board was empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
let min_x = board.keys().map(|p| p.x).min().unwrap();
|
let min_x = board.keys().map(|p| p.x).min().unwrap();
|
||||||
|
@ -106,13 +105,13 @@ impl Robot {
|
||||||
match color {
|
match color {
|
||||||
0 => board.insert(self.pos, false),
|
0 => board.insert(self.pos, false),
|
||||||
1 => board.insert(self.pos, true),
|
1 => board.insert(self.pos, true),
|
||||||
_ => return Err(err!("robot brain output different from 0 or 1")),
|
_ => bail!("robot brain output different from 0 or 1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
match direction {
|
match direction {
|
||||||
0 => self.turn_left(),
|
0 => self.turn_left(),
|
||||||
1 => self.turn_right(),
|
1 => self.turn_right(),
|
||||||
_ => return Err(err!("robot brain output different from 0 or 1")),
|
_ => bail!("robot brain output different from 0 or 1"),
|
||||||
};
|
};
|
||||||
self.move_forward();
|
self.move_forward();
|
||||||
self.brain.output.clear();
|
self.brain.output.clear();
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{anyhow, Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day12.txt");
|
const INPUT: &str = include_str!("../input/day12.txt");
|
||||||
|
|
||||||
|
@ -178,7 +176,7 @@ fn part2(mut planets: Vec<Planet>) -> Result<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(err!("planets never reached the same state twice"))
|
Err(anyhow!("planets never reached the same state twice"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -224,38 +222,38 @@ impl Planet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Planet {
|
impl FromStr for Planet {
|
||||||
type Err = Box<dyn Error>;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
let x_equals = s
|
let x_equals = s
|
||||||
.find("x=")
|
.find("x=")
|
||||||
.ok_or_else(|| err!("couldn't find x value for planet: {}", s))?;
|
.with_context(|| format!("couldn't find x value for planet: {}", s))?;
|
||||||
|
|
||||||
let comma = s
|
let comma = s
|
||||||
.find(',')
|
.find(',')
|
||||||
.ok_or_else(|| err!("couldn't find comma after x value: {}", s))?;
|
.with_context(|| format!("couldn't find comma after x value: {}", s))?;
|
||||||
|
|
||||||
let x = s[(x_equals + 2)..comma].parse()?;
|
let x = s[(x_equals + 2)..comma].parse()?;
|
||||||
let s = &s[(comma + 1)..];
|
let s = &s[(comma + 1)..];
|
||||||
|
|
||||||
let y_equals = s
|
let y_equals = s
|
||||||
.find("y=")
|
.find("y=")
|
||||||
.ok_or_else(|| err!("couldn't find y value for planet: {}", s))?;
|
.with_context(|| format!("couldn't find y value for planet: {}", s))?;
|
||||||
|
|
||||||
let comma = s
|
let comma = s
|
||||||
.find(',')
|
.find(',')
|
||||||
.ok_or_else(|| err!("couldn't find comma after y value: {}", s))?;
|
.with_context(|| format!("couldn't find comma after y value: {}", s))?;
|
||||||
|
|
||||||
let y = s[(y_equals + 2)..comma].parse()?;
|
let y = s[(y_equals + 2)..comma].parse()?;
|
||||||
let s = &s[(comma + 1)..];
|
let s = &s[(comma + 1)..];
|
||||||
|
|
||||||
let z_equals = s
|
let z_equals = s
|
||||||
.find("z=")
|
.find("z=")
|
||||||
.ok_or_else(|| err!("couldn't find z value for planet: {}", s))?;
|
.with_context(|| format!("couldn't find z value for planet: {}", s))?;
|
||||||
|
|
||||||
let bracket = s
|
let bracket = s
|
||||||
.find('>')
|
.find('>')
|
||||||
.ok_or_else(|| err!("couldn't find bracket after z value: {}", s))?;
|
.with_context(|| format!("couldn't find bracket after z value: {}", s))?;
|
||||||
|
|
||||||
let z = s[(z_equals + 2)..bracket].parse()?;
|
let z = s[(z_equals + 2)..bracket].parse()?;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Display, Write};
|
use std::fmt::{self, Display, Write};
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{bail, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use crate::intcode::{parse_memory, Intcode};
|
use crate::intcode::{parse_memory, Intcode};
|
||||||
|
|
||||||
|
@ -119,7 +118,7 @@ impl Tile {
|
||||||
2 => Tile::Block,
|
2 => Tile::Block,
|
||||||
3 => Tile::Paddle,
|
3 => Tile::Paddle,
|
||||||
4 => Tile::Ball,
|
4 => Tile::Ball,
|
||||||
_ => return Err(err!("couldn't associate number with tile: {}", n)),
|
_ => bail!("couldn't associate number with tile: {}", n),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(tile)
|
Ok(tile)
|
||||||
|
|
|
@ -2,8 +2,7 @@ use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aoc::err;
|
use anyhow::{Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../input/day14.txt");
|
const INPUT: &str = include_str!("../input/day14.txt");
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
|
||||||
for line in input.lines() {
|
for line in input.lines() {
|
||||||
let arrow = line
|
let arrow = line
|
||||||
.find(" => ")
|
.find(" => ")
|
||||||
.ok_or_else(|| err!("couldn't find arrow in line: {}", line))?;
|
.with_context(|| format!("couldn't find arrow in line: {}", line))?;
|
||||||
|
|
||||||
let elems = &line[..arrow];
|
let elems = &line[..arrow];
|
||||||
let elems = elems
|
let elems = elems
|
||||||
|
@ -30,7 +29,7 @@ fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
|
||||||
.map(|elem| {
|
.map(|elem| {
|
||||||
let space = elem
|
let space = elem
|
||||||
.find(' ')
|
.find(' ')
|
||||||
.ok_or_else(|| err!("couldn't find separator for elem {}", elem))?;
|
.with_context(|| format!("couldn't find separator for elem {}", elem))?;
|
||||||
let amount = elem[..space].parse()?;
|
let amount = elem[..space].parse()?;
|
||||||
let name = &elem[(space + 1)..];
|
let name = &elem[(space + 1)..];
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ fn parse_recipes(input: &str) -> Result<HashMap<String, Recipe>> {
|
||||||
let result = &line[(arrow + 4)..].trim_end();
|
let result = &line[(arrow + 4)..].trim_end();
|
||||||
let space = result
|
let space = result
|
||||||
.find(' ')
|
.find(' ')
|
||||||
.ok_or_else(|| err!("couldn't find separator for result {}", result))?;
|
.with_context(|| format!("couldn't find separator for result {}", result))?;
|
||||||
let result_amount = result[..space].parse()?;
|
let result_amount = result[..space].parse()?;
|
||||||
let result_name = &result[(space + 1)..];
|
let result_name = &result[(space + 1)..];
|
||||||
|
|
||||||
|
@ -76,7 +75,7 @@ fn get_ore_cost(
|
||||||
if in_stock < quantity {
|
if in_stock < quantity {
|
||||||
let recipe = recipes
|
let recipe = recipes
|
||||||
.get(&material)
|
.get(&material)
|
||||||
.ok_or_else(|| err!("couldn't find recipe for {}", material))?;
|
.with_context(|| format!("couldn't find recipe for {}", material))?;
|
||||||
|
|
||||||
let needed = quantity - in_stock;
|
let needed = quantity - in_stock;
|
||||||
let num_reactions = (needed + recipe.produced - 1) / recipe.produced;
|
let num_reactions = (needed + recipe.produced - 1) / recipe.produced;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use aoc::err;
|
use anyhow::{anyhow, bail, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
mod parameter;
|
mod parameter;
|
||||||
|
|
||||||
|
@ -8,7 +7,7 @@ use parameter::Parameter;
|
||||||
pub fn parse_memory(s: &str) -> Result<Vec<i64>> {
|
pub fn parse_memory(s: &str) -> Result<Vec<i64>> {
|
||||||
s.trim_end()
|
s.trim_end()
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(|x| x.parse().map_err(|e| err!("couldn't parse int: {}", e)))
|
.map(|x| x.parse().map_err(anyhow::Error::new))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ impl Intcode {
|
||||||
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
||||||
|
|
||||||
if let Parameter::Immediate(_) = dst {
|
if let Parameter::Immediate(_) = dst {
|
||||||
Err(err!("add: destination parameter can't be immediate"))
|
Err(anyhow!("add: destination parameter can't be immediate"))
|
||||||
} else {
|
} else {
|
||||||
Ok(Opcode::Add(op1, op2, dst))
|
Ok(Opcode::Add(op1, op2, dst))
|
||||||
}
|
}
|
||||||
|
@ -85,7 +84,9 @@ impl Intcode {
|
||||||
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
||||||
|
|
||||||
if let Parameter::Immediate(_) = dst {
|
if let Parameter::Immediate(_) = dst {
|
||||||
Err(err!("multiply: destination parameter can't be immediate"))
|
Err(anyhow!(
|
||||||
|
"multiply: destination parameter can't be immediate"
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Opcode::Multiply(op1, op2, dst))
|
Ok(Opcode::Multiply(op1, op2, dst))
|
||||||
}
|
}
|
||||||
|
@ -94,7 +95,7 @@ impl Intcode {
|
||||||
let dst = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
|
let dst = Parameter::new(mode1, self.memory.get(self.ip + 1).copied())?;
|
||||||
|
|
||||||
if let Parameter::Immediate(_) = dst {
|
if let Parameter::Immediate(_) = dst {
|
||||||
Err(err!("input: destination parameter can't be immediate"))
|
Err(anyhow!("input: destination parameter can't be immediate"))
|
||||||
} else {
|
} else {
|
||||||
Ok(Opcode::Input(dst))
|
Ok(Opcode::Input(dst))
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,9 @@ impl Intcode {
|
||||||
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
||||||
|
|
||||||
if let Parameter::Immediate(_) = dst {
|
if let Parameter::Immediate(_) = dst {
|
||||||
Err(err!("less than: destination parameter can't be immediate"))
|
Err(anyhow!(
|
||||||
|
"less than: destination parameter can't be immediate"
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Opcode::LessThan(op1, op2, dst))
|
Ok(Opcode::LessThan(op1, op2, dst))
|
||||||
}
|
}
|
||||||
|
@ -133,7 +136,7 @@ impl Intcode {
|
||||||
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
let dst = Parameter::new(mode3, self.memory.get(self.ip + 3).copied())?;
|
||||||
|
|
||||||
if let Parameter::Immediate(_) = dst {
|
if let Parameter::Immediate(_) = dst {
|
||||||
Err(err!("equals: destination parameter can't be immediate"))
|
Err(anyhow!("equals: destination parameter can't be immediate"))
|
||||||
} else {
|
} else {
|
||||||
Ok(Opcode::Equals(op1, op2, dst))
|
Ok(Opcode::Equals(op1, op2, dst))
|
||||||
}
|
}
|
||||||
|
@ -144,14 +147,14 @@ impl Intcode {
|
||||||
Ok(Opcode::AdjustRelBase(offset))
|
Ok(Opcode::AdjustRelBase(offset))
|
||||||
}
|
}
|
||||||
99 => Ok(Opcode::Halt),
|
99 => Ok(Opcode::Halt),
|
||||||
_ => Err(err!("unknown opcode: {}", opcode)),
|
_ => Err(anyhow!("unknown opcode: {}", opcode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(&mut self) -> Result<bool> {
|
fn exec(&mut self) -> Result<bool> {
|
||||||
loop {
|
loop {
|
||||||
if self.ip >= self.memory.len() {
|
if self.ip >= self.memory.len() {
|
||||||
return Err(err!("reached end of program without halting"));
|
bail!("reached end of program without halting");
|
||||||
}
|
}
|
||||||
|
|
||||||
let opcode = self.get_opcode()?;
|
let opcode = self.get_opcode()?;
|
||||||
|
@ -181,7 +184,7 @@ impl Intcode {
|
||||||
} else if self.wait_input {
|
} else if self.wait_input {
|
||||||
break Ok(false);
|
break Ok(false);
|
||||||
} else {
|
} else {
|
||||||
break Err(err!("tried to read input but it was empty"));
|
break Err(anyhow!("tried to read input but it was empty"));
|
||||||
};
|
};
|
||||||
dst.set(input, &mut self.memory, self.relative_base)?;
|
dst.set(input, &mut self.memory, self.relative_base)?;
|
||||||
|
|
||||||
|
@ -197,7 +200,7 @@ impl Intcode {
|
||||||
let val = test.get(&mut self.memory, self.relative_base)?;
|
let val = test.get(&mut self.memory, self.relative_base)?;
|
||||||
let dst = dst.get(&mut self.memory, self.relative_base)?;
|
let dst = dst.get(&mut self.memory, self.relative_base)?;
|
||||||
if dst < 0 {
|
if dst < 0 {
|
||||||
return Err(err!("dst must be a valid address: {}", dst));
|
bail!("dst must be a valid address: {}", dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if val != 0 {
|
if val != 0 {
|
||||||
|
@ -210,7 +213,7 @@ impl Intcode {
|
||||||
let val = test.get(&mut self.memory, self.relative_base)?;
|
let val = test.get(&mut self.memory, self.relative_base)?;
|
||||||
let dst = dst.get(&mut self.memory, self.relative_base)?;
|
let dst = dst.get(&mut self.memory, self.relative_base)?;
|
||||||
if dst < 0 {
|
if dst < 0 {
|
||||||
return Err(err!("dst must be a valid address: {}", dst));
|
bail!("dst must be a valid address: {}", dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use aoc::err;
|
use anyhow::{anyhow, Context, Result};
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Parameter {
|
pub enum Parameter {
|
||||||
|
@ -10,13 +9,13 @@ pub enum Parameter {
|
||||||
|
|
||||||
impl Parameter {
|
impl Parameter {
|
||||||
pub fn new(mode: i64, val: Option<i64>) -> Result<Self> {
|
pub fn new(mode: i64, val: Option<i64>) -> Result<Self> {
|
||||||
let val = val.ok_or_else(|| err!("parameter value out of bounds"))?;
|
let val = val.context("parameter value out of bounds")?;
|
||||||
let mode = mode % 10;
|
let mode = mode % 10;
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
0 => {
|
0 => {
|
||||||
if val < 0 {
|
if val < 0 {
|
||||||
Err(err!("negative value for position parameter: {}", val))
|
Err(anyhow!("negative value for position parameter: {}", val))
|
||||||
} else {
|
} else {
|
||||||
let val = val as usize;
|
let val = val as usize;
|
||||||
Ok(Parameter::Position(val))
|
Ok(Parameter::Position(val))
|
||||||
|
@ -24,7 +23,7 @@ impl Parameter {
|
||||||
}
|
}
|
||||||
1 => Ok(Parameter::Immediate(val)),
|
1 => Ok(Parameter::Immediate(val)),
|
||||||
2 => Ok(Parameter::Relative(val)),
|
2 => Ok(Parameter::Relative(val)),
|
||||||
_ => Err(err!("wrong mode for parameter: {}", mode)),
|
_ => Err(anyhow!("wrong mode for parameter: {}", mode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +74,7 @@ impl Parameter {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Parameter::Immediate(_) => Err(err!("cannot write to immediate parameter")),
|
Parameter::Immediate(_) => Err(anyhow!("cannot write to immediate parameter")),
|
||||||
Parameter::Relative(offset) => {
|
Parameter::Relative(offset) => {
|
||||||
let address = relative_base.wrapping_add(*offset as usize);
|
let address = relative_base.wrapping_add(*offset as usize);
|
||||||
let cell = memory.get_mut(address);
|
let cell = memory.get_mut(address);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
use aoc::DayFunc;
|
use aoc::DayFunc;
|
||||||
use aoc::Result;
|
|
||||||
|
|
||||||
use aoc2019::day01;
|
use aoc2019::day01;
|
||||||
use aoc2019::day02;
|
use aoc2019::day02;
|
||||||
|
|
Loading…
Reference in a new issue