3
\$\begingroup\$

This code is meant to take a rectangular area, and randomly divide it up into smaller rectangles in a binary tree.

I'm somewhat new to Rust.

I'm concerned mostly about the create_subrooms function. I've tried lots of other permutations, but I can't find any more elegant way of writing this, and it still looks pretty ugly in my opinion.

Some specific questions I have:

  • Would it be poor form to have the function take ownership of root, modify it and return it? This would mean I could create the tree in a single line instead of creating the Room, creating it's children and then explicitly assigning it to the left/right of it's parent
  • Would I be better off having the function accept four size parameters, instead of creating the root Room beforehand and passing a reference? Or would that be too verbose?

This struct represents a node in the tree:

struct Room {
    x: u32,
    y: u32,
    end_x: u32,
    end_y: u32,
    left: Option<Rc<Room>>>,
    right: Option<Rc<Room>>,
}

And this function takes a previously created root Room, and recursively generates its children:

fn create_subrooms(&mut self, root: &mut Room, depth: u32) {
        if depth < self.max_rec_depth && self.is_valid_size(root) {
            let mut left: Room;
            let mut right: Room;

            // Horizontal and Vertical are the direction along which, the
            // rectangle is split, and the new boundaries are randomly chosen
            // perpendicular to that
            match rand::random::<Direction>() {
                Vertical => {
                    let cut = self.rng.gen_range(root.x, root.end_x);

                    // Not including the 'new' method for brevity, 
                    // but it's form is (x, y, end_x, end_y)
                    // children are None by default
                    left = Room::new(root.x, root.y, cut, root.end_y);
                    right = Room::new(cut, root.y, root.end_x, root.end_y);
                }
                Horizontal => {
                    let cut = self.rng.gen_range(root.y, root.end_y);

                    left = Room::new(root.x, root.y, root.end_x, cut);
                    right = Room::new(root.x, cut, root.end_x, root.end_y);
                }
            };

            self.create_subrooms(&mut left, depth + 1);
            root.left = Some(Rc::new(left));

            self.create_subrooms(&mut right, depth + 1);
            root.right = Some(Rc::new(right));
        }
    }

The self parameters are from a Builder struct which is used to customise how the area is divided.

The create_rooms function is initially called like this:

fn divide_room(&mut self) {
    let mut root = SubDungeon::new(0, 0, self.width, self.height);
    self.create_subdungeons(&mut root, 0);
    Rc::new(root)
}
\$\endgroup\$
  • \$\begingroup\$ Is the tree important, or just the leaf nodes? If you're generating "rooms", I would expect just the leaf nodes. If it's "subrooms", what's the difference? \$\endgroup\$ – Austin Hastings Apr 19 at 23:43
  • \$\begingroup\$ Can you add some code to the question that shows how create_rooms is called? That's helpful for understanding it. \$\endgroup\$ – Roland Illig Apr 20 at 4:39
  • \$\begingroup\$ @AustinHastings the tree is important, as I need to do some task later where the tree is stepped through and a calculation is performed using the Rooms at each level of the tree. \$\endgroup\$ – JMac Apr 20 at 8:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.