# Project Euler #11“numbers in a grid” in Rust

To learn more about Rust, I implemented Project Euler #11 "Numbers in a grid". Contrary to some people, I prefer not having the actual data grid in my code, so I put it in a file, which I read in the beginning.

I'm wondering how 'Rustic' my code is. Specially I wonder about the following points:

• How to most concisely read a table of integers into a data structure? Is it possible to create an array of a certain size? Do I need all this spliting and from_str mapping?
• Have I handled the array indices in the right way? I'm not used to needing all this casting.
• I my max function sufficiently generic?

use std::io;
fn max(a:int, b:int) -> int {if a > b {a} else {b}}
fn main() {
let n = 20;
let mut ar:Vec<Vec<int>> = vec![];
for line in io::stdin().lines() {
let s = line.unwrap();
let ss = s.as_slice().trim().split(' ');
let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect();
ar.push(xs);
}
let mut best = 0;
for i in range(0i,n) {
for j in range(0i,n) {
for &(di, dj) in [(0,1),(1,1),(1,0),(1,-1i)].iter() {
if i+di*3 < n && j+dj*3 < n && j+dj*3 >= 0 {
let mut p = 1;
for k in range(0i,4) {
p *= ar[(i+di*k) as uint][(j+dj*k) as uint]
}
best = max(best, p);
}
}
}
}
println!("{}", best);
}


Just like most people not actively involved in the language design, I'm still finding my feet with Rust as well, so take what I have to say with a large grain of salt.

You don't need to define your own max function: there is one already in the standard library, in std::cmp to be exact:

pub fn max<T: Ord>(v1: T, v2: T) -> T


This will work for anything that has an impl Ord, which int certainly does.

You can avoid the casts if you simply read everything in as a uint in the first place. In fact, it's probably a good idea to split up the code reading and parsing the file from the code that does the calculation. I'd write it something like:

use std::io;

fn read_grid(path: &str) -> Vec<Vec<uint>> {
let path = Path::new(path);
let mut lines = file.lines().map(|x| x.unwrap());
let mut grid: Vec<Vec<uint>> = vec![];

for line in lines {
let option = line.as_slice().split(' ').map(|x| -> Option<uint> from_str(x.trim()));
grid.push(option.filter(|x| x.is_some()).map(|x| x.unwrap()).collect());
}
grid
}


This will also skip over any non-convertible values (that is, anything that from_str(x.trim()) gives None from.

I don't doubt there are still much better ways of writing this, but that's about where I'm at for now.

• I don't think I can use uint, as my dj can be negative. At least, if j is uint and dj is int, I'll have to write j+dj*3 someway different. I think. – Thomas Ahle Sep 29 '14 at 16:01
• .map(|x| -> Option<uint> from_str(x.trim())).filter(|x| x.is_some()).map(|x| x.unwrap()) would be better as .filter_map(|x| from_str::<uint>(x.trim()). And once it’s done that way, the ::<uint> part can be inferred, so it can be dropped too. – Chris Morgan Oct 6 '14 at 2:56
• The recommended style would also have use std::io::{BufferedReader, File};. – Chris Morgan Oct 6 '14 at 3:03
• If you really wanted to mess with people, you could write the entire body of the function in one expression, BufferedReader::new(File::open(&Path::new(path))).lines().map(|x| x.unwrap()[].split(' ').filter_map(|x| from_str(x.trim())).collect()).collect()… (oh yeah, you can use [] where you used to have .as_slice()) – Chris Morgan Oct 6 '14 at 3:07
• @ChrisMorgan You should write all of this up as an answer. – Yuushi Oct 6 '14 at 3:19