Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add binary space partition and random room placement algorithms for procedural generation #3

Merged
merged 7 commits into from
Nov 4, 2023

Conversation

Chubbygummibear
Copy link

@Chubbygummibear Chubbygummibear commented Oct 2, 2023

I hope I'm doing this right. This is the code I've been testing with and it compiles using the default
cargo build --release --target i686-pc-windows-msvc
from the readme so I assume that means it will work and won't destroy the server

Adds rust functions for binary space partitioning and random room placement. Currently just for my procedural maintenance generation code, but can be applied to more than that in the future, should anyone else want to use it

Binary Space Partitioning:

In computer science, binary space partitioning (BSP) is a method for space partitioning which recursively subdivides a Euclidean space into two convex sets by using hyperplanes as partitions. This process of subdividing gives rise to a representation of objects within the space in the form of a tree data structure known as a BSP tree.

Basically cutting a shape in half, then that half in half, recursively until all subsections are equal to a minimum given size, or further cuts would reduce the size beneath the desired minimum
Binary_space_partition

Random Room Placement:

Given an area of specified dimensions, will create rooms of varying dimensions and place them randomly in the area. The only logic applied is that the rooms fit within the boundaries of the area and don't overlap one another

Credit to https://www.jamesbaum.co.uk/blether/procedural-level-generation-rust/ for getting me started with the code I needed to make this work

Comment on lines 37 to 39
if map_subsection_min_size < map_subsection_min_room_width || map_subsection_min_size < map_subsection_min_room_height{
map_subsection_min_size = cmp::max(map_subsection_min_room_width, map_subsection_min_room_height) + 1
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to understand this logic. So if the map_subsection_min_size is less than map_subsection_min_room_width or map_subsection_min_room_width it'll be set to whatever is highest + 1.

From the sounds of it it seems like you want map_subsection_min_size to always be atleast 1 more than map_subsection_min_room_width and map_subsection_min_room_height

If that is the case then I think you might have a bug, you should be using <= not < or else you could end up in the scenario of map_subsection_min_size being equal to map_subsection_min_size

and you could also simplify this to

Suggested change
if map_subsection_min_size < map_subsection_min_room_width || map_subsection_min_size < map_subsection_min_room_height{
map_subsection_min_size = cmp::max(map_subsection_min_room_width, map_subsection_min_room_height) + 1
}
let map_subsection_min_size = cmp::max(
map_subsection_min_size_as_str.parse::<i32>()?,
cmp::max(map_subsection_min_room_width, map_subsection_min_room_height) + 1
)

and avoid using a mutable variable

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha about the mut, and updated to use your double cmp method over the if then cmp 👍

Comment on lines 47 to 52
let mut string = String::new();
for room in &level.all_rooms {
let serialized = serde_json::to_string(&room).unwrap();
let _ = write!(string, "{}", serialized);
//println!("serialized = {}", serialized);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this leftover debug code? I don't see where the string value is used!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right my b, got rid of it

//println!("serialized = {}", serialized);
}

Ok(format!("{}",serde_json::to_string(&level.all_rooms)?))
Copy link
Member

@AshCorr AshCorr Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Ok(format!("{}",serde_json::to_string(&level.all_rooms)?))
serde_json::to_string(&level.all_rooms)

serde_json::to_string already returns a Result<String>, maybe you can just return that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately just trying to return the serde_json::to_string gives me
mismatched types serde_json::Error and error::Error have similar names, but are actually distinct types
but wrapping it in an Ok()? converts the error into the appropriate error rust-g is expecting

Copy link
Member

@AshCorr AshCorr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mightt be worth reviewing all your commented code and either removing it or uncommenting it! Makes it a little confusing to know whats what.

let max_rooms = desired_room_count as usize;
let max_attempts = 15;
let mut attempts = 0;
while self.level.all_rooms.iter().filter(|&rm| rm.room_type == 3).count() <= max_rooms && attempts <= max_attempts {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rm.room_type == 3

Could we maybe use some kind of enum for room_type? hard to know what 3 is supposed to mean!

}

fn place_rooms_random(&mut self, desired_room_count: i32, rng: &mut StdRng) {
let max_rooms = desired_room_count as usize;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you not make place_rooms_Random take a usize ? or just use an i32?

map.level
}

fn place_rooms_random(&mut self, desired_room_count: i32, rng: &mut StdRng) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh is it worth just making place_rooms_random a function of Level instead of creating an entirely different RandomRoomLevel struct?

board: Vec<Vec<i32>>,
all_rooms: Vec<Room>,
increment: i32,
//hash: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still need this?

for _ in 0..self.height {
let space_tile = 0;
//let wall_tile = 1;
let floor_tile = 5;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could have a TileType enum?

Comment on lines 136 to 149
let gen_floor_first = true;

let mut row = vec![floor_tile; self.width as usize];
if !gen_floor_first {
row = vec![space_tile; self.width as usize];
}
// if gen_floor_first {
// if index == 0 || index == self.height - 1 {
// row = vec![wall_tile; self.width as usize];
// }

// row[0] = wall_tile;
// row[self.width as usize - 1] = wall_tile;
// }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you meant to do something with gen_floor_first here?

Comment on lines 209 to 218
let height: i32;
match *self {
RoomDimensions::Maint3x3 => height = 3,
RoomDimensions::Maint3x5 => height = 5,
RoomDimensions::Maint5x3 => height = 3,
RoomDimensions::Maint5x4 => height = 4,
RoomDimensions::Maint10x5 => height = 5,
RoomDimensions::Maint10x10 => height = 10,
}
return height + 2
Copy link
Member

@AshCorr AshCorr Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let height: i32;
match *self {
RoomDimensions::Maint3x3 => height = 3,
RoomDimensions::Maint3x5 => height = 5,
RoomDimensions::Maint5x3 => height = 3,
RoomDimensions::Maint5x4 => height = 4,
RoomDimensions::Maint10x5 => height = 5,
RoomDimensions::Maint10x10 => height = 10,
}
return height + 2
match *self {
RoomDimensions::Maint3x3 => 3,
RoomDimensions::Maint3x5 => 5,
RoomDimensions::Maint5x3 => 3,
RoomDimensions::Maint5x4 => 4,
RoomDimensions::Maint10x5 => 5,
RoomDimensions::Maint10x10 => 10,
} + 2

Comment on lines 222 to 231
let width: i32;
match *self {
RoomDimensions::Maint3x3 => width = 3,
RoomDimensions::Maint3x5 => width = 3,
RoomDimensions::Maint5x3 => width = 5,
RoomDimensions::Maint5x4 => width = 5,
RoomDimensions::Maint10x5 => width = 10,
RoomDimensions::Maint10x10 => width = 10,
}
return width + 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let width: i32;
match *self {
RoomDimensions::Maint3x3 => width = 3,
RoomDimensions::Maint3x5 => width = 3,
RoomDimensions::Maint5x3 => width = 5,
RoomDimensions::Maint5x4 => width = 5,
RoomDimensions::Maint10x5 => width = 10,
RoomDimensions::Maint10x10 => width = 10,
}
return width + 2;
match *self {
RoomDimensions::Maint3x3 => width = 3,
RoomDimensions::Maint3x5 => width = 3,
RoomDimensions::Maint5x3 => width = 5,
RoomDimensions::Maint5x4 => width = 5,
RoomDimensions::Maint10x5 => width = 10,
RoomDimensions::Maint10x10 => width = 10,
} + 2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might also want a comment for what the + 2 is for!

src/binary_space_partition.rs Outdated Show resolved Hide resolved
src/binary_space_partition.rs Show resolved Hide resolved
simplify is_leaf

Co-authored-by: Ashleigh Carr <[email protected]>
@ToasterBiome ToasterBiome merged commit fa6e3bc into yogstation13:master Nov 4, 2023
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants