terrain_forge/lib.rs
1//! # TerrainForge
2//!
3//! A modular procedural generation engine for terrain, dungeons, and maps.
4//!
5//! ## Quick Start
6//!
7//! ```rust
8//! use terrain_forge::{Grid, ops};
9//!
10//! let mut grid = Grid::new(80, 60);
11//! ops::generate("bsp", &mut grid, Some(12345), None).unwrap();
12//!
13//! println!("Generated {} floor tiles", grid.count(|t| t.is_floor()));
14//! ```
15//!
16//! ## Quick Start (Direct Instantiation)
17//!
18//! ```rust
19//! use terrain_forge::{Algorithm, Grid};
20//! use terrain_forge::algorithms::{Bsp, BspConfig};
21//!
22//! let mut grid = Grid::new(80, 60);
23//! let bsp = Bsp::new(BspConfig {
24//! min_room_size: 6,
25//! max_depth: 5,
26//! room_padding: 1,
27//! });
28//! bsp.generate(&mut grid, 12345);
29//! ```
30//!
31//! ## Semantic Extraction
32//!
33//! Extract semantic information from any generated map:
34//!
35//! ```rust
36//! use terrain_forge::{algorithms, SemanticExtractor, Grid, Rng};
37//!
38//! // 1. Generate map using any method
39//! let mut grid = Grid::new(80, 60);
40//! algorithms::get("cellular").unwrap().generate(&mut grid, 12345);
41//!
42//! // 2. Extract semantic information
43//! let extractor = SemanticExtractor::for_caves();
44//! let mut rng = Rng::new(12345);
45//! let semantic = extractor.extract(&grid, &mut rng);
46//!
47//! // Works with any grid source - pipelines, external tools, etc.
48//! ```
49//!
50//! ## Algorithms
51//!
52//! 15 generation algorithms available via [`algorithms::get`]:
53//! - `bsp` - Binary Space Partitioning for structured rooms
54//! - `cellular` - Cellular automata for organic caves
55//! - `drunkard` - Random walk for winding corridors
56//! - `maze` - Perfect maze generation
57//! - `rooms` - Simple rectangular rooms
58//! - `voronoi` - Voronoi-based regions
59//! - `dla` - Diffusion-limited aggregation
60//! - `wfc` - Wave Function Collapse
61//! - `percolation` - Connected cluster generation
62//! - `diamond_square` - Heightmap terrain
63//! - `noise_fill` - Noise-driven threshold fill
64//! - `fractal` - Fractal noise terrain
65//! - `agent` - Multi-agent carving
66//! - `glass_seam` - Region connector
67//! - `room_accretion` - Brogue-style organic dungeons
68//!
69//! ## Composition
70//!
71//! Chain algorithms with [`compose::Pipeline`] or layer with [`compose::LayeredGenerator`]:
72//!
73//! ```rust
74//! use terrain_forge::{Grid, Tile};
75//! use terrain_forge::pipeline::Pipeline;
76//!
77//! let mut grid = Grid::new(80, 60);
78//! let mut pipeline = Pipeline::new();
79//! pipeline.add_algorithm("rooms", None, None);
80//! pipeline.add_algorithm("cellular", None, None);
81//! pipeline.execute_seed(&mut grid, 12345).unwrap();
82//! ```
83//!
84//! ## Effects
85//!
86//! Post-process with [`effects`]: morphology, connectivity, filters, transforms.
87//!
88//! ## Noise
89//!
90//! [`noise`] module provides Perlin, Simplex, Value, Worley with FBM and modifiers.
91
92mod algorithm;
93mod grid;
94mod rng;
95mod semantic_extractor;
96mod semantic_visualization;
97
98#[cfg(test)]
99mod semantic_tests;
100
101pub mod algorithms;
102pub mod analysis;
103pub mod compose;
104pub mod constraints;
105pub mod effects;
106pub mod noise;
107pub mod ops;
108pub mod pipeline;
109pub mod semantic;
110pub mod spatial;
111
112pub use algorithm::Algorithm;
113pub use grid::{Cell, Grid, Tile};
114pub use ops::{CombineMode, Params};
115pub use rng::Rng;
116pub use semantic::{ConnectivityGraph, Marker, Masks, Region, SemanticConfig, SemanticLayers};
117pub use semantic_extractor::{extract_semantics, extract_semantics_default, SemanticExtractor};
118pub use semantic_visualization::{
119 visualize_connectivity_graph, visualize_masks, visualize_region_ids, visualize_regions,
120 visualize_semantic_layers, VisualizationConfig,
121};
122
123/// Generate a map with semantic layers using the new extraction approach
124///
125/// **DEPRECATED**: This function is provided for backward compatibility.
126/// For new code, use the decoupled `SemanticExtractor` approach:
127///
128/// ```rust
129/// use terrain_forge::{algorithms, SemanticExtractor, Grid, Rng};
130///
131/// // Instead of this deprecated approach:
132/// // let (grid, semantic) = generate_with_semantic_tuple("cellular", 80, 60, 12345);
133///
134/// // Use this:
135/// let mut grid = Grid::new(80, 60);
136/// algorithms::get("cellular").unwrap().generate(&mut grid, 12345);
137/// let semantic = SemanticExtractor::for_caves().extract(&grid, &mut Rng::new(12345));
138/// ```
139#[deprecated(
140 since = "0.3.0",
141 note = "Use decoupled SemanticExtractor for better flexibility"
142)]
143pub fn generate_with_semantic(
144 algorithm_name: &str,
145 width: usize,
146 height: usize,
147 seed: u64,
148) -> (Grid<Tile>, Option<SemanticLayers>) {
149 let mut grid = Grid::new(width, height);
150 let mut rng = Rng::new(seed);
151
152 // Generate tiles using any algorithm
153 if let Some(algo) = algorithms::get(algorithm_name) {
154 algo.generate(&mut grid, seed);
155 }
156
157 // Extract semantic layers using the new standalone system
158 let extractor = match algorithm_name {
159 "cellular" => SemanticExtractor::for_caves(),
160 "bsp" | "rooms" | "room_accretion" => SemanticExtractor::for_rooms(),
161 "maze" => SemanticExtractor::for_mazes(),
162 _ => SemanticExtractor::default(),
163 };
164
165 let semantic = extractor.extract(&grid, &mut rng);
166
167 (grid, Some(semantic))
168}
169
170/// Generate a map that meets specific semantic requirements
171///
172/// This function attempts to generate a map that satisfies the given semantic requirements
173/// by trying different seeds and validating the results. It provides a simple wrapper
174/// around the existing generation system with requirement validation.
175///
176/// # Arguments
177/// * `algorithm_name` - Name of the generation algorithm to use
178/// * `width` - Grid width
179/// * `height` - Grid height
180/// * `requirements` - Semantic requirements that must be met
181/// * `max_attempts` - Maximum number of generation attempts (default: 10)
182/// * `base_seed` - Base seed for generation attempts
183///
184/// # Returns
185/// * `Ok((grid, semantic))` - Successfully generated map meeting requirements
186/// * `Err(String)` - Failed to meet requirements after max attempts
187///
188/// # Example
189/// ```rust
190/// use terrain_forge::{generate_with_requirements, semantic::SemanticRequirements};
191///
192/// let requirements = SemanticRequirements::basic_dungeon();
193/// match generate_with_requirements("bsp", 80, 60, requirements, Some(5), 12345) {
194/// Ok((grid, semantic)) => println!("Generated valid dungeon!"),
195/// Err(msg) => println!("Failed: {}", msg),
196/// }
197/// ```
198pub fn generate_with_requirements(
199 algorithm_name: &str,
200 width: usize,
201 height: usize,
202 requirements: semantic::SemanticRequirements,
203 max_attempts: Option<usize>,
204 base_seed: u64,
205) -> Result<(Grid<Tile>, semantic::SemanticLayers), String> {
206 let max_attempts = max_attempts.unwrap_or(10);
207
208 for attempt in 0..max_attempts {
209 let seed = base_seed.wrapping_add(attempt as u64);
210 let mut grid = Grid::new(width, height);
211 let mut rng = Rng::new(seed);
212
213 // Generate using specified algorithm
214 if let Some(algo) = algorithms::get(algorithm_name) {
215 algo.generate(&mut grid, seed);
216 } else {
217 return Err(format!("Unknown algorithm: {}", algorithm_name));
218 }
219
220 // Extract semantic layers
221 let extractor = match algorithm_name {
222 "cellular" => SemanticExtractor::for_caves(),
223 "bsp" | "rooms" | "room_accretion" => SemanticExtractor::for_rooms(),
224 "maze" => SemanticExtractor::for_mazes(),
225 _ => SemanticExtractor::default(),
226 };
227
228 let semantic = extractor.extract(&grid, &mut rng);
229
230 // Validate requirements
231 if requirements.validate(&semantic) {
232 return Ok((grid, semantic));
233 }
234 }
235
236 Err(format!(
237 "Failed to generate map meeting requirements after {} attempts",
238 max_attempts
239 ))
240}