1
\$\begingroup\$

So I have this binary spaced partition leaf:

#[derive(Clone)]
pub struct Leaf {
 container: Rect,
 left: Option<Box<Leaf>>,
 right: Option<Box<Leaf>>,
 room: Option<Rect>,
 split_vertical: Option<bool>,
}
impl Leaf {
 fn new(container: Rect) -> Leaf {
 Leaf {
 container,
 left: None,
 right: None,
 room: None,
 split_vertical: None,
 }
 }
 fn split(
 &mut self,
 grid: Vec<Vec<i32>>,
 mut random_generator: StdRng,
 min_container_size: i32,
 debug_game: bool,
 ) -> bool {
 if self.left.is_some() && self.right.is_some() {
 return false;
 }
 let mut split_vertical: bool = random_generator.gen::<bool>();
 if (self.container.width > self.container.height)
 && ((self.container.width.unwrap() / self.container.height.unwrap()) as f64 >= 1.25)
 {
 split_vertical = true;
 } else if (self.container.height > self.container.width)
 && ((self.container.height.unwrap() / self.container.width.unwrap()) as f64 >= 1.25)
 {
 split_vertical = false;
 }
 let max_size: i32 = if split_vertical {
 self.container.width.unwrap() - min_container_size
 } else {
 self.container.height.unwrap() - min_container_size
 };
 if max_size <= min_container_size {
 return false;
 }
 let mut pos: i32 = random_generator.gen_range(min_container_size..max_size);
 if split_vertical {
 pos += self.container.top_left.x;
 if debug_game {
 println!("split vertical debug");
 }
 self.left = Option::from(Box::new(Leaf {
 container: Rect {
 top_left: Point {
 x: self.container.top_left.x,
 y: self.container.top_left.y,
 },
 bottom_right: Point {
 x: pos - 1,
 y: self.container.bottom_right.y,
 },
 center: None,
 width: None,
 height: None,
 },
 left: None,
 right: None,
 room: None,
 split_vertical: None,
 }));
 self.right = Option::from(Box::new(Leaf {
 container: Rect {
 top_left: Point {
 x: pos + 1,
 y: self.container.top_left.y,
 },
 bottom_right: Point {
 x: self.container.bottom_right.x,
 y: self.container.bottom_right.y,
 },
 center: None,
 width: None,
 height: None,
 },
 left: None,
 right: None,
 room: None,
 split_vertical: None,
 }))
 } else {
 pos += self.container.top_left.y;
 if debug_game {
 println!("split horizontal debug");
 }
 self.left = Option::from(Box::new(Leaf {
 container: Rect {
 top_left: Point {
 x: self.container.top_left.x,
 y: self.container.top_left.y,
 },
 bottom_right: Point {
 x: self.container.bottom_right.x,
 y: pos - 1,
 },
 center: None,
 width: None,
 height: None,
 },
 left: None,
 right: None,
 room: None,
 split_vertical: None,
 }));
 self.right = Option::from(Box::new(Leaf {
 container: Rect {
 top_left: Point {
 x: self.container.top_left.x,
 y: pos - 1,
 },
 bottom_right: Point {
 x: self.container.bottom_right.x,
 y: self.container.bottom_right.y,
 },
 center: None,
 width: None,
 height: None,
 },
 left: None,
 right: None,
 room: None,
 split_vertical: None,
 }))
 }
 self.split_vertical = Option::from(split_vertical);
 return true;
 }
 fn create_room(
 &mut self,
 grid: Vec<Vec<i32>>,
 mut random_generator: StdRng,
 min_room_size: i32,
 room_ratio: f32,
 ) -> bool {
 if self.left.is_some() && self.right.is_some() {
 return false;
 }
 let width: i32 = random_generator.gen_range(min_room_size..self.container.width.unwrap());
 let height: i32 = random_generator.gen_range(min_room_size..self.container.height.unwrap());
 let x_pos: i32 = random_generator
 .gen_range(self.container.top_left.x..self.container.bottom_right.x - width);
 let y_pos: i32 = random_generator
 .gen_range(self.container.top_left.y..self.container.bottom_right.y - height);
 let rect: Rect = Rect {
 top_left: Point { x: x_pos, y: y_pos },
 bottom_right: Point {
 x: x_pos + width - 1,
 y: y_pos + height - 1,
 },
 center: None,
 width: None,
 height: None,
 };
 if ((min(rect.width.unwrap(), rect.height.unwrap()) as f32)
 / (max(rect.width.unwrap(), rect.height.unwrap()) as f32))
 < room_ratio
 {
 return false;
 }
 rect.place_rect(grid);
 self.room = Option::from(rect);
 return true;
 }
}

And the Point and Rect structs:

#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub struct Point {
 pub x: i32,
 pub y: i32,
}
impl Point {
 fn new(x: i32, y: i32) -> Point {
 Point { x, y }
 }
 pub fn sum(&self, other: &Point) -> (i32, i32) {
 (self.x + other.x, self.y + other.y)
 }
 pub fn abs_diff(&self, other: &Point) -> (i32, i32) {
 ((self.x - other.x).abs(), (self.y - other.y).abs())
 }
}
#[derive(Clone)]
pub struct Rect {
 pub top_left: Point,
 pub bottom_right: Point,
 pub center: Option<Point>,
 pub width: Option<i32>,
 pub height: Option<i32>,
}
impl Rect {
 fn new(top_left: Point, bottom_right: Point) -> Rect {
 let sum: (i32, i32) = top_left.sum(&bottom_right);
 let diff: (i32, i32) = bottom_right.abs_diff(&top_left);
 Rect {
 top_left,
 bottom_right,
 center: Option::from(Point {
 x: ((sum.0 as f32) / 2.0).round() as i32,
 y: ((sum.1 as f32) / 2.0).round() as i32,
 }),
 width: Option::from(diff.0),
 height: Option::from(diff.1),
 }
 }
 pub fn get_distance_to(&self, other: &Rect) -> i32 {
 return max(
 (self.center.unwrap().x - other.center.unwrap().x).abs(),
 (self.center.unwrap().y - other.center.unwrap().y).abs(),
 );
 }
 pub fn place_rect(&self, grid: Vec<Vec<i32>>) {}
}

However, I'm fairly new to Rust and am not sure how to optimise this further than I already have. I know there's some repetition (especially with creating the child leafs) and wanted to know if there was a way to simplify it, speed it up, and make it more idiomatic?

asked Dec 29, 2022 at 17:15
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
#[derive(Clone)]
pub struct Leaf {
 container: Rect,
 left: Option<Box<Leaf>>,
 right: Option<Box<Leaf>>,
 room: Option<Rect>,
 split_vertical: Option<bool>,
}

The left, right, and split_vertical options are all linked. They are all set together. So I'd do something like:

#[derive(Clone)]
pub struct Division {
 left: Leaf,
 right: Leaf,
 split_vertical: bool
}
#[derive(Clone)]
pub struct Leaf {
 container: Rect,
 division: Option<Box<Division>>,
 room: Option<Rect>,
}

This will allow you to simplify the code quite a bit as you don't have to create multiple options/boxes/unwrap separate fields.

 self.left = Option::from(Box::new(Leaf {
 container: Rect {
 top_left: Point {
 x: self.container.top_left.x,
 y: self.container.top_left.y,
 },
 bottom_right: Point {
 x: self.container.bottom_right.x,
 y: pos - 1,
 },
 center: None,
 width: None,
 height: None,
 },
 left: None,
 right: None,
 room: None,
 split_vertical: None,
 }));

You already have Leaf::new and Rect::new which could be used to avoid most of the boilerplate that you have here.

 self.left = Option::from(Box::new(Leaf::new(Rect::new(Point {
 x: self.container.top_left.x,
 y: self.container.top_left.y,
 },
 Point {
 x: self.container.bottom_right.x,
 y: pos - 1,
 }))));
answered Jan 2, 2023 at 4:25
\$\endgroup\$
5
  • \$\begingroup\$ How would you store and instantiated division struct into the left or right leafs? Surely, you would need more code duplication within the if else statement \$\endgroup\$ Commented Jan 6, 2023 at 14:26
  • \$\begingroup\$ @Aspect11, I'm afraid I don't understand your question. \$\endgroup\$ Commented Jan 7, 2023 at 2:28
  • \$\begingroup\$ How would you store the division into the left/right children? \$\endgroup\$ Commented Jan 7, 2023 at 14:10
  • \$\begingroup\$ @Aspect11 the division contains the left/right children. So I don't understand why you are asking about store the division into the children \$\endgroup\$ Commented Jan 7, 2023 at 16:45
  • \$\begingroup\$ @Aspect11, since there's clear some point of confusion and I can't figure out what you are asking, I went around and rewrote your code with my suggestions here: play.rust-lang.org/…, hopefully that will clarify what you are asking. \$\endgroup\$ Commented Jan 7, 2023 at 17:08

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.