Skip to main content

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::{line_points, 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 that meets specific semantic requirements
124///
125/// This function attempts to generate a map that satisfies the given semantic requirements
126/// by trying different seeds and validating the results. It provides a simple wrapper
127/// around the existing generation system with requirement validation.
128///
129/// # Arguments
130/// * `algorithm_name` - Name of the generation algorithm to use
131/// * `width` - Grid width
132/// * `height` - Grid height  
133/// * `requirements` - Semantic requirements that must be met
134/// * `max_attempts` - Maximum number of generation attempts (default: 10)
135/// * `base_seed` - Base seed for generation attempts
136///
137/// # Returns
138/// * `Ok((grid, semantic))` - Successfully generated map meeting requirements
139/// * `Err(String)` - Failed to meet requirements after max attempts
140///
141/// # Example
142/// ```rust
143/// use terrain_forge::{generate_with_requirements, semantic::SemanticRequirements};
144///
145/// let requirements = SemanticRequirements::basic_dungeon();
146/// match generate_with_requirements("bsp", 80, 60, requirements, Some(5), 12345) {
147///     Ok((grid, semantic)) => println!("Generated valid dungeon!"),
148///     Err(msg) => println!("Failed: {}", msg),
149/// }
150/// ```
151pub fn generate_with_requirements(
152    algorithm_name: &str,
153    width: usize,
154    height: usize,
155    requirements: semantic::SemanticRequirements,
156    max_attempts: Option<usize>,
157    base_seed: u64,
158) -> Result<(Grid<Tile>, semantic::SemanticLayers), String> {
159    let max_attempts = max_attempts.unwrap_or(10);
160
161    for attempt in 0..max_attempts {
162        let seed = base_seed.wrapping_add(attempt as u64);
163        let mut grid = Grid::new(width, height);
164        let mut rng = Rng::new(seed);
165
166        // Generate using specified algorithm
167        if let Some(algo) = algorithms::get(algorithm_name) {
168            algo.generate(&mut grid, seed);
169        } else {
170            return Err(format!("Unknown algorithm: {}", algorithm_name));
171        }
172
173        // Extract semantic layers
174        let extractor = match algorithm_name {
175            "cellular" => SemanticExtractor::for_caves(),
176            "bsp" | "rooms" | "room_accretion" => SemanticExtractor::for_rooms(),
177            "maze" => SemanticExtractor::for_mazes(),
178            _ => SemanticExtractor::default(),
179        };
180
181        let semantic = extractor.extract(&grid, &mut rng);
182
183        // Validate requirements
184        if requirements.validate(&semantic) {
185            return Ok((grid, semantic));
186        }
187    }
188
189    Err(format!(
190        "Failed to generate map meeting requirements after {} attempts",
191        max_attempts
192    ))
193}