better rust

This commit is contained in:
Rüdiger Ludwig 2023-10-30 16:11:33 +01:00
parent 41b013b5e9
commit d5b6cb72cb
21 changed files with 61 additions and 112 deletions

View file

@ -6,10 +6,10 @@ fn format_path(day_num: usize, file: &str) -> String {
} }
pub fn read_string(day_num: usize, file: &str) -> io::Result<String> { pub fn read_string(day_num: usize, file: &str) -> io::Result<String> {
Ok(fs::read_to_string(format_path(day_num, file))?) fs::read_to_string(format_path(day_num, file))
} }
pub fn split_lines<'a>(lines: &'a str) -> impl Iterator<Item = &'a str> + 'a { pub fn split_lines(lines: &str) -> impl Iterator<Item = &'_ str> + '_ {
lines lines
.split('\n') .split('\n')
.with_position() .with_position()

View file

@ -14,7 +14,7 @@ pub const NEG_Z: UnitVector = UnitVector(Pos3::new(0, 0, -1));
impl UnitVector { impl UnitVector {
pub fn new(vector: Pos3<i8>) -> Option<Self> { pub fn new(vector: Pos3<i8>) -> Option<Self> {
vector.is_unit().then(|| UnitVector(vector)) vector.is_unit().then_some(UnitVector(vector))
} }
pub fn x(self) -> i8 { pub fn x(self) -> i8 {

View file

@ -14,7 +14,7 @@ impl DayTrait for Day {
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> { fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = split_lines(lines) let sum = split_lines(lines)
.map(|line| Rps::parse_line(line)) .map(Rps::parse_line)
.collect::<Result<Vec<_>, _>>()? .collect::<Result<Vec<_>, _>>()?
.into_iter() .into_iter()
.map(|(first, second)| second.asses_pair(&first)) .map(|(first, second)| second.asses_pair(&first))
@ -25,7 +25,7 @@ impl DayTrait for Day {
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> { fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = split_lines(lines) let sum = split_lines(lines)
.map(|line| Strategy::parse_line(line)) .map(Strategy::parse_line)
.collect::<Result<Vec<_>, _>>()? .collect::<Result<Vec<_>, _>>()?
.into_iter() .into_iter()
.map(|(first, second)| second.fullfill(&first).asses_pair(&first)) .map(|(first, second)| second.fullfill(&first).asses_pair(&first))

View file

@ -14,7 +14,7 @@ impl DayTrait for Day {
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> { fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = split_lines(lines) let sum = split_lines(lines)
.map(|line| find_double(line)) .map(find_double)
.map_ok(priority) .map_ok(priority)
.flatten_ok() .flatten_ok()
.fold_ok(0, |a, b| a + b)?; .fold_ok(0, |a, b| a + b)?;

View file

@ -15,7 +15,7 @@ impl DayTrait for Day {
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> { fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = split_lines(lines) let sum = split_lines(lines)
.map(|line| parse(line)) .map(parse)
.filter_ok(fully_contained) .filter_ok(fully_contained)
.fold_ok(0i64, |a, _| a + 1)?; .fold_ok(0i64, |a, _| a + 1)?;
Ok(ResultType::Integer(sum)) Ok(ResultType::Integer(sum))
@ -23,7 +23,7 @@ impl DayTrait for Day {
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> { fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
let sum = split_lines(lines) let sum = split_lines(lines)
.map(|line| parse(line)) .map(parse)
.filter_ok(overlaps) .filter_ok(overlaps)
.fold_ok(0i64, |a, _| a + 1)?; .fold_ok(0i64, |a, _| a + 1)?;
Ok(ResultType::Integer(sum)) Ok(ResultType::Integer(sum))

View file

@ -59,12 +59,10 @@ fn parse_crate(line: &str) -> Vec<Option<char>> {
.collect() .collect()
} }
fn parse_all_crates<'a>( fn parse_all_crates(line_it: &mut dyn Iterator<Item = &str>) -> Result<Vec<String>, CrateError> {
line_it: &mut dyn Iterator<Item = &'a str>,
) -> Result<Vec<String>, CrateError> {
let rows = line_it let rows = line_it
.take_while(|line| !line.is_empty()) .take_while(|line| !line.is_empty())
.map(|row| parse_crate(row)) .map(parse_crate)
.collect_vec(); .collect_vec();
let Some(stacks_count) = rows.iter().map(|row| row.len()).max() else { let Some(stacks_count) = rows.iter().map(|row| row.len()).max() else {
return Err(CrateError::NoCargoStacksGiven); return Err(CrateError::NoCargoStacksGiven);
@ -83,12 +81,10 @@ fn parse_all_crates<'a>(
Ok(stacks) Ok(stacks)
} }
fn parse<'a>(lines: &'a str) -> Result<(Vec<String>, Vec<Move>), CrateError> { fn parse(lines: &str) -> Result<(Vec<String>, Vec<Move>), CrateError> {
let mut iter = split_lines(lines); let mut iter = split_lines(lines);
let stacks = parse_all_crates(&mut iter)?; let stacks = parse_all_crates(&mut iter)?;
let moves: Vec<_> = iter let moves: Vec<_> = iter.map(Move::try_from).collect::<Result<_, _>>()?;
.map(|command| Move::try_from(command))
.collect::<Result<_, _>>()?;
Ok((stacks, moves)) Ok((stacks, moves))
} }
@ -194,7 +190,7 @@ mod test {
#[test] #[test]
fn test_parse_all_crates() -> Result<()> { fn test_parse_all_crates() -> Result<()> {
let lines = vec![ let lines = [
" [D] ", " [D] ",
"[N] [C] ", "[N] [C] ",
"[Z] [M] [P]", "[Z] [M] [P]",

View file

@ -44,7 +44,7 @@ fn find_marker(word: &str, marker_length: usize) -> Result<usize, MarkerError> {
if word.len() < marker_length { if word.len() < marker_length {
return Err(MarkerError::StringTooShort(word.to_owned(), marker_length)); return Err(MarkerError::StringTooShort(word.to_owned(), marker_length));
} }
let mut letter_count = vec![0; 26]; let mut letter_count = [0; 26];
let mut doubles = 0; let mut doubles = 0;
for new in word.chars().take(marker_length) { for new in word.chars().take(marker_length) {
let new = char_pos(new); let new = char_pos(new);

View file

@ -92,13 +92,13 @@ impl Rope {
* returns true if the whole rope moved, otherwise false * returns true if the whole rope moved, otherwise false
*/ */
pub fn move_rope(&mut self, head_direction: Direction) -> bool { pub fn move_rope(&mut self, head_direction: Direction) -> bool {
self.head = self.head + head_direction; self.head += head_direction;
let mut prev = self.head; let mut prev = self.head;
let mut knots_unmoved = self.knots.len(); let mut knots_unmoved = self.knots.len();
for knot in self.knots.iter_mut() { for knot in self.knots.iter_mut() {
if let Some(diff) = get_closer(*knot, prev) { if let Some(diff) = get_closer(*knot, prev) {
*knot = *knot + diff; *knot += diff;
prev = *knot; prev = *knot;
knots_unmoved -= 1; knots_unmoved -= 1;
} else { } else {

View file

@ -59,8 +59,8 @@ impl Operation {
let (input, _) = tag("new = old ")(input)?; let (input, _) = tag("new = old ")(input)?;
alt(( alt((
value(Operation::Squared, tag("* old")), value(Operation::Squared, tag("* old")),
preceded(char('*'), trim0(i64.map(|a| Operation::Times(a)))), preceded(char('*'), trim0(i64.map(Operation::Times))),
preceded(char('+'), trim0(i64.map(|a| Operation::Plus(a)))), preceded(char('+'), trim0(i64.map(Operation::Plus))),
))(input) ))(input)
} }

View file

@ -48,19 +48,7 @@ struct Path {
impl PartialOrd for Path { impl PartialOrd for Path {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match other.length.partial_cmp(&self.length) { Some(self.cmp(other))
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match other.height.partial_cmp(&self.height) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.pos.x().partial_cmp(&other.pos.x()) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
self.pos.y().partial_cmp(&other.pos.y())
} }
} }

View file

@ -147,7 +147,7 @@ impl Packets {
pub fn parse_all(lines: &str) -> Result<Vec<Packets>, PacketError> { pub fn parse_all(lines: &str) -> Result<Vec<Packets>, PacketError> {
split_lines(lines) split_lines(lines)
.filter(|line| !line.is_empty()) .filter(|line| !line.is_empty())
.map(|line| Packets::parse(line)) .map(Packets::parse)
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
} }
} }

View file

@ -874,7 +874,7 @@ impl<AG: ActorGroup> Ord for WeightedState<AG> {
impl<AG: ActorGroup> Deref for WeightedState<AG> { impl<AG: ActorGroup> Deref for WeightedState<AG> {
type Target = ValveState<AG>; type Target = ValveState<AG>;
fn deref<'b>(&'b self) -> &'b Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }
} }
@ -1029,7 +1029,7 @@ mod test {
result.closed, result.closed,
vec![Index(1), Index(2), Index(3), Index(7), Index(9)] vec![Index(1), Index(2), Index(3), Index(7), Index(9)]
); );
assert_eq!(result.potential, Flow(20 * 1)); assert_eq!(result.potential, Flow(20));
Ok(()) Ok(())
} }
@ -1091,8 +1091,8 @@ mod test {
assert_eq!(next.len(), 15); assert_eq!(next.len(), 15);
let result = &next[4]; let result = &next[4];
assert_eq!(result.flow, Flow(13 * 3)); assert_eq!(result.flow, Flow(13 * 3));
assert_eq!(result.potential, Flow(21 * 2 + 2 * 1)); assert_eq!(result.potential, Flow(21 * 2 + 2));
assert_eq!(result.flow_potential(), Flow(13 * 3 + 21 * 2 + 2 * 1)); assert_eq!(result.flow_potential(), Flow(13 * 3 + 21 * 2 + 2));
assert_eq!( assert_eq!(
result.closed, result.closed,
vec![Index(2), Index(3), Index(4), Index(7), Index(9)] vec![Index(2), Index(3), Index(4), Index(7), Index(9)]

View file

@ -15,31 +15,19 @@ impl DayTrait for Day {
} }
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> { fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
let pushes = Dispenser::new( let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
lines
.trim_end()
.chars()
.map(|c| Push::parse(c))
.try_collect()?,
)?;
let result = Day::run(pushes, 2022)?; let result = Day::run(pushes, 2022)?;
Ok(ResultType::Integer(result as i64)) Ok(ResultType::Integer(result))
} }
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> { fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
let pushes = Dispenser::new( let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
lines
.trim_end()
.chars()
.map(|c| Push::parse(c))
.try_collect()?,
)?;
let result = Day::run(pushes, 1000000000000)?; let result = Day::run(pushes, 1000000000000)?;
Ok(ResultType::Integer(result as i64)) Ok(ResultType::Integer(result))
} }
} }
@ -156,12 +144,11 @@ impl Rock {
let positions = blocks let positions = blocks
.iter() .iter()
.enumerate() .enumerate()
.map(|(y, line)| { .flat_map(|(y, line)| {
line.iter() line.iter()
.enumerate() .enumerate()
.filter_map(move |(x, block)| block.then_some((x, height - 1 - y))) .filter_map(move |(x, block)| block.then_some((x, height - 1 - y)))
}) })
.flatten()
.collect_vec(); .collect_vec();
Ok(Rock { Ok(Rock {
@ -299,8 +286,8 @@ impl Stack {
let mut rock = FallingRock::new(rock, self.height()); let mut rock = FallingRock::new(rock, self.height());
loop { loop {
let push = push_cycle.next(); let push = push_cycle.next();
rock = rock.try_push(push, &self); rock = rock.try_push(push, self);
match rock.try_drop(&self) { match rock.try_drop(self) {
Ok(next_rock) => rock = next_rock, Ok(next_rock) => rock = next_rock,
Err(rock) => { Err(rock) => {
let bottom = rock.bottom; let bottom = rock.bottom;
@ -413,13 +400,7 @@ mod test {
fn drop_one() -> Result<()> { fn drop_one() -> Result<()> {
let day = Day {}; let day = Day {};
let lines = read_string(day.get_day_number(), "example01.txt")?; let lines = read_string(day.get_day_number(), "example01.txt")?;
let pushes = Dispenser::new( let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
lines
.trim_end()
.chars()
.map(|c| Push::parse(c))
.try_collect()?,
)?;
let raw = read_string(day.get_day_number(), "blocks.txt")?; let raw = read_string(day.get_day_number(), "blocks.txt")?;
let rocks = Dispenser::new(Rock::parse(&raw)?)?; let rocks = Dispenser::new(Rock::parse(&raw)?)?;
@ -435,13 +416,7 @@ mod test {
fn drop_some() -> Result<()> { fn drop_some() -> Result<()> {
let day = Day {}; let day = Day {};
let lines = read_string(day.get_day_number(), "example01.txt")?; let lines = read_string(day.get_day_number(), "example01.txt")?;
let pushes = Dispenser::new( let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
lines
.trim_end()
.chars()
.map(|c| Push::parse(c))
.try_collect()?,
)?;
let result = Day::run(pushes, 10)?; let result = Day::run(pushes, 10)?;

View file

@ -38,7 +38,7 @@ struct Droplet(i64, i64, i64);
impl Droplet { impl Droplet {
fn parse(line: &str) -> Result<Droplet, DropletError> { fn parse(line: &str) -> Result<Droplet, DropletError> {
let split = line.split(",").collect_vec(); let split = line.split(',').collect_vec();
if split.len() != 3 { if split.len() != 3 {
return Err(DropletError::IllegalDroplet(line.to_owned())); return Err(DropletError::IllegalDroplet(line.to_owned()));
} }
@ -135,9 +135,7 @@ impl TryFrom<&str> for Blob {
type Error = DropletError; type Error = DropletError;
fn try_from(lines: &str) -> Result<Self, Self::Error> { fn try_from(lines: &str) -> Result<Self, Self::Error> {
let droplets = split_lines(lines) let droplets = split_lines(lines).map(Droplet::parse).try_collect()?;
.map(|line| Droplet::parse(line))
.try_collect()?;
Ok(Blob { droplets }) Ok(Blob { droplets })
} }
} }
@ -148,7 +146,7 @@ impl Blob {
return None; return None;
} }
let mut range = Ranges::new(&self.droplets.iter().next().unwrap()); let mut range = Ranges::new(self.droplets.iter().next().unwrap());
for droplet in self.droplets.iter().skip(1) { for droplet in self.droplets.iter().skip(1) {
range.extend(droplet); range.extend(droplet);
} }

View file

@ -114,7 +114,7 @@ impl Ingredients {
} }
fn inc(&self, mat: Material) -> Ingredients { fn inc(&self, mat: Material) -> Ingredients {
let mut next = self.0.clone(); let mut next = self.0;
next[mat as usize] += 1; next[mat as usize] += 1;
Ingredients(next) Ingredients(next)
} }
@ -351,7 +351,7 @@ impl Cabinet {
let _ = sender.send(result); let _ = sender.send(result);
}); });
done = done + 1; done += 1;
if done >= count { if done >= count {
break; break;
} }
@ -404,7 +404,7 @@ impl Simulation {
} }
pub fn no_production(mut self) -> Self { pub fn no_production(mut self) -> Self {
self.time = self.time - 1; self.time -= 1;
self.material = self.material + &self.robots; self.material = self.material + &self.robots;
self self
} }

View file

@ -84,7 +84,7 @@ impl Ring {
self.items self.items
.iter() .iter()
.position(|v| *v == value) .position(|v| *v == value)
.ok_or_else(|| RingError::ItemNotFound(value)) .ok_or(RingError::ItemNotFound(value))
} }
fn next_pos(&self, pos: usize) -> usize { fn next_pos(&self, pos: usize) -> usize {
@ -145,9 +145,7 @@ impl Ring {
} }
fn multiply(&mut self, arg: i64) { fn multiply(&mut self, arg: i64) {
self.items self.items.iter_mut().for_each(|value| *value *= arg);
.iter_mut()
.for_each(|value| *value = *value * arg);
} }
} }

View file

@ -16,8 +16,8 @@ use thiserror::Error;
const DAY_NUMBER: usize = 21; const DAY_NUMBER: usize = 21;
const ROOT: &'static str = "root"; const ROOT: &str = "root";
const HUMAN: &'static str = "humn"; const HUMAN: &str = "humn";
pub struct Day; pub struct Day;
impl DayTrait for Day { impl DayTrait for Day {
@ -91,11 +91,7 @@ impl MonkeyJob {
} }
fn parse(input: &str) -> IResult<&str, MonkeyJob> { fn parse(input: &str) -> IResult<&str, MonkeyJob> {
trim0(alt(( trim0(alt((i64.map(MonkeyJob::Yell), MonkeyJob::parse_operation))).parse(input)
i64.map(|val| MonkeyJob::Yell(val)),
MonkeyJob::parse_operation,
)))
.parse(input)
} }
fn perform(&self, troop: &Troop) -> Result<i64, MonkeyError> { fn perform(&self, troop: &Troop) -> Result<i64, MonkeyError> {

View file

@ -98,7 +98,7 @@ impl WorldMap {
value(None, char(' ')), value(None, char(' ')),
)); ));
let line = eol_terminated(many1(tile)); let line = eol_terminated(many1(tile));
let mut lines = many1(line).map(|tiles| WorldMap::new(tiles)); let mut lines = many1(line).map(WorldMap::new);
lines.parse(input) lines.parse(input)
} }
@ -147,7 +147,7 @@ enum Instruction {
impl Instruction { impl Instruction {
fn parse(input: &str) -> IResult<&str, Vec<Instruction>> { fn parse(input: &str) -> IResult<&str, Vec<Instruction>> {
many1(alt(( many1(alt((
usize.map(|v| Instruction::Walk(v)), usize.map(Instruction::Walk),
value(Instruction::Right, char('R')), value(Instruction::Right, char('R')),
value(Instruction::Left, char('L')), value(Instruction::Left, char('L')),
))) )))
@ -342,7 +342,7 @@ struct CubeWalker {
impl CubeWalker { impl CubeWalker {
fn get_side_length(world: &WorldMap) -> Result<usize, WorldError> { fn get_side_length(world: &WorldMap) -> Result<usize, WorldError> {
let width = world.width().ok_or_else(|| WorldError::NotAValidCube)?; let width = world.width().ok_or(WorldError::NotAValidCube)?;
let height = world.height(); let height = world.height();
if width % 3 == 0 && height % 4 == 0 && width / 3 == height / 4 { if width % 3 == 0 && height % 4 == 0 && width / 3 == height / 4 {
Ok(height / 4) Ok(height / 4)

View file

@ -1,7 +1,10 @@
use super::template::{DayTrait, ResultType}; use super::template::{DayTrait, ResultType};
use crate::common::{area::Area, direction::Direction, pos2::Pos2}; use crate::common::{area::Area, direction::Direction, pos2::Pos2};
use itertools::Itertools; use itertools::Itertools;
use std::{collections::HashMap, str::FromStr}; use std::{
collections::{hash_map::Entry, HashMap},
str::FromStr,
};
use thiserror::Error; use thiserror::Error;
const DAY_NUMBER: usize = 23; const DAY_NUMBER: usize = 23;
@ -143,14 +146,13 @@ impl FromStr for Field {
let elves: HashMap<Pos2<i32>, bool> = lines let elves: HashMap<Pos2<i32>, bool> = lines
.split('\n') .split('\n')
.enumerate() .enumerate()
.map(|(y, row)| { .flat_map(|(y, row)| {
row.chars().enumerate().filter_map(move |(x, c)| match c { row.chars().enumerate().filter_map(move |(x, c)| match c {
'.' => None, '.' => None,
'#' => Some(Ok((Pos2::new(x as i32, y as i32), true))), '#' => Some(Ok((Pos2::new(x as i32, y as i32), true))),
_ => Some(Err(FieldError::UnknownChar(c))), _ => Some(Err(FieldError::UnknownChar(c))),
}) })
}) })
.flatten()
.try_collect()?; .try_collect()?;
Ok(Field { Ok(Field {
@ -198,10 +200,10 @@ impl Field {
{ {
match self.check(elf, self.direction.iter()) { match self.check(elf, self.direction.iter()) {
MoveCheck::MoveTo(proposal, direction) => { MoveCheck::MoveTo(proposal, direction) => {
if proposals.contains_key(&proposal) { if let Entry::Vacant(e) = proposals.entry(proposal) {
proposals.remove(&proposal); e.insert((elf, direction));
} else { } else {
proposals.insert(proposal, (elf, direction)); proposals.remove(&proposal);
} }
} }
MoveCheck::NoNeighbors => { MoveCheck::NoNeighbors => {
@ -214,7 +216,7 @@ impl Field {
return false; return false;
} }
self.elves.extend(deactivate.into_iter()); self.elves.extend(deactivate);
for (to, (from, direction)) in proposals { for (to, (from, direction)) in proposals {
self.elves.remove(&from); self.elves.remove(&from);
@ -328,7 +330,7 @@ mod test {
Pos2::new(2, 5) Pos2::new(2, 5)
); );
let field: Field = lines.parse()?; let field: Field = lines.parse()?;
let elves = HashSet::from_iter(field.rounds(2).into_iter()); let elves = HashSet::from_iter(field.rounds(2));
assert_eq!(elves, expected); assert_eq!(elves, expected);
Ok(()) Ok(())

View file

@ -178,7 +178,7 @@ impl Valley {
let raw = input let raw = input
.iter() .iter()
.enumerate() .enumerate()
.map(|(y, row)| { .flat_map(|(y, row)| {
row.char_indices().filter_map(move |(x, c)| match c { row.char_indices().filter_map(move |(x, c)| match c {
'#' => { '#' => {
if x != 0 && x != row.len() - 1 { if x != 0 && x != row.len() - 1 {
@ -195,7 +195,6 @@ impl Valley {
_ => Some(Err(BlizzardError::IllegalChar(c))), _ => Some(Err(BlizzardError::IllegalChar(c))),
}) })
}) })
.flatten()
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
Ok(Blizzards::new(raw, width - 2, height)) Ok(Blizzards::new(raw, width - 2, height))
@ -208,7 +207,7 @@ impl Valley {
let mut queue = vec![start]; let mut queue = vec![start];
let mut next_queue = vec![]; let mut next_queue = vec![];
while let Some(current) = queue.pop() { while let Some(current) = queue.pop() {
for next_state in current.next_states(&self) { for next_state in current.next_states(self) {
if next_state.trip == trips { if next_state.trip == trips {
return Ok(next_state.time.get()); return Ok(next_state.time.get());
} }
@ -420,10 +419,7 @@ mod test {
assert_eq!(valley.storm.len(), 5); assert_eq!(valley.storm.len(), 5);
assert_eq!(valley.get_entry(), Pos2::new(0, 0)); assert_eq!(valley.get_entry(), Pos2::new(0, 0));
assert_eq!(valley.get_exit(), Pos2::new(4, 6)); assert_eq!(valley.get_exit(), Pos2::new(4, 6));
assert_eq!( assert!(!valley.storm.get(Time(3)).is_accessible(&Pos2::new(3, 2)));
valley.storm.get(Time(3)).is_accessible(&Pos2::new(3, 2)),
false
);
Ok(()) Ok(())
} }

View file

@ -86,7 +86,7 @@ impl FromStr for Snafu {
"=-012" "=-012"
.chars() .chars()
.position(|d| d == c) .position(|d| d == c)
.ok_or_else(|| SnafuError::IllegalChar(c)) .ok_or(SnafuError::IllegalChar(c))
}) })
.fold_ok(0, |acc, next| acc * 5 + (next as i64 - 2))?, .fold_ok(0, |acc, next| acc * 5 + (next as i64 - 2))?,
) )