Brownian tree

You are encouraged to solve this task according to the task description, using any language you may know.



Task

Generate and draw a   Brownian Tree.



A Brownian Tree is generated as a result of an initial seed, followed by the interaction of two processes.

 The initial "seed" is placed somewhere within the field. Where is not particularly important; it could be randomized, or it could be a fixed point.
 Particles are injected into the field, and are individually given a (typically random) motion pattern.
 When a particle collides with the seed or tree, its position is fixed, and it's considered to be part of the tree.

Because of the lax rules governing the random nature of the particle's placement and motion, no two resulting trees are really expected to be the same, or even necessarily have the same general shape. 



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