1use narrative_engine::core::grammar::GrammarSet;
11use narrative_engine::core::markov::MarkovTrainer;
12use narrative_engine::core::pipeline::{NarrativeEngine, WorldState};
13use narrative_engine::core::voice::VoiceRegistry;
14use narrative_engine::schema::entity::{Entity, EntityId, Pronouns, VoiceId};
15use narrative_engine::schema::event::{EntityRef, Event, Mood, Stakes};
16use narrative_engine::schema::narrative_fn::NarrativeFunction;
17use std::collections::HashMap;
18
19fn main() {
20 let grammars = GrammarSet::load_from_ron(std::path::Path::new(
22 "genre_data/survival_thriller/grammar.ron",
23 ))
24 .expect("Failed to load survival thriller grammar");
25
26 let mut voices = VoiceRegistry::new();
27 voices
28 .load_from_ron(std::path::Path::new(
29 "genre_data/survival_thriller/voices.ron",
30 ))
31 .expect("Failed to load survival thriller voices");
32
33 let corpus = std::fs::read_to_string("genre_data/survival_thriller/corpus.txt")
35 .expect("Failed to read survival thriller corpus");
36 let markov_model = MarkovTrainer::train(&corpus, 3);
37
38 let mut markov_models = HashMap::new();
39 markov_models.insert("survival_thriller".to_string(), markov_model);
40
41 let mut engine = NarrativeEngine::builder()
42 .seed(1993)
43 .with_grammars(grammars)
44 .with_voices(voices)
45 .with_markov_models(markov_models)
46 .build()
47 .expect("Failed to build engine");
48
49 let mut entities = HashMap::new();
51
52 entities.insert(
54 EntityId(1),
55 Entity {
56 id: EntityId(1),
57 name: "Dr. Grant".to_string(),
58 pronouns: Pronouns::HeHim,
59 tags: [
60 "scientist".to_string(),
61 "determined".to_string(),
62 "field_expert".to_string(),
63 ]
64 .into_iter()
65 .collect(),
66 relationships: Vec::new(),
67 voice_id: Some(VoiceId(202)), properties: HashMap::new(),
69 },
70 );
71
72 entities.insert(
74 EntityId(2),
75 Entity {
76 id: EntityId(2),
77 name: "Dr. Malcolm".to_string(),
78 pronouns: Pronouns::HeHim,
79 tags: [
80 "scientist".to_string(),
81 "skeptic".to_string(),
82 "charismatic".to_string(),
83 ]
84 .into_iter()
85 .collect(),
86 relationships: Vec::new(),
87 voice_id: Some(VoiceId(202)), properties: HashMap::new(),
89 },
90 );
91
92 entities.insert(
94 EntityId(3),
95 Entity {
96 id: EntityId(3),
97 name: "Muldoon".to_string(),
98 pronouns: Pronouns::HeHim,
99 tags: [
100 "hunter".to_string(),
101 "pragmatic".to_string(),
102 "alert".to_string(),
103 ]
104 .into_iter()
105 .collect(),
106 relationships: Vec::new(),
107 voice_id: Some(VoiceId(201)), properties: HashMap::new(),
109 },
110 );
111
112 entities.insert(
114 EntityId(10),
115 Entity {
116 id: EntityId(10),
117 name: "Control Room".to_string(),
118 pronouns: Pronouns::ItIts,
119 tags: [
120 "location".to_string(),
121 "technology".to_string(),
122 "enclosed".to_string(),
123 ]
124 .into_iter()
125 .collect(),
126 relationships: Vec::new(),
127 voice_id: None,
128 properties: HashMap::new(),
129 },
130 );
131
132 entities.insert(
134 EntityId(11),
135 Entity {
136 id: EntityId(11),
137 name: "Rex Paddock".to_string(),
138 pronouns: Pronouns::ItIts,
139 tags: [
140 "location".to_string(),
141 "dangerous".to_string(),
142 "perimeter".to_string(),
143 ]
144 .into_iter()
145 .collect(),
146 relationships: Vec::new(),
147 voice_id: None,
148 properties: HashMap::new(),
149 },
150 );
151
152 entities.insert(
154 EntityId(12),
155 Entity {
156 id: EntityId(12),
157 name: "Raptor Pen".to_string(),
158 pronouns: Pronouns::ItIts,
159 tags: [
160 "location".to_string(),
161 "dangerous".to_string(),
162 "high_security".to_string(),
163 ]
164 .into_iter()
165 .collect(),
166 relationships: Vec::new(),
167 voice_id: None,
168 properties: HashMap::new(),
169 },
170 );
171
172 entities.insert(
174 EntityId(20),
175 Entity {
176 id: EntityId(20),
177 name: "Security System".to_string(),
178 pronouns: Pronouns::ItIts,
179 tags: ["system".to_string(), "automated".to_string()]
180 .into_iter()
181 .collect(),
182 relationships: Vec::new(),
183 voice_id: None,
184 properties: HashMap::new(),
185 },
186 );
187
188 let world = WorldState {
189 entities: &entities,
190 };
191
192 println!("========================================");
194 println!(" DINO PARK INCIDENT REPORT");
195 println!(" [CLASSIFIED — Park Security]");
196 println!("========================================");
197 println!();
198
199 let event1 = Event {
202 event_type: "routine_check".to_string(),
203 participants: vec![EntityRef {
204 entity_id: EntityId(3),
205 role: "subject".to_string(),
206 }],
207 location: Some(EntityRef {
208 entity_id: EntityId(10),
209 role: "location".to_string(),
210 }),
211 mood: Mood::Neutral,
212 stakes: Stakes::Low,
213 outcome: None,
214 narrative_fn: NarrativeFunction::StatusChange,
215 metadata: HashMap::new(),
216 };
217 print_scene(
218 1,
219 "0600 — Morning Status Report",
220 "RADIO OPERATOR",
221 &mut engine,
222 &event1,
223 &world,
224 Some(VoiceId(200)),
225 );
226
227 let event2 = Event {
230 event_type: "power_fluctuation".to_string(),
231 participants: vec![EntityRef {
232 entity_id: EntityId(1),
233 role: "subject".to_string(),
234 }],
235 location: Some(EntityRef {
236 entity_id: EntityId(10),
237 role: "location".to_string(),
238 }),
239 mood: Mood::Neutral,
240 stakes: Stakes::Medium,
241 outcome: None,
242 narrative_fn: NarrativeFunction::Foreshadowing,
243 metadata: HashMap::new(),
244 };
245 print_scene(
246 2,
247 "1430 — Power Fluctuation Detected",
248 "NARRATOR",
249 &mut engine,
250 &event2,
251 &world,
252 Some(VoiceId(203)),
253 );
254
255 let event3 = Event {
258 event_type: "perimeter_breach".to_string(),
259 participants: vec![EntityRef {
260 entity_id: EntityId(3),
261 role: "subject".to_string(),
262 }],
263 location: Some(EntityRef {
264 entity_id: EntityId(11),
265 role: "location".to_string(),
266 }),
267 mood: Mood::Dread,
268 stakes: Stakes::High,
269 outcome: None,
270 narrative_fn: NarrativeFunction::Escalation,
271 metadata: HashMap::new(),
272 };
273 print_scene(
274 3,
275 "2247 — Perimeter Breach: Rex Paddock",
276 "RADIO OPERATOR",
277 &mut engine,
278 &event3,
279 &world,
280 Some(VoiceId(200)),
281 );
282
283 let event4 = Event {
286 event_type: "systems_failing".to_string(),
287 participants: vec![
288 EntityRef {
289 entity_id: EntityId(1),
290 role: "subject".to_string(),
291 },
292 EntityRef {
293 entity_id: EntityId(2),
294 role: "object".to_string(),
295 },
296 ],
297 location: Some(EntityRef {
298 entity_id: EntityId(10),
299 role: "location".to_string(),
300 }),
301 mood: Mood::Chaotic,
302 stakes: Stakes::Critical,
303 outcome: None,
304 narrative_fn: NarrativeFunction::Escalation,
305 metadata: HashMap::new(),
306 };
307 print_scene(
308 4,
309 "2253 — Multiple System Failures",
310 "NARRATOR",
311 &mut engine,
312 &event4,
313 &world,
314 Some(VoiceId(203)),
315 );
316
317 let event5 = Event {
320 event_type: "damage_assessment".to_string(),
321 participants: vec![EntityRef {
322 entity_id: EntityId(1),
323 role: "subject".to_string(),
324 }],
325 location: Some(EntityRef {
326 entity_id: EntityId(12),
327 role: "location".to_string(),
328 }),
329 mood: Mood::Dread,
330 stakes: Stakes::High,
331 outcome: None,
332 narrative_fn: NarrativeFunction::Discovery,
333 metadata: HashMap::new(),
334 };
335 print_scene(
336 5,
337 "2301 — Discovery: Raptor Pen Integrity",
338 "DR. GRANT",
339 &mut engine,
340 &event5,
341 &world,
342 None,
343 );
344
345 let event6 = Event {
348 event_type: "critical_failure".to_string(),
349 participants: vec![EntityRef {
350 entity_id: EntityId(3),
351 role: "subject".to_string(),
352 }],
353 location: Some(EntityRef {
354 entity_id: EntityId(10),
355 role: "location".to_string(),
356 }),
357 mood: Mood::Somber,
358 stakes: Stakes::Critical,
359 outcome: None,
360 narrative_fn: NarrativeFunction::Loss,
361 metadata: HashMap::new(),
362 };
363 print_scene(
364 6,
365 "2315 — Critical Failure: All Systems",
366 "RADIO OPERATOR",
367 &mut engine,
368 &event6,
369 &world,
370 Some(VoiceId(200)),
371 );
372
373 let event7 = Event {
376 event_type: "aftermath".to_string(),
377 participants: vec![EntityRef {
378 entity_id: EntityId(2),
379 role: "subject".to_string(),
380 }],
381 location: Some(EntityRef {
382 entity_id: EntityId(11),
383 role: "location".to_string(),
384 }),
385 mood: Mood::Dread,
386 stakes: Stakes::Critical,
387 outcome: None,
388 narrative_fn: NarrativeFunction::Loss,
389 metadata: HashMap::new(),
390 };
391 print_scene(
392 7,
393 "2330 — Final Log Entry",
394 "NARRATOR",
395 &mut engine,
396 &event7,
397 &world,
398 Some(VoiceId(203)),
399 );
400
401 println!("========================================");
402 println!(" [END OF INCIDENT REPORT]");
403 println!(" [STATUS: FACILITY ABANDONED]");
404 println!("========================================");
405}
406
407fn print_scene(
408 _number: u32,
409 title: &str,
410 voice_label: &str,
411 engine: &mut NarrativeEngine,
412 event: &Event,
413 world: &WorldState<'_>,
414 voice_override: Option<VoiceId>,
415) {
416 println!("--- {} ---", title);
417 println!(
418 "[Voice: {} | {} | {}]",
419 voice_label,
420 event.mood.tag().strip_prefix("mood:").unwrap_or("?"),
421 event.stakes.tag().strip_prefix("stakes:").unwrap_or("?"),
422 );
423 println!();
424
425 let result = if let Some(vid) = voice_override {
426 engine.narrate_as(event, vid, world)
427 } else {
428 engine.narrate(event, world)
429 };
430
431 match result {
432 Ok(text) => println!("{}", text),
433 Err(e) => println!("[Generation error: {}]", e),
434 }
435
436 println!();
437 println!();
438}