#![allow(clippy::clone_double_ref)]
use image::Rgb;
use rand::seq::SliceRandom;
use rand::{thread_rng, Rng};
use dcc_lsystem::renderer::ImageRendererOptionsBuilder;
use dcc_lsystem::renderer::Renderer;
use dcc_lsystem::turtle::{TurtleAction, TurtleLSystemBuilder};
fn valid_rule(rule: &[&str]) -> bool {
if rule.is_empty() {
return false;
}
let r = rule.join("");
if r.contains("+-") || !r.contains('+') {
return false;
}
let mut level = 0;
for c in rule {
if c == &"+" {
level += 1;
} else if c == &"-" {
if level == 0 {
return false;
}
level -= 1;
}
}
level == 0
}
pub fn main() {
'processing: loop {
let mut rng = thread_rng();
let axiom_length = rng.gen_range(0..=2);
let mut axiom = vec!["X"];
let choices = ["L", "R", "F", "X", "Y"];
let weighted_choices = [
("F", rng.gen_range(1..=8)),
("X", rng.gen_range(2..=4)),
("Y", rng.gen_range(2..=4)),
("L", rng.gen_range(2..=6)),
("R", rng.gen_range(2..=6)),
("+", rng.gen_range(4..=8)),
("-", rng.gen_range(4..=8)),
];
for _ in 0..axiom_length {
axiom.push(choices.choose(&mut rng).unwrap().clone());
}
let mut x_rule = Vec::new();
while !valid_rule(&x_rule) {
x_rule.clear();
let x_rule_length = rng.gen_range(4..=10);
for _ in 0..x_rule_length {
x_rule.push(
weighted_choices
.choose_weighted(&mut rng, |item| item.1)
.unwrap()
.0
.clone(),
);
}
}
let mut y_rule = Vec::new();
while !valid_rule(&y_rule) {
y_rule.clear();
let y_rule_length = rng.gen_range(4..=10);
for _ in 0..y_rule_length {
y_rule.push(
weighted_choices
.choose_weighted(&mut rng, |item| item.1)
.unwrap()
.0
.clone(),
);
}
}
let mut builder = TurtleLSystemBuilder::new();
builder
.token("L", TurtleAction::Rotate(25))
.token("R", TurtleAction::Rotate(-25))
.token("F", TurtleAction::Forward(100))
.token("+", TurtleAction::Push)
.token("-", TurtleAction::Pop)
.token("X", TurtleAction::Nothing)
.token("Y", TurtleAction::Nothing)
.axiom(&axiom.join(" "))
.rule(format!("X => {}", x_rule.join(" ")).as_str())
.rule(format!("Y => {}", y_rule.join(" ")).as_str());
let (mut system, renderer) = builder.finish();
let options = ImageRendererOptionsBuilder::new()
.padding(20)
.thickness(1.0)
.fill_color(Rgb([0u8, 0u8, 0u8]))
.line_color(Rgb([218u8, 112u8, 214u8]))
.build();
system.step_by(10);
let buffer = renderer.render(&system, &options);
if buffer.width() < 1000 || buffer.height() < 1000 {
continue 'processing;
}
buffer.save("test_render.png").expect("Saving file failed");
break;
}
}