pub struct SemanticRequirements {
pub min_regions: HashMap<String, usize>,
pub max_regions: HashMap<String, usize>,
pub required_connections: Vec<(String, String)>,
pub min_walkable_area: Option<usize>,
pub required_markers: HashMap<MarkerType, usize>,
}Expand description
Requirements for semantic-driven generation
Fields§
§min_regions: HashMap<String, usize>Minimum number of regions of each type
max_regions: HashMap<String, usize>Maximum number of regions of each type
required_connections: Vec<(String, String)>Required connectivity between region types
min_walkable_area: Option<usize>Minimum total walkable area
required_markers: HashMap<MarkerType, usize>Required marker types and their minimum counts
Implementations§
Source§impl SemanticRequirements
impl SemanticRequirements
Sourcepub fn none() -> Self
pub fn none() -> Self
Create requirements with no constraints
Examples found in repository?
examples/requirements_demo.rs (line 7)
3fn main() {
4 println!("=== Generate with Requirements Demo ===\n");
5
6 // Create simple requirements that match BSP output
7 let mut requirements = SemanticRequirements::none();
8 requirements.min_regions.insert("Hall".to_string(), 1); // BSP produces "Hall" regions
9 requirements
10 .required_markers
11 .insert(MarkerType::Custom("PlayerStart".to_string()), 1); // BSP produces "PlayerStart"
12
13 println!("Requirements:");
14 println!(" - Minimum 1 Hall region");
15 println!(" - At least 1 PlayerStart marker");
16 println!();
17
18 match generate_with_requirements("bsp", 40, 30, requirements, Some(10), 12345) {
19 Ok((grid, semantic)) => {
20 println!("✅ Successfully generated map meeting requirements!");
21 println!(" Grid size: {}x{}", grid.width(), grid.height());
22 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
23 println!(" Total regions: {}", semantic.regions.len());
24
25 // Count Hall regions
26 let hall_count = semantic.regions.iter().filter(|r| r.kind == "Hall").count();
27 println!(" Hall regions: {}", hall_count);
28
29 // Count PlayerStart markers
30 let start_count = semantic
31 .markers
32 .iter()
33 .filter(|m| m.tag() == "PlayerStart")
34 .count();
35 println!(" PlayerStart markers: {}", start_count);
36
37 println!("\nFirst few regions:");
38 for (i, region) in semantic.regions.iter().take(3).enumerate() {
39 println!(" {}: {} ({} cells)", i + 1, region.kind, region.area());
40 }
41 }
42 Err(msg) => {
43 println!("❌ Failed to generate: {}", msg);
44 }
45 }
46}More examples
examples/requirement_generation.rs (line 22)
3fn main() {
4 println!("=== Requirement-Driven Generation Demo ===\n");
5
6 // Demo 1: Basic dungeon requirements
7 println!("1. Basic Dungeon Requirements:");
8 let basic_req = SemanticRequirements::basic_dungeon();
9
10 match generate_with_requirements("bsp", 40, 30, basic_req, Some(5), 12345) {
11 Ok((grid, semantic)) => {
12 println!(" ✅ Generated valid dungeon!");
13 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
14 println!(" Regions: {}", semantic.regions.len());
15 println!(" Markers: {}", semantic.markers.len());
16 }
17 Err(msg) => println!(" ❌ Failed: {}", msg),
18 }
19
20 // Demo 2: Custom requirements
21 println!("\n2. Custom Cave Requirements:");
22 let mut cave_req = SemanticRequirements::none();
23 cave_req.min_regions.insert("cavern".to_string(), 2);
24 cave_req.min_walkable_area = Some(200);
25 cave_req
26 .required_markers
27 .insert(MarkerType::Custom("entrance".to_string()), 1);
28 cave_req
29 .required_markers
30 .insert(MarkerType::Custom("treasure".to_string()), 1);
31
32 match generate_with_requirements("cellular", 50, 40, cave_req, Some(10), 54321) {
33 Ok((grid, semantic)) => {
34 println!(" ✅ Generated valid cave system!");
35 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
36 println!(" Regions: {}", semantic.regions.len());
37
38 // Show region types
39 let mut region_types = std::collections::HashMap::new();
40 for region in &semantic.regions {
41 *region_types.entry(®ion.kind).or_insert(0) += 1;
42 }
43 for (kind, count) in region_types {
44 println!(" {}: {}", kind, count);
45 }
46 }
47 Err(msg) => println!(" ❌ Failed: {}", msg),
48 }
49
50 // Demo 3: Strict requirements (likely to fail)
51 println!("\n3. Strict Requirements (demonstration of failure):");
52 let mut strict_req = SemanticRequirements::none();
53 strict_req.min_regions.insert("room".to_string(), 10); // Very strict
54 strict_req
55 .required_markers
56 .insert(MarkerType::QuestObjective { priority: 1 }, 5);
57 strict_req.min_walkable_area = Some(800);
58
59 match generate_with_requirements("bsp", 30, 20, strict_req, Some(3), 98765) {
60 Ok((grid, _semantic)) => {
61 println!(" ✅ Unexpectedly succeeded!");
62 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
63 }
64 Err(msg) => println!(" ❌ Expected failure: {}", msg),
65 }
66}examples/complete_workflow.rs (line 103)
3fn main() {
4 println!("=== Complete Phase 1 & 2 Feature Demo ===\n");
5
6 // Demo: Complete workflow using all new features
7 println!("🏰 Generating Advanced Multi-Feature Dungeon\n");
8
9 // Step 1: Use pipeline template with custom parameters
10 println!("1. Pipeline Template Generation:");
11 let library = TemplateLibrary::new();
12 let template = library.get_template("simple_dungeon").unwrap();
13
14 let mut custom_params = std::collections::HashMap::new();
15 custom_params.insert("seed".to_string(), "12345".to_string());
16
17 let pipeline = template.instantiate(Some(custom_params));
18
19 let mut grid = Grid::new(40, 30);
20 let mut context = PipelineContext::new();
21 let mut rng = Rng::new(12345);
22
23 let result = pipeline.execute(&mut grid, &mut context, &mut rng);
24 println!(
25 " Template execution: {}",
26 if result.success {
27 "✅ Success"
28 } else {
29 "❌ Failed"
30 }
31 );
32 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
33
34 // Step 2: Extract semantic information
35 println!("\n2. Semantic Analysis:");
36 let extractor = SemanticExtractor::for_rooms();
37 let mut semantic = extractor.extract(&grid, &mut rng);
38
39 println!(" Regions found: {}", semantic.regions.len());
40 println!(" Original markers: {}", semantic.markers.len());
41
42 // Step 3: Add hierarchical markers based on regions
43 println!("\n3. Hierarchical Marker Placement:");
44 let mut quest_count = 0;
45 let mut loot_count = 0;
46 let mut encounter_count = 0;
47
48 for (i, region) in semantic.regions.iter().enumerate() {
49 if !region.cells.is_empty() {
50 let (x, y) = region.cells[region.cells.len() / 2]; // Middle of region
51
52 match i % 3 {
53 0 => {
54 // Quest area
55 semantic.markers.push(Marker::new(
56 x,
57 y,
58 MarkerType::QuestObjective {
59 priority: (i % 3 + 1) as u8,
60 },
61 ));
62 quest_count += 1;
63 }
64 1 => {
65 // Loot area
66 semantic.markers.push(Marker::new(
67 x,
68 y,
69 MarkerType::LootTier {
70 tier: (i % 3 + 1) as u8,
71 },
72 ));
73 loot_count += 1;
74 }
75 2 => {
76 // Encounter area
77 if i == 2 {
78 semantic
79 .markers
80 .push(Marker::new(x, y, MarkerType::BossRoom));
81 } else {
82 semantic.markers.push(Marker::new(
83 x,
84 y,
85 MarkerType::EncounterZone {
86 difficulty: (i % 5 + 1) as u8,
87 },
88 ));
89 }
90 encounter_count += 1;
91 }
92 _ => {}
93 }
94 }
95 }
96
97 println!(" Added {} quest markers", quest_count);
98 println!(" Added {} loot markers", loot_count);
99 println!(" Added {} encounter markers", encounter_count);
100
101 // Step 4: Validate with requirements
102 println!("\n4. Requirement Validation:");
103 let mut requirements = SemanticRequirements::none();
104 requirements.min_regions.insert("Hall".to_string(), 1);
105 requirements
106 .required_markers
107 .insert(MarkerType::Custom("PlayerStart".to_string()), 1);
108
109 let validation_result = requirements.validate(&semantic);
110 println!(
111 " Requirements met: {}",
112 if validation_result {
113 "✅ Yes"
114 } else {
115 "❌ No"
116 }
117 );
118
119 // Step 5: Marker constraints analysis
120 println!("\n5. Marker Constraint Analysis:");
121 let quest_constraints = MarkerConstraints::quest_objective();
122 let loot_constraints = MarkerConstraints::loot();
123
124 println!(" Quest marker constraints:");
125 println!(
126 " Min distance (same type): {:?}",
127 quest_constraints.min_distance_same
128 );
129 println!(
130 " Excluded types: {} types",
131 quest_constraints.exclude_types.len()
132 );
133
134 println!(" Loot marker constraints:");
135 println!(
136 " Min distance (same type): {:?}",
137 loot_constraints.min_distance_same
138 );
139 println!(
140 " Min distance (any): {:?}",
141 loot_constraints.min_distance_any
142 );
143
144 // Step 6: Multi-floor connectivity simulation
145 println!("\n6. Multi-Floor Connectivity:");
146
147 // Create a second floor based on the first
148 let mut floor2 = Grid::new(40, 30);
149 // Copy some areas from floor 1 to create overlapping regions
150 for y in 5..25 {
151 for x in 5..35 {
152 if grid.get(x, y).is_some_and(|t| t.is_floor()) && rng.random() < 0.6 {
153 floor2.set(x, y, terrain_forge::Tile::Floor);
154 }
155 }
156 }
157
158 let floors = vec![grid.clone(), floor2];
159 let mut connectivity = VerticalConnectivity::new();
160
161 connectivity.analyze_stair_candidates(&floors, 2);
162 connectivity.place_stairs(3);
163
164 println!(" Floor 1 tiles: {}", floors[0].count(|t| t.is_floor()));
165 println!(" Floor 2 tiles: {}", floors[1].count(|t| t.is_floor()));
166 println!(
167 " Stair candidates: {}",
168 connectivity.stair_candidates.len()
169 );
170 println!(" Stairs placed: {}", connectivity.stairs.len());
171
172 // Step 7: Final summary
173 println!("\n🎯 Generation Summary:");
174 println!(" Grid size: {}x{}", grid.width(), grid.height());
175 println!(" Total floor area: {}", grid.count(|t| t.is_floor()));
176 println!(
177 " Density: {:.1}%",
178 (grid.count(|t| t.is_floor()) as f32 / (grid.width() * grid.height()) as f32) * 100.0
179 );
180 println!(" Regions: {}", semantic.regions.len());
181 println!(" Total markers: {}", semantic.markers.len());
182
183 // Group markers by category
184 let mut categories = std::collections::HashMap::new();
185 for marker in &semantic.markers {
186 *categories.entry(marker.marker_type.category()).or_insert(0) += 1;
187 }
188
189 println!(" Marker distribution:");
190 for (category, count) in categories {
191 println!(" {}: {}", category, count);
192 }
193
194 println!(
195 " Pipeline steps executed: {}",
196 context.execution_history().len()
197 );
198 println!(" Multi-floor stairs: {}", connectivity.stairs.len());
199
200 println!("\n✨ Advanced dungeon generation complete!");
201}Sourcepub fn basic_dungeon() -> Self
pub fn basic_dungeon() -> Self
Create basic dungeon requirements
Examples found in repository?
examples/phase1_demo.rs (line 79)
76fn demo_generate_with_requirements() {
77 println!("📋 Demo 2: Generate with Requirements");
78
79 let mut requirements = SemanticRequirements::basic_dungeon();
80 requirements.min_regions.insert("room".to_string(), 4);
81 requirements
82 .required_markers
83 .insert(MarkerType::LootTier { tier: 1 }, 2);
84
85 match terrain_forge::generate_with_requirements("bsp", 60, 40, requirements, Some(5), 54321) {
86 Ok((grid, semantic)) => {
87 println!(" ✅ Generated valid dungeon!");
88 println!(" Regions: {}", semantic.regions.len());
89 println!(" Markers: {}", semantic.markers.len());
90 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
91 }
92 Err(msg) => println!(" ❌ Failed: {}", msg),
93 }
94 println!();
95}More examples
examples/requirement_generation.rs (line 8)
3fn main() {
4 println!("=== Requirement-Driven Generation Demo ===\n");
5
6 // Demo 1: Basic dungeon requirements
7 println!("1. Basic Dungeon Requirements:");
8 let basic_req = SemanticRequirements::basic_dungeon();
9
10 match generate_with_requirements("bsp", 40, 30, basic_req, Some(5), 12345) {
11 Ok((grid, semantic)) => {
12 println!(" ✅ Generated valid dungeon!");
13 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
14 println!(" Regions: {}", semantic.regions.len());
15 println!(" Markers: {}", semantic.markers.len());
16 }
17 Err(msg) => println!(" ❌ Failed: {}", msg),
18 }
19
20 // Demo 2: Custom requirements
21 println!("\n2. Custom Cave Requirements:");
22 let mut cave_req = SemanticRequirements::none();
23 cave_req.min_regions.insert("cavern".to_string(), 2);
24 cave_req.min_walkable_area = Some(200);
25 cave_req
26 .required_markers
27 .insert(MarkerType::Custom("entrance".to_string()), 1);
28 cave_req
29 .required_markers
30 .insert(MarkerType::Custom("treasure".to_string()), 1);
31
32 match generate_with_requirements("cellular", 50, 40, cave_req, Some(10), 54321) {
33 Ok((grid, semantic)) => {
34 println!(" ✅ Generated valid cave system!");
35 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
36 println!(" Regions: {}", semantic.regions.len());
37
38 // Show region types
39 let mut region_types = std::collections::HashMap::new();
40 for region in &semantic.regions {
41 *region_types.entry(®ion.kind).or_insert(0) += 1;
42 }
43 for (kind, count) in region_types {
44 println!(" {}: {}", kind, count);
45 }
46 }
47 Err(msg) => println!(" ❌ Failed: {}", msg),
48 }
49
50 // Demo 3: Strict requirements (likely to fail)
51 println!("\n3. Strict Requirements (demonstration of failure):");
52 let mut strict_req = SemanticRequirements::none();
53 strict_req.min_regions.insert("room".to_string(), 10); // Very strict
54 strict_req
55 .required_markers
56 .insert(MarkerType::QuestObjective { priority: 1 }, 5);
57 strict_req.min_walkable_area = Some(800);
58
59 match generate_with_requirements("bsp", 30, 20, strict_req, Some(3), 98765) {
60 Ok((grid, _semantic)) => {
61 println!(" ✅ Unexpectedly succeeded!");
62 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
63 }
64 Err(msg) => println!(" ❌ Expected failure: {}", msg),
65 }
66}Sourcepub fn validate(&self, layers: &SemanticLayers) -> bool
pub fn validate(&self, layers: &SemanticLayers) -> bool
Validate if semantic layers meet these requirements
Examples found in repository?
examples/complete_workflow.rs (line 109)
3fn main() {
4 println!("=== Complete Phase 1 & 2 Feature Demo ===\n");
5
6 // Demo: Complete workflow using all new features
7 println!("🏰 Generating Advanced Multi-Feature Dungeon\n");
8
9 // Step 1: Use pipeline template with custom parameters
10 println!("1. Pipeline Template Generation:");
11 let library = TemplateLibrary::new();
12 let template = library.get_template("simple_dungeon").unwrap();
13
14 let mut custom_params = std::collections::HashMap::new();
15 custom_params.insert("seed".to_string(), "12345".to_string());
16
17 let pipeline = template.instantiate(Some(custom_params));
18
19 let mut grid = Grid::new(40, 30);
20 let mut context = PipelineContext::new();
21 let mut rng = Rng::new(12345);
22
23 let result = pipeline.execute(&mut grid, &mut context, &mut rng);
24 println!(
25 " Template execution: {}",
26 if result.success {
27 "✅ Success"
28 } else {
29 "❌ Failed"
30 }
31 );
32 println!(" Floor tiles: {}", grid.count(|t| t.is_floor()));
33
34 // Step 2: Extract semantic information
35 println!("\n2. Semantic Analysis:");
36 let extractor = SemanticExtractor::for_rooms();
37 let mut semantic = extractor.extract(&grid, &mut rng);
38
39 println!(" Regions found: {}", semantic.regions.len());
40 println!(" Original markers: {}", semantic.markers.len());
41
42 // Step 3: Add hierarchical markers based on regions
43 println!("\n3. Hierarchical Marker Placement:");
44 let mut quest_count = 0;
45 let mut loot_count = 0;
46 let mut encounter_count = 0;
47
48 for (i, region) in semantic.regions.iter().enumerate() {
49 if !region.cells.is_empty() {
50 let (x, y) = region.cells[region.cells.len() / 2]; // Middle of region
51
52 match i % 3 {
53 0 => {
54 // Quest area
55 semantic.markers.push(Marker::new(
56 x,
57 y,
58 MarkerType::QuestObjective {
59 priority: (i % 3 + 1) as u8,
60 },
61 ));
62 quest_count += 1;
63 }
64 1 => {
65 // Loot area
66 semantic.markers.push(Marker::new(
67 x,
68 y,
69 MarkerType::LootTier {
70 tier: (i % 3 + 1) as u8,
71 },
72 ));
73 loot_count += 1;
74 }
75 2 => {
76 // Encounter area
77 if i == 2 {
78 semantic
79 .markers
80 .push(Marker::new(x, y, MarkerType::BossRoom));
81 } else {
82 semantic.markers.push(Marker::new(
83 x,
84 y,
85 MarkerType::EncounterZone {
86 difficulty: (i % 5 + 1) as u8,
87 },
88 ));
89 }
90 encounter_count += 1;
91 }
92 _ => {}
93 }
94 }
95 }
96
97 println!(" Added {} quest markers", quest_count);
98 println!(" Added {} loot markers", loot_count);
99 println!(" Added {} encounter markers", encounter_count);
100
101 // Step 4: Validate with requirements
102 println!("\n4. Requirement Validation:");
103 let mut requirements = SemanticRequirements::none();
104 requirements.min_regions.insert("Hall".to_string(), 1);
105 requirements
106 .required_markers
107 .insert(MarkerType::Custom("PlayerStart".to_string()), 1);
108
109 let validation_result = requirements.validate(&semantic);
110 println!(
111 " Requirements met: {}",
112 if validation_result {
113 "✅ Yes"
114 } else {
115 "❌ No"
116 }
117 );
118
119 // Step 5: Marker constraints analysis
120 println!("\n5. Marker Constraint Analysis:");
121 let quest_constraints = MarkerConstraints::quest_objective();
122 let loot_constraints = MarkerConstraints::loot();
123
124 println!(" Quest marker constraints:");
125 println!(
126 " Min distance (same type): {:?}",
127 quest_constraints.min_distance_same
128 );
129 println!(
130 " Excluded types: {} types",
131 quest_constraints.exclude_types.len()
132 );
133
134 println!(" Loot marker constraints:");
135 println!(
136 " Min distance (same type): {:?}",
137 loot_constraints.min_distance_same
138 );
139 println!(
140 " Min distance (any): {:?}",
141 loot_constraints.min_distance_any
142 );
143
144 // Step 6: Multi-floor connectivity simulation
145 println!("\n6. Multi-Floor Connectivity:");
146
147 // Create a second floor based on the first
148 let mut floor2 = Grid::new(40, 30);
149 // Copy some areas from floor 1 to create overlapping regions
150 for y in 5..25 {
151 for x in 5..35 {
152 if grid.get(x, y).is_some_and(|t| t.is_floor()) && rng.random() < 0.6 {
153 floor2.set(x, y, terrain_forge::Tile::Floor);
154 }
155 }
156 }
157
158 let floors = vec![grid.clone(), floor2];
159 let mut connectivity = VerticalConnectivity::new();
160
161 connectivity.analyze_stair_candidates(&floors, 2);
162 connectivity.place_stairs(3);
163
164 println!(" Floor 1 tiles: {}", floors[0].count(|t| t.is_floor()));
165 println!(" Floor 2 tiles: {}", floors[1].count(|t| t.is_floor()));
166 println!(
167 " Stair candidates: {}",
168 connectivity.stair_candidates.len()
169 );
170 println!(" Stairs placed: {}", connectivity.stairs.len());
171
172 // Step 7: Final summary
173 println!("\n🎯 Generation Summary:");
174 println!(" Grid size: {}x{}", grid.width(), grid.height());
175 println!(" Total floor area: {}", grid.count(|t| t.is_floor()));
176 println!(
177 " Density: {:.1}%",
178 (grid.count(|t| t.is_floor()) as f32 / (grid.width() * grid.height()) as f32) * 100.0
179 );
180 println!(" Regions: {}", semantic.regions.len());
181 println!(" Total markers: {}", semantic.markers.len());
182
183 // Group markers by category
184 let mut categories = std::collections::HashMap::new();
185 for marker in &semantic.markers {
186 *categories.entry(marker.marker_type.category()).or_insert(0) += 1;
187 }
188
189 println!(" Marker distribution:");
190 for (category, count) in categories {
191 println!(" {}: {}", category, count);
192 }
193
194 println!(
195 " Pipeline steps executed: {}",
196 context.execution_history().len()
197 );
198 println!(" Multi-floor stairs: {}", connectivity.stairs.len());
199
200 println!("\n✨ Advanced dungeon generation complete!");
201}Trait Implementations§
Source§impl Clone for SemanticRequirements
impl Clone for SemanticRequirements
Source§fn clone(&self) -> SemanticRequirements
fn clone(&self) -> SemanticRequirements
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreAuto Trait Implementations§
impl Freeze for SemanticRequirements
impl RefUnwindSafe for SemanticRequirements
impl Send for SemanticRequirements
impl Sync for SemanticRequirements
impl Unpin for SemanticRequirements
impl UnwindSafe for SemanticRequirements
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more