2019: switch to anyhow

This commit is contained in:
Antoine Martin 2020-12-14 19:24:43 +01:00
parent d91165207f
commit deb808faf3
19 changed files with 84 additions and 114 deletions

1
Cargo.lock generated
View file

@ -34,6 +34,7 @@ dependencies = [
name = "aoc2019" name = "aoc2019"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"aoc", "aoc",
"criterion", "criterion",
] ]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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