RosettaCodeData/Task/Brownian-tree/Rust/brownian-tree.rs

105 lines
3.0 KiB
Rust

extern crate image;
extern crate rand;
use image::ColorType;
use std::cmp::{min, max};
use std::env;
use std::path::Path;
use std::process;
use rand::Rng;
fn help() {
println!("Usage: brownian_tree <output_path> <mote_count> <edge_length>");
}
fn main() {
let args: Vec<String> = env::args().collect();
let mut output_path = Path::new("out.png");
let mut mote_count: u32 = 10000;
let mut width: usize = 512;
let mut height: usize = 512;
match args.len() {
1 => {}
4 => {
output_path = Path::new(&args[1]);
mote_count = args[2].parse::<u32>().unwrap();
width = args[3].parse::<usize>().unwrap();
height = width;
}
_ => {
help();
process::exit(0);
}
}
assert!(width >= 2);
// Base 1d array
let mut field_raw = vec![0u8; width * height];
populate_tree(&mut field_raw, width, height, mote_count);
// Balance image for 8-bit grayscale
let our_max = field_raw.iter().fold(0u8, |champ, e| max(champ, *e));
let fudge = std::u8::MAX / our_max;
let balanced: Vec<u8> = field_raw.iter().map(|e| e * fudge).collect();
match image::save_buffer(output_path,
&balanced,
width as u32,
height as u32,
ColorType::L8) {
Err(e) => println!("Error writing output image:\n{}", e),
Ok(_) => println!("Output written to:\n{}", output_path.to_str().unwrap()),
}
}
fn populate_tree(raw: &mut Vec<u8>, width: usize, height: usize, mc: u32) {
// Vector of 'width' elements slices
let mut field_base: Vec<_> = raw.as_mut_slice().chunks_mut(width).collect();
// Addressable 2d vector
let field: &mut [&mut [u8]] = field_base.as_mut_slice();
// Seed mote
field[width / 2][height / 2] = 1;
let mut rng = rand::thread_rng();
for i in 0..mc {
if i % 100 == 0 {
println!("{}", i)
}
let mut x=rng.gen_range(1usize..width-1);
let mut y=rng.gen_range(1usize..height-1);
// Increment field value when motes spawn on top of the structure
if field[x][y] > 0 {
field[x][y] = min(field[x][y] as u32 + 1, std::u8::MAX as u32) as u8;
continue;
}
loop {
let contacts = field[x - 1][y - 1] + field[x][y - 1] + field[x + 1][y - 1] +
field[x - 1][y] + field[x + 1][y] +
field[x - 1][y + 1] + field[x][y + 1] +
field[x + 1][y + 1];
if contacts > 0 {
field[x][y] = 1;
break;
} else {
let xw = rng.gen_range(-1..2) + x as i32;
let yw = rng.gen_range(-1..2) + y as i32;
if xw < 1 || xw >= (width as i32 - 1) || yw < 1 || yw >= (height as i32 - 1) {
break;
}
x = xw as usize;
y = yw as usize;
}
}
}
}