Add constraints and common submodules to waveform_collapse map builder
This commit is contained in:
parent
3ce4994417
commit
5fcc22ab6a
@ -7,7 +7,7 @@ pub const MAP_WIDTH: usize = 80;
|
||||
pub const MAP_HEIGHT: usize = 43;
|
||||
pub const MAP_COUNT: usize = MAP_HEIGHT * MAP_WIDTH;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum TileType {
|
||||
Wall,
|
||||
Floor,
|
||||
|
13
src/map_builders/waveform_collapse/common.rs
Normal file
13
src/map_builders/waveform_collapse/common.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use crate::TileType;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
pub struct MapChunk {
|
||||
pub pattern: Vec<TileType>,
|
||||
pub exits: [Vec<bool>; 4],
|
||||
pub has_exits: bool,
|
||||
pub compatible_with: [Vec<usize>; 4],
|
||||
}
|
||||
|
||||
pub fn tile_idx_in_chunk(chunk_size: i32, x: i32, y: i32) -> usize {
|
||||
((y * chunk_size) + x) as usize
|
||||
}
|
226
src/map_builders/waveform_collapse/constraints.rs
Normal file
226
src/map_builders/waveform_collapse/constraints.rs
Normal file
@ -0,0 +1,226 @@
|
||||
use super::MapChunk;
|
||||
use crate::map_builders::waveform_collapse::common::tile_idx_in_chunk;
|
||||
use crate::{Map, TileType};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn build_patterns(
|
||||
map: &Map,
|
||||
chunk_size: i32,
|
||||
include_flipping: bool,
|
||||
dedupe: bool,
|
||||
) -> Vec<Vec<TileType>> {
|
||||
let chunks_x = map.width / chunk_size;
|
||||
let chunks_y = map.height / chunk_size;
|
||||
let mut patterns = Vec::new();
|
||||
|
||||
for cy in 0..chunks_y {
|
||||
for cx in 0..chunks_x {
|
||||
// Normal orientation
|
||||
let mut pattern: Vec<TileType> = Vec::new();
|
||||
let start_x = cx * chunk_size;
|
||||
let end_x = (cx + 1) * chunk_size;
|
||||
let start_y = cy * chunk_size;
|
||||
let end_y = (cy + 1) * chunk_size;
|
||||
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..end_x {
|
||||
let idx = map.xy_idx(x, y);
|
||||
pattern.push(map.tiles[idx]);
|
||||
}
|
||||
}
|
||||
patterns.push(pattern);
|
||||
|
||||
if include_flipping {
|
||||
// Flip horizontal
|
||||
pattern = Vec::new();
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..end_x {
|
||||
let idx = map.xy_idx(end_x - (x + 1), y);
|
||||
pattern.push(map.tiles[idx]);
|
||||
}
|
||||
}
|
||||
patterns.push(pattern);
|
||||
|
||||
// Flip vertical
|
||||
pattern = Vec::new();
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..end_x {
|
||||
let idx = map.xy_idx(x, end_y - (y + 1));
|
||||
pattern.push(map.tiles[idx]);
|
||||
}
|
||||
}
|
||||
patterns.push(pattern);
|
||||
|
||||
// Flip both
|
||||
pattern = Vec::new();
|
||||
for y in start_y..end_y {
|
||||
for x in start_x..end_x {
|
||||
let idx = map.xy_idx(end_x - (x + 1), end_y - (y + 1));
|
||||
pattern.push(map.tiles[idx]);
|
||||
}
|
||||
}
|
||||
patterns.push(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dedupe
|
||||
if dedupe {
|
||||
rltk::console::log(format!(
|
||||
"Pre de-duplication, there are {} patterns",
|
||||
patterns.len()
|
||||
));
|
||||
|
||||
// Use a set to de-duplicate
|
||||
let set: HashSet<Vec<TileType>> = patterns.drain(..).collect();
|
||||
patterns.extend(set.into_iter());
|
||||
|
||||
rltk::console::log(format!("There are {} patterns", patterns.len()));
|
||||
}
|
||||
|
||||
patterns
|
||||
}
|
||||
|
||||
pub fn render_pattern_to_map(
|
||||
map: &mut Map,
|
||||
chunk: &MapChunk,
|
||||
chunk_size: i32,
|
||||
start_x: i32,
|
||||
start_y: i32,
|
||||
) {
|
||||
let mut i = 0_usize;
|
||||
for tile_y in 0..chunk_size {
|
||||
for tile_x in 0..chunk_size {
|
||||
let map_idx = map.xy_idx(start_x + tile_x, start_y + tile_y);
|
||||
map.tiles[map_idx] = chunk.pattern[i];
|
||||
map.visible_tiles[map_idx] = true;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (x, northbound) in chunk.exits[0].iter().enumerate() {
|
||||
if *northbound {
|
||||
let map_idx = map.xy_idx(start_x + x as i32, start_y);
|
||||
map.tiles[map_idx] = TileType::DownStairs;
|
||||
}
|
||||
}
|
||||
for (x, southbound) in chunk.exits[1].iter().enumerate() {
|
||||
if *southbound {
|
||||
let map_idx = map.xy_idx(start_x + x as i32, start_y + chunk_size - 1);
|
||||
map.tiles[map_idx] = TileType::DownStairs;
|
||||
}
|
||||
}
|
||||
for (x, westbound) in chunk.exits[2].iter().enumerate() {
|
||||
if *westbound {
|
||||
let map_idx = map.xy_idx(start_x, start_y + x as i32);
|
||||
map.tiles[map_idx] = TileType::DownStairs;
|
||||
}
|
||||
}
|
||||
for (x, eastbound) in chunk.exits[3].iter().enumerate() {
|
||||
if *eastbound {
|
||||
let map_idx = map.xy_idx(start_x + chunk_size - 1, start_y + x as i32);
|
||||
map.tiles[map_idx] = TileType::DownStairs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn patterns_to_constraints(patterns: Vec<Vec<TileType>>, chunk_size: i32) -> Vec<MapChunk> {
|
||||
// Move into the new constraints object
|
||||
let mut constraints: Vec<MapChunk> = Vec::new();
|
||||
for p in patterns {
|
||||
let mut new_chunk = MapChunk {
|
||||
pattern: p,
|
||||
exits: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
|
||||
has_exits: true,
|
||||
compatible_with: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
|
||||
};
|
||||
for exit in new_chunk.exits.iter_mut() {
|
||||
for _i in 0..chunk_size {
|
||||
exit.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
let mut n_exits = 0;
|
||||
for x in 0..chunk_size {
|
||||
// Check for north-bound exits
|
||||
let north_idx = tile_idx_in_chunk(chunk_size, x, 0);
|
||||
if new_chunk.pattern[north_idx] == TileType::Floor {
|
||||
new_chunk.exits[0][x as usize] = true;
|
||||
n_exits += 1;
|
||||
}
|
||||
|
||||
// Check for south-bound exits
|
||||
let south_idx = tile_idx_in_chunk(chunk_size, x, chunk_size - 1);
|
||||
if new_chunk.pattern[south_idx] == TileType::Floor {
|
||||
new_chunk.exits[1][x as usize] = true;
|
||||
n_exits += 1;
|
||||
}
|
||||
|
||||
// Check for west-bound exits
|
||||
let west_idx = tile_idx_in_chunk(chunk_size, 0, x);
|
||||
if new_chunk.pattern[west_idx] == TileType::Floor {
|
||||
new_chunk.exits[2][x as usize] = true;
|
||||
n_exits += 1;
|
||||
}
|
||||
|
||||
// Check for east-bound exits
|
||||
let east_idx = tile_idx_in_chunk(chunk_size, chunk_size - 1, x);
|
||||
if new_chunk.pattern[east_idx] == TileType::Floor {
|
||||
new_chunk.exits[3][x as usize] = true;
|
||||
n_exits += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if n_exits == 0 {
|
||||
new_chunk.has_exits = false;
|
||||
}
|
||||
|
||||
constraints.push(new_chunk);
|
||||
}
|
||||
|
||||
// Build compatibility matrix
|
||||
let ch = constraints.clone();
|
||||
for c in constraints.iter_mut() {
|
||||
for (j, potential) in ch.iter().enumerate() {
|
||||
// If there are no exits at all, it's compatible
|
||||
if !c.has_exits || !potential.has_exits {
|
||||
for compat in c.compatible_with.iter_mut() {
|
||||
compat.push(j);
|
||||
}
|
||||
} else {
|
||||
// Evaluate compatibility by direction
|
||||
for (direction, exit_list) in c.exits.iter_mut().enumerate() {
|
||||
let opposite = match direction {
|
||||
0 => 1, // Our North, Their South
|
||||
1 => 0, // Our South, Their North
|
||||
2 => 3, // Our West, Their East
|
||||
_ => 2, // Our East, Their West
|
||||
};
|
||||
|
||||
let mut it_fits = false;
|
||||
let mut has_any = false;
|
||||
for (slot, can_enter) in exit_list.iter().enumerate() {
|
||||
if *can_enter {
|
||||
has_any = true;
|
||||
if potential.exits[opposite][slot] {
|
||||
it_fits = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if it_fits {
|
||||
c.compatible_with[direction].push(j);
|
||||
}
|
||||
if !has_any {
|
||||
// There's no exits on this side, we don't care what goes there
|
||||
for compat in c.compatible_with.iter_mut() {
|
||||
compat.push(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constraints
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use rltk::rex::XpFile;
|
||||
use crate::{Map, TileType};
|
||||
use rltk::rex::XpFile;
|
||||
|
||||
/// Loads a RexPaint file, and converts it into our map format
|
||||
pub fn load_rex_map(new_depth: i32, xp_file: &XpFile) -> Map {
|
||||
|
0
src/map_builders/waveform_collapse/solver.rs
Normal file
0
src/map_builders/waveform_collapse/solver.rs
Normal file
Loading…
Reference in New Issue
Block a user