I'm trying to write idiomatic and fast Rust code by solving AoC challenges this year! :-)
The input format in this problem is a list of lines each containing one string token (one of forward/down/up
) and one integer, separated by whitespace. The number of lines is not known in advance. Example:
forward 5
down 5
forward 8
up 3
down 8
forward 2
This is my Rust code for taking input:
use std::{
fs::File,
io::{BufRead, BufReader, Result as io_result},
};
enum Action {
F,
D,
U,
}
fn read_inputs() -> io_result<Vec<(Action, u32)>> {
let input_file = File::open("inputs/2.txt")?;
let file_reader = BufReader::new(input_file);
let inputs = file_reader
.lines()
.map(|line| {
let line_res = line.unwrap();
let mut res = line_res.split(" ");
let (action, value) = (res.next().unwrap(), res.next().unwrap());
return {
(
{
if action == "forward" {
Action::F
} else {
if action == "down" {
Action::D
} else {
Action::U
}
}
},
value.parse().unwrap(),
)
};
})
.collect::<Vec<(Action, u32)>>();
return Ok(inputs);
}
I'm unsure about my code for a number of reasons:
- Four unwraps in a single closure. If we could reduce the unwraps on
res.next()
, perhaps by specifying the line is guaranteed to contain a tuple of two tokens, it would be great. - The nesting depth of the ternary if-else is exceedingly high, not sure how to better it though.
- Perhaps if this was a very large file, would using
.lines()
still be reasonable or could we make this code faster? (preferably relying on Rust's zero cost abstractions)
Looking forward to advise on this code along these points and any other point as you deem fit.
The part of my code which solves the actual problem, I'm pretty happy with that honestly because I got to use a match
clause :-) Still if there's anything that could be improved here, in terms of idiomatic or faster Rust, please do advise!
fn part1(inputs: &Vec<(Action, u32)>) -> u32 {
let (mut horizontal, mut depth): (u32, u32) = (0, 0);
for (action, movement) in inputs {
match action {
Action::F => {
horizontal += movement;
}
Action::D => {
depth += movement;
}
Action::U => {
depth -= movement;
}
}
}
return horizontal * depth;
}
fn main() {
let inputs = read_inputs().expect("Input read correctly");
let answer = part1(&inputs);
println!("Answer: {}", answer)
}