1use terrain_forge::{
6 algorithms::{PrefabConfig, PrefabData, PrefabLibrary, PrefabPlacer, PrefabTransform},
7 Algorithm, Grid, Rng, Tile,
8};
9
10fn main() {
11 println!("=== Advanced Prefab System Demo ===\n");
12
13 println!("1. Creating Prefab Library:");
15 let library = create_sample_library();
16
17 println!(
18 " Created library with {} prefabs:",
19 library.get_prefabs().len()
20 );
21 for prefab in library.get_prefabs() {
22 println!(
23 " - {} ({}x{}, weight: {:.1}, tags: {:?})",
24 prefab.name, prefab.width, prefab.height, prefab.weight, prefab.tags
25 );
26 }
27
28 println!("\n2. Weighted Selection Test:");
30 let mut rng = Rng::new(12345);
31 let mut selection_counts = std::collections::HashMap::new();
32
33 for _ in 0..100 {
34 if let Some(prefab) = library.select_weighted(&mut rng, None) {
35 *selection_counts.entry(prefab.name.clone()).or_insert(0) += 1;
36 }
37 }
38
39 println!(" Selection frequency (100 trials):");
40 for (name, count) in &selection_counts {
41 println!(" {}: {} times", name, count);
42 }
43
44 println!("\n3. Tag-based Selection:");
46 let room_prefabs = library.get_by_tag("room");
47 let corridor_prefabs = library.get_by_tag("corridor");
48
49 println!(" Room prefabs: {}", room_prefabs.len());
50 for prefab in &room_prefabs {
51 println!(" - {}", prefab.name);
52 }
53
54 println!(" Corridor prefabs: {}", corridor_prefabs.len());
55 for prefab in &corridor_prefabs {
56 println!(" - {}", prefab.name);
57 }
58
59 println!("\n4. Prefab Transformations:");
61 if let Some(base_prefab) = library.get_prefabs().first() {
62 println!(
63 " Base prefab '{}' ({}x{}):",
64 base_prefab.name, base_prefab.width, base_prefab.height
65 );
66 print_prefab_pattern(base_prefab);
67
68 let rotated = base_prefab.rotated();
70 println!(
71 " After 90° rotation ({}x{}):",
72 rotated.width, rotated.height
73 );
74 print_prefab_pattern(&rotated);
75
76 let mirrored = base_prefab.mirrored_horizontal();
78 println!(
79 " After horizontal mirror ({}x{}):",
80 mirrored.width, mirrored.height
81 );
82 print_prefab_pattern(&mirrored);
83
84 let transform = PrefabTransform {
86 rotation: 1,
87 mirror_h: true,
88 mirror_v: false,
89 };
90 let transformed = transform.apply(base_prefab);
91 println!(
92 " After rotation + mirror ({}x{}):",
93 transformed.width, transformed.height
94 );
95 print_prefab_pattern(&transformed);
96 }
97
98 println!("\n5. Generation with Advanced Prefabs:");
100 let config = PrefabConfig {
101 max_prefabs: 5,
102 min_spacing: 3,
103 allow_rotation: true,
104 allow_mirroring: true,
105 weighted_selection: true,
106 placement_mode: terrain_forge::algorithms::PrefabPlacementMode::Overwrite,
107 tags: None,
108 };
109
110 let placer = PrefabPlacer::new(config, library.clone());
111 let mut grid = Grid::new(30, 25);
112 placer.generate(&mut grid, 54321);
113
114 let floor_count = grid.count(|t| t.is_floor());
115 println!(
116 " Generated {}x{} grid with {} floor tiles",
117 grid.width(),
118 grid.height(),
119 floor_count
120 );
121
122 print_grid(&grid);
123
124 println!("\n6. JSON Serialization:");
126 match library.save_to_json("prefab_library.json") {
127 Ok(()) => {
128 println!(" ✅ Saved library to prefab_library.json");
129
130 match PrefabLibrary::load_from_json("prefab_library.json") {
132 Ok(loaded_library) => {
133 println!(" ✅ Successfully loaded library back");
134 println!(" Loaded {} prefabs", loaded_library.get_prefabs().len());
135 }
136 Err(e) => println!(" ❌ Failed to load: {}", e),
137 }
138 }
139 Err(e) => println!(" ❌ Failed to save: {}", e),
140 }
141
142 println!("\n7. Performance Comparison:");
144
145 let simple_config = PrefabConfig {
147 max_prefabs: 10,
148 min_spacing: 2,
149 allow_rotation: false,
150 allow_mirroring: false,
151 weighted_selection: false,
152 placement_mode: terrain_forge::algorithms::PrefabPlacementMode::Overwrite,
153 tags: None,
154 };
155
156 let start = std::time::Instant::now();
157 let simple_placer = PrefabPlacer::new(simple_config, library.clone());
158 let mut simple_grid = Grid::new(40, 30);
159 simple_placer.generate(&mut simple_grid, 98765);
160 let simple_time = start.elapsed();
161
162 let advanced_config = PrefabConfig {
164 max_prefabs: 10,
165 min_spacing: 2,
166 allow_rotation: true,
167 allow_mirroring: true,
168 weighted_selection: true,
169 placement_mode: terrain_forge::algorithms::PrefabPlacementMode::Overwrite,
170 tags: None,
171 };
172
173 let start = std::time::Instant::now();
174 let advanced_placer = PrefabPlacer::new(advanced_config, library);
175 let mut advanced_grid = Grid::new(40, 30);
176 advanced_placer.generate(&mut advanced_grid, 98765);
177 let advanced_time = start.elapsed();
178
179 println!(" Simple generation: {:?}", simple_time);
180 println!(" Advanced generation: {:?}", advanced_time);
181 println!(
182 " Overhead: {:.1}x",
183 advanced_time.as_nanos() as f32 / simple_time.as_nanos() as f32
184 );
185
186 println!("\n✅ Advanced prefab system demo complete!");
187 println!(" - JSON serialization for persistent libraries");
188 println!(" - Weighted selection for balanced generation");
189 println!(" - Transformations for variety and reuse");
190 println!(" - Tag-based organization for targeted selection");
191}
192
193fn create_sample_library() -> PrefabLibrary {
194 let mut library = PrefabLibrary::new();
195
196 let small_room = PrefabData {
198 name: "small_room".to_string(),
199 width: 5,
200 height: 5,
201 pattern: vec![
202 "#####".to_string(),
203 "#...#".to_string(),
204 "#...#".to_string(),
205 "#...#".to_string(),
206 "#####".to_string(),
207 ],
208 weight: 3.0,
209 tags: vec!["room".to_string(), "small".to_string()],
210 legend: None,
211 };
212 library.add_prefab(terrain_forge::algorithms::Prefab::from_data(small_room));
213
214 let large_room = PrefabData {
216 name: "large_room".to_string(),
217 width: 7,
218 height: 6,
219 pattern: vec![
220 "#######".to_string(),
221 "#.....#".to_string(),
222 "#.....#".to_string(),
223 "#.....#".to_string(),
224 "#.....#".to_string(),
225 "#######".to_string(),
226 ],
227 weight: 1.5,
228 tags: vec!["room".to_string(), "large".to_string()],
229 legend: None,
230 };
231 library.add_prefab(terrain_forge::algorithms::Prefab::from_data(large_room));
232
233 let corridor = PrefabData {
235 name: "corridor".to_string(),
236 width: 7,
237 height: 3,
238 pattern: vec![
239 "#######".to_string(),
240 ".......".to_string(),
241 "#######".to_string(),
242 ],
243 weight: 0.8,
244 tags: vec!["corridor".to_string(), "connection".to_string()],
245 legend: None,
246 };
247 library.add_prefab(terrain_forge::algorithms::Prefab::from_data(corridor));
248
249 let mut legend = std::collections::HashMap::new();
251 legend.insert(
252 "M".to_string(),
253 terrain_forge::algorithms::PrefabLegendEntry {
254 tile: Some("floor".to_string()),
255 marker: Some("loot_slot".to_string()),
256 mask: None,
257 },
258 );
259 let l_room = PrefabData {
260 name: "l_shaped_room".to_string(),
261 width: 6,
262 height: 6,
263 pattern: vec![
264 "######".to_string(),
265 "#....#".to_string(),
266 "#....#".to_string(),
267 "#..M##".to_string(),
268 "#..###".to_string(),
269 "######".to_string(),
270 ],
271 weight: 0.5,
272 tags: vec![
273 "room".to_string(),
274 "special".to_string(),
275 "l_shaped".to_string(),
276 ],
277 legend: Some(legend),
278 };
279 library.add_prefab(terrain_forge::algorithms::Prefab::from_data(l_room));
280
281 library
282}
283
284fn print_prefab_pattern(prefab: &terrain_forge::algorithms::Prefab) {
285 for y in 0..prefab.height {
286 print!(" ");
287 for x in 0..prefab.width {
288 print!("{}", if prefab.get(x, y) { "." } else { "#" });
289 }
290 println!();
291 }
292}
293
294fn print_grid(grid: &Grid<Tile>) {
295 println!(" Generated layout:");
296 for y in 0..grid.height().min(12) {
297 print!(" ");
298 for x in 0..grid.width() {
299 let tile = grid.get(x as i32, y as i32).unwrap();
300 print!("{}", if tile.is_floor() { "." } else { "#" });
301 }
302 println!();
303 }
304 if grid.height() > 12 {
305 println!(" ... ({} more rows)", grid.height() - 12);
306 }
307}