105 lines
3.0 KiB
Rust
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;
|
|
}
|
|
}
|
|
}
|
|
}
|