Skip to main content

VerticalConnectivity

Struct VerticalConnectivity 

Source
pub struct VerticalConnectivity {
    pub stair_candidates: Vec<(u32, u32, u32, u32)>,
    pub stairs: Vec<(u32, u32, u32, u32)>,
    pub floor_accessibility: HashMap<u32, Vec<u32>>,
}
Expand description

Vertical connectivity analysis for multi-floor support

Fields§

§stair_candidates: Vec<(u32, u32, u32, u32)>

Potential stair locations (x, y, floor_from, floor_to)

§stairs: Vec<(u32, u32, u32, u32)>

Confirmed stair placements

§floor_accessibility: HashMap<u32, Vec<u32>>

Regions accessible from each floor

Implementations§

Source§

impl VerticalConnectivity

Source

pub fn new() -> Self

Create empty vertical connectivity analysis

Examples found in repository?
examples/phase1_demo.rs (line 113)
97fn demo_vertical_connectivity() {
98    println!("🏗️ Demo 3: Vertical Connectivity");
99
100    // Create two simple floor grids
101    let mut floor1 = Grid::new(20, 20);
102    let mut floor2 = Grid::new(20, 20);
103
104    // Add some floor areas
105    for y in 5..15 {
106        for x in 5..15 {
107            floor1.set(x, y, terrain_forge::Tile::Floor);
108            floor2.set(x, y, terrain_forge::Tile::Floor);
109        }
110    }
111
112    let floors = vec![floor1, floor2];
113    let mut connectivity = VerticalConnectivity::new();
114
115    connectivity.analyze_stair_candidates(&floors, 2);
116    connectivity.place_stairs(3);
117
118    println!(
119        "  Stair candidates found: {}",
120        connectivity.stair_candidates.len()
121    );
122    println!("  Stairs placed: {}", connectivity.stairs.len());
123
124    if let Some((x, y, from, to)) = connectivity.stairs.first() {
125        println!(
126            "  Sample stair: ({}, {}) connecting floor {} to {}",
127            x, y, from, to
128        );
129    }
130    println!();
131}
More examples
Hide additional examples
examples/vertical_connectivity.rs (line 56)
3fn main() {
4    println!("=== Vertical Connectivity Demo ===\n");
5
6    // Create two floors for a multi-level dungeon
7    let mut floor1 = Grid::new(25, 20);
8    let mut floor2 = Grid::new(25, 20);
9
10    // Floor 1: Large central room with corridors
11    for y in 5..15 {
12        for x in 5..20 {
13            floor1.set(x, y, Tile::Floor);
14        }
15    }
16    // Add some corridors
17    for x in 2..5 {
18        for y in 8..12 {
19            floor1.set(x, y, Tile::Floor);
20        }
21    }
22
23    // Floor 2: Multiple smaller rooms
24    // Room 1
25    for y in 3..8 {
26        for x in 3..10 {
27            floor2.set(x, y, Tile::Floor);
28        }
29    }
30    // Room 2
31    for y in 12..17 {
32        for x in 8..18 {
33            floor2.set(x, y, Tile::Floor);
34        }
35    }
36    // Room 3
37    for y in 6..12 {
38        for x in 15..22 {
39            floor2.set(x, y, Tile::Floor);
40        }
41    }
42
43    let floors = vec![floor1, floor2];
44
45    println!("Created 2-floor dungeon:");
46    println!(
47        "  Floor 1: {} floor tiles",
48        floors[0].count(|t| t.is_floor())
49    );
50    println!(
51        "  Floor 2: {} floor tiles",
52        floors[1].count(|t| t.is_floor())
53    );
54
55    // Analyze vertical connectivity
56    let mut connectivity = VerticalConnectivity::new();
57
58    // Find stair candidates with different clearance requirements
59    println!("\n1. Stair Candidate Analysis:");
60
61    connectivity.analyze_stair_candidates(&floors, 1); // Minimal clearance
62    println!(
63        "  With 1-tile clearance: {} candidates",
64        connectivity.stair_candidates.len()
65    );
66
67    connectivity.analyze_stair_candidates(&floors, 2); // More clearance
68    println!(
69        "  With 2-tile clearance: {} candidates",
70        connectivity.stair_candidates.len()
71    );
72
73    connectivity.analyze_stair_candidates(&floors, 3); // Maximum clearance
74    println!(
75        "  With 3-tile clearance: {} candidates",
76        connectivity.stair_candidates.len()
77    );
78
79    // Place stairs with different limits
80    println!("\n2. Stair Placement:");
81
82    connectivity.place_stairs(1);
83    println!("  Placed {} stairs (max 1)", connectivity.stairs.len());
84
85    connectivity.place_stairs(3);
86    println!("  Placed {} stairs (max 3)", connectivity.stairs.len());
87
88    connectivity.place_stairs(5);
89    println!("  Placed {} stairs (max 5)", connectivity.stairs.len());
90
91    // Show stair locations
92    println!("\n3. Stair Locations:");
93    for (i, &(x, y, from_floor, to_floor)) in connectivity.stairs.iter().enumerate() {
94        println!(
95            "  Stair {}: ({}, {}) connecting floor {} to floor {}",
96            i + 1,
97            x,
98            y,
99            from_floor,
100            to_floor
101        );
102    }
103
104    // Demonstrate with 3 floors
105    println!("\n4. Three-Floor Example:");
106
107    let mut floor3 = Grid::new(25, 20);
108    // Floor 3: Single large room
109    for y in 6..14 {
110        for x in 6..19 {
111            floor3.set(x, y, Tile::Floor);
112        }
113    }
114
115    let three_floors = vec![floors[0].clone(), floors[1].clone(), floor3];
116    let mut connectivity3 = VerticalConnectivity::new();
117
118    connectivity3.analyze_stair_candidates(&three_floors, 2);
119    connectivity3.place_stairs(2);
120
121    println!(
122        "  Floor 3: {} floor tiles",
123        three_floors[2].count(|t| t.is_floor())
124    );
125    println!(
126        "  Total stair candidates: {}",
127        connectivity3.stair_candidates.len()
128    );
129    println!("  Stairs placed: {}", connectivity3.stairs.len());
130
131    // Group stairs by floor connection
132    let mut connections = std::collections::HashMap::new();
133    for &(_, _, from, to) in &connectivity3.stairs {
134        *connections.entry((from, to)).or_insert(0) += 1;
135    }
136
137    println!("  Floor connections:");
138    for ((from, to), count) in connections {
139        println!("    Floor {} ↔ Floor {}: {} stairs", from, to, count);
140    }
141}
examples/complete_workflow.rs (line 159)
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}
Source

pub fn analyze_stair_candidates( &mut self, floor_grids: &[Grid<Tile>], min_clearance: usize, )

Analyze potential stair placements between floors This is a basic implementation that looks for suitable floor tiles adjacent to walls that could support stairs

Examples found in repository?
examples/phase1_demo.rs (line 115)
97fn demo_vertical_connectivity() {
98    println!("🏗️ Demo 3: Vertical Connectivity");
99
100    // Create two simple floor grids
101    let mut floor1 = Grid::new(20, 20);
102    let mut floor2 = Grid::new(20, 20);
103
104    // Add some floor areas
105    for y in 5..15 {
106        for x in 5..15 {
107            floor1.set(x, y, terrain_forge::Tile::Floor);
108            floor2.set(x, y, terrain_forge::Tile::Floor);
109        }
110    }
111
112    let floors = vec![floor1, floor2];
113    let mut connectivity = VerticalConnectivity::new();
114
115    connectivity.analyze_stair_candidates(&floors, 2);
116    connectivity.place_stairs(3);
117
118    println!(
119        "  Stair candidates found: {}",
120        connectivity.stair_candidates.len()
121    );
122    println!("  Stairs placed: {}", connectivity.stairs.len());
123
124    if let Some((x, y, from, to)) = connectivity.stairs.first() {
125        println!(
126            "  Sample stair: ({}, {}) connecting floor {} to {}",
127            x, y, from, to
128        );
129    }
130    println!();
131}
More examples
Hide additional examples
examples/vertical_connectivity.rs (line 61)
3fn main() {
4    println!("=== Vertical Connectivity Demo ===\n");
5
6    // Create two floors for a multi-level dungeon
7    let mut floor1 = Grid::new(25, 20);
8    let mut floor2 = Grid::new(25, 20);
9
10    // Floor 1: Large central room with corridors
11    for y in 5..15 {
12        for x in 5..20 {
13            floor1.set(x, y, Tile::Floor);
14        }
15    }
16    // Add some corridors
17    for x in 2..5 {
18        for y in 8..12 {
19            floor1.set(x, y, Tile::Floor);
20        }
21    }
22
23    // Floor 2: Multiple smaller rooms
24    // Room 1
25    for y in 3..8 {
26        for x in 3..10 {
27            floor2.set(x, y, Tile::Floor);
28        }
29    }
30    // Room 2
31    for y in 12..17 {
32        for x in 8..18 {
33            floor2.set(x, y, Tile::Floor);
34        }
35    }
36    // Room 3
37    for y in 6..12 {
38        for x in 15..22 {
39            floor2.set(x, y, Tile::Floor);
40        }
41    }
42
43    let floors = vec![floor1, floor2];
44
45    println!("Created 2-floor dungeon:");
46    println!(
47        "  Floor 1: {} floor tiles",
48        floors[0].count(|t| t.is_floor())
49    );
50    println!(
51        "  Floor 2: {} floor tiles",
52        floors[1].count(|t| t.is_floor())
53    );
54
55    // Analyze vertical connectivity
56    let mut connectivity = VerticalConnectivity::new();
57
58    // Find stair candidates with different clearance requirements
59    println!("\n1. Stair Candidate Analysis:");
60
61    connectivity.analyze_stair_candidates(&floors, 1); // Minimal clearance
62    println!(
63        "  With 1-tile clearance: {} candidates",
64        connectivity.stair_candidates.len()
65    );
66
67    connectivity.analyze_stair_candidates(&floors, 2); // More clearance
68    println!(
69        "  With 2-tile clearance: {} candidates",
70        connectivity.stair_candidates.len()
71    );
72
73    connectivity.analyze_stair_candidates(&floors, 3); // Maximum clearance
74    println!(
75        "  With 3-tile clearance: {} candidates",
76        connectivity.stair_candidates.len()
77    );
78
79    // Place stairs with different limits
80    println!("\n2. Stair Placement:");
81
82    connectivity.place_stairs(1);
83    println!("  Placed {} stairs (max 1)", connectivity.stairs.len());
84
85    connectivity.place_stairs(3);
86    println!("  Placed {} stairs (max 3)", connectivity.stairs.len());
87
88    connectivity.place_stairs(5);
89    println!("  Placed {} stairs (max 5)", connectivity.stairs.len());
90
91    // Show stair locations
92    println!("\n3. Stair Locations:");
93    for (i, &(x, y, from_floor, to_floor)) in connectivity.stairs.iter().enumerate() {
94        println!(
95            "  Stair {}: ({}, {}) connecting floor {} to floor {}",
96            i + 1,
97            x,
98            y,
99            from_floor,
100            to_floor
101        );
102    }
103
104    // Demonstrate with 3 floors
105    println!("\n4. Three-Floor Example:");
106
107    let mut floor3 = Grid::new(25, 20);
108    // Floor 3: Single large room
109    for y in 6..14 {
110        for x in 6..19 {
111            floor3.set(x, y, Tile::Floor);
112        }
113    }
114
115    let three_floors = vec![floors[0].clone(), floors[1].clone(), floor3];
116    let mut connectivity3 = VerticalConnectivity::new();
117
118    connectivity3.analyze_stair_candidates(&three_floors, 2);
119    connectivity3.place_stairs(2);
120
121    println!(
122        "  Floor 3: {} floor tiles",
123        three_floors[2].count(|t| t.is_floor())
124    );
125    println!(
126        "  Total stair candidates: {}",
127        connectivity3.stair_candidates.len()
128    );
129    println!("  Stairs placed: {}", connectivity3.stairs.len());
130
131    // Group stairs by floor connection
132    let mut connections = std::collections::HashMap::new();
133    for &(_, _, from, to) in &connectivity3.stairs {
134        *connections.entry((from, to)).or_insert(0) += 1;
135    }
136
137    println!("  Floor connections:");
138    for ((from, to), count) in connections {
139        println!("    Floor {} ↔ Floor {}: {} stairs", from, to, count);
140    }
141}
examples/complete_workflow.rs (line 161)
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}
Source

pub fn place_stairs(&mut self, max_stairs_per_floor: usize)

Place stairs at the best candidate locations

Examples found in repository?
examples/phase1_demo.rs (line 116)
97fn demo_vertical_connectivity() {
98    println!("🏗️ Demo 3: Vertical Connectivity");
99
100    // Create two simple floor grids
101    let mut floor1 = Grid::new(20, 20);
102    let mut floor2 = Grid::new(20, 20);
103
104    // Add some floor areas
105    for y in 5..15 {
106        for x in 5..15 {
107            floor1.set(x, y, terrain_forge::Tile::Floor);
108            floor2.set(x, y, terrain_forge::Tile::Floor);
109        }
110    }
111
112    let floors = vec![floor1, floor2];
113    let mut connectivity = VerticalConnectivity::new();
114
115    connectivity.analyze_stair_candidates(&floors, 2);
116    connectivity.place_stairs(3);
117
118    println!(
119        "  Stair candidates found: {}",
120        connectivity.stair_candidates.len()
121    );
122    println!("  Stairs placed: {}", connectivity.stairs.len());
123
124    if let Some((x, y, from, to)) = connectivity.stairs.first() {
125        println!(
126            "  Sample stair: ({}, {}) connecting floor {} to {}",
127            x, y, from, to
128        );
129    }
130    println!();
131}
More examples
Hide additional examples
examples/vertical_connectivity.rs (line 82)
3fn main() {
4    println!("=== Vertical Connectivity Demo ===\n");
5
6    // Create two floors for a multi-level dungeon
7    let mut floor1 = Grid::new(25, 20);
8    let mut floor2 = Grid::new(25, 20);
9
10    // Floor 1: Large central room with corridors
11    for y in 5..15 {
12        for x in 5..20 {
13            floor1.set(x, y, Tile::Floor);
14        }
15    }
16    // Add some corridors
17    for x in 2..5 {
18        for y in 8..12 {
19            floor1.set(x, y, Tile::Floor);
20        }
21    }
22
23    // Floor 2: Multiple smaller rooms
24    // Room 1
25    for y in 3..8 {
26        for x in 3..10 {
27            floor2.set(x, y, Tile::Floor);
28        }
29    }
30    // Room 2
31    for y in 12..17 {
32        for x in 8..18 {
33            floor2.set(x, y, Tile::Floor);
34        }
35    }
36    // Room 3
37    for y in 6..12 {
38        for x in 15..22 {
39            floor2.set(x, y, Tile::Floor);
40        }
41    }
42
43    let floors = vec![floor1, floor2];
44
45    println!("Created 2-floor dungeon:");
46    println!(
47        "  Floor 1: {} floor tiles",
48        floors[0].count(|t| t.is_floor())
49    );
50    println!(
51        "  Floor 2: {} floor tiles",
52        floors[1].count(|t| t.is_floor())
53    );
54
55    // Analyze vertical connectivity
56    let mut connectivity = VerticalConnectivity::new();
57
58    // Find stair candidates with different clearance requirements
59    println!("\n1. Stair Candidate Analysis:");
60
61    connectivity.analyze_stair_candidates(&floors, 1); // Minimal clearance
62    println!(
63        "  With 1-tile clearance: {} candidates",
64        connectivity.stair_candidates.len()
65    );
66
67    connectivity.analyze_stair_candidates(&floors, 2); // More clearance
68    println!(
69        "  With 2-tile clearance: {} candidates",
70        connectivity.stair_candidates.len()
71    );
72
73    connectivity.analyze_stair_candidates(&floors, 3); // Maximum clearance
74    println!(
75        "  With 3-tile clearance: {} candidates",
76        connectivity.stair_candidates.len()
77    );
78
79    // Place stairs with different limits
80    println!("\n2. Stair Placement:");
81
82    connectivity.place_stairs(1);
83    println!("  Placed {} stairs (max 1)", connectivity.stairs.len());
84
85    connectivity.place_stairs(3);
86    println!("  Placed {} stairs (max 3)", connectivity.stairs.len());
87
88    connectivity.place_stairs(5);
89    println!("  Placed {} stairs (max 5)", connectivity.stairs.len());
90
91    // Show stair locations
92    println!("\n3. Stair Locations:");
93    for (i, &(x, y, from_floor, to_floor)) in connectivity.stairs.iter().enumerate() {
94        println!(
95            "  Stair {}: ({}, {}) connecting floor {} to floor {}",
96            i + 1,
97            x,
98            y,
99            from_floor,
100            to_floor
101        );
102    }
103
104    // Demonstrate with 3 floors
105    println!("\n4. Three-Floor Example:");
106
107    let mut floor3 = Grid::new(25, 20);
108    // Floor 3: Single large room
109    for y in 6..14 {
110        for x in 6..19 {
111            floor3.set(x, y, Tile::Floor);
112        }
113    }
114
115    let three_floors = vec![floors[0].clone(), floors[1].clone(), floor3];
116    let mut connectivity3 = VerticalConnectivity::new();
117
118    connectivity3.analyze_stair_candidates(&three_floors, 2);
119    connectivity3.place_stairs(2);
120
121    println!(
122        "  Floor 3: {} floor tiles",
123        three_floors[2].count(|t| t.is_floor())
124    );
125    println!(
126        "  Total stair candidates: {}",
127        connectivity3.stair_candidates.len()
128    );
129    println!("  Stairs placed: {}", connectivity3.stairs.len());
130
131    // Group stairs by floor connection
132    let mut connections = std::collections::HashMap::new();
133    for &(_, _, from, to) in &connectivity3.stairs {
134        *connections.entry((from, to)).or_insert(0) += 1;
135    }
136
137    println!("  Floor connections:");
138    for ((from, to), count) in connections {
139        println!("    Floor {} ↔ Floor {}: {} stairs", from, to, count);
140    }
141}
examples/complete_workflow.rs (line 162)
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 VerticalConnectivity

Source§

fn clone(&self) -> VerticalConnectivity

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for VerticalConnectivity

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for VerticalConnectivity

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V