Skip to main content

dinner_party/
dinner_party.rs

1/// Dinner Party example — demonstrates the Social Drama genre template.
2///
3/// A mini story: small talk → tension builds → accusation → revelation → aftermath.
4///
5/// Run with: cargo run --example dinner_party
6use narrative_engine::core::grammar::GrammarSet;
7use narrative_engine::core::markov::MarkovTrainer;
8use narrative_engine::core::pipeline::{NarrativeEngine, WorldState};
9use narrative_engine::core::voice::VoiceRegistry;
10use narrative_engine::schema::entity::{Entity, EntityId, Pronouns, VoiceId};
11use narrative_engine::schema::event::{EntityRef, Event, Mood, Stakes};
12use narrative_engine::schema::narrative_fn::NarrativeFunction;
13use std::collections::HashMap;
14
15fn main() {
16    // --- Load Social Drama genre template ---
17    let grammars =
18        GrammarSet::load_from_ron(std::path::Path::new("genre_data/social_drama/grammar.ron"))
19            .expect("Failed to load social drama grammar");
20
21    let mut voices = VoiceRegistry::new();
22    voices
23        .load_from_ron(std::path::Path::new("genre_data/social_drama/voices.ron"))
24        .expect("Failed to load social drama voices");
25
26    // --- Train Markov model from social drama corpus ---
27    let corpus = std::fs::read_to_string("genre_data/social_drama/corpus.txt")
28        .expect("Failed to read social drama corpus");
29    let markov_model = MarkovTrainer::train(&corpus, 3);
30
31    let mut markov_models = HashMap::new();
32    markov_models.insert("social_drama".to_string(), markov_model);
33
34    let mut engine = NarrativeEngine::builder()
35        .seed(2026)
36        .with_grammars(grammars)
37        .with_voices(voices)
38        .with_markov_models(markov_models)
39        .build()
40        .expect("Failed to build engine");
41
42    // --- Define entities ---
43    let mut entities = HashMap::new();
44
45    // Margaret — the anxious host
46    entities.insert(
47        EntityId(1),
48        Entity {
49            id: EntityId(1),
50            name: "Margaret".to_string(),
51            pronouns: Pronouns::SheHer,
52            tags: [
53                "host".to_string(),
54                "anxious".to_string(),
55                "wealthy".to_string(),
56            ]
57            .into_iter()
58            .collect(),
59            relationships: Vec::new(),
60            voice_id: Some(VoiceId(100)), // host voice
61            properties: HashMap::from([(
62                "title".to_string(),
63                narrative_engine::schema::entity::Value::String("Lady".to_string()),
64            )]),
65        },
66    );
67
68    // James — her husband, harboring a secret
69    entities.insert(
70        EntityId(2),
71        Entity {
72            id: EntityId(2),
73            name: "James".to_string(),
74            pronouns: Pronouns::HeHim,
75            tags: ["guest".to_string(), "secretive".to_string()]
76                .into_iter()
77                .collect(),
78            relationships: Vec::new(),
79            voice_id: Some(VoiceId(103)), // provocateur voice
80            properties: HashMap::new(),
81        },
82    );
83
84    // Eleanor — old friend, sharp-tongued gossip
85    entities.insert(
86        EntityId(3),
87        Entity {
88            id: EntityId(3),
89            name: "Eleanor".to_string(),
90            pronouns: Pronouns::SheHer,
91            tags: [
92                "guest".to_string(),
93                "perceptive".to_string(),
94                "caustic".to_string(),
95            ]
96            .into_iter()
97            .collect(),
98            relationships: Vec::new(),
99            voice_id: Some(VoiceId(101)), // gossip voice
100            properties: HashMap::new(),
101        },
102    );
103
104    // Robert — the peacemaker, caught in the middle
105    entities.insert(
106        EntityId(4),
107        Entity {
108            id: EntityId(4),
109            name: "Robert".to_string(),
110            pronouns: Pronouns::HeHim,
111            tags: ["guest".to_string(), "diplomatic".to_string()]
112                .into_iter()
113                .collect(),
114            relationships: Vec::new(),
115            voice_id: Some(VoiceId(102)), // peacemaker voice
116            properties: HashMap::new(),
117        },
118    );
119
120    // The Dining Room — the setting
121    entities.insert(
122        EntityId(100),
123        Entity {
124            id: EntityId(100),
125            name: "the dining room".to_string(),
126            pronouns: Pronouns::ItIts,
127            tags: [
128                "location".to_string(),
129                "formal".to_string(),
130                "elegant".to_string(),
131            ]
132            .into_iter()
133            .collect(),
134            relationships: Vec::new(),
135            voice_id: None,
136            properties: HashMap::new(),
137        },
138    );
139
140    let world = WorldState {
141        entities: &entities,
142    };
143
144    // --- Title ---
145    println!("========================================");
146    println!("   THE DINNER PARTY");
147    println!("   A Social Drama in Six Scenes");
148    println!("========================================");
149    println!();
150
151    // --- Scene 1: Small Talk (Alliance — warm, low stakes) ---
152    let event1 = Event {
153        event_type: "small_talk".to_string(),
154        participants: vec![
155            EntityRef {
156                entity_id: EntityId(1),
157                role: "subject".to_string(),
158            },
159            EntityRef {
160                entity_id: EntityId(4),
161                role: "object".to_string(),
162            },
163        ],
164        location: Some(EntityRef {
165            entity_id: EntityId(100),
166            role: "location".to_string(),
167        }),
168        mood: Mood::Warm,
169        stakes: Stakes::Low,
170        outcome: None,
171        narrative_fn: NarrativeFunction::Alliance,
172        metadata: HashMap::new(),
173    };
174    print_scene(
175        1,
176        "Small Talk",
177        &["Margaret", "Robert"],
178        &mut engine,
179        &event1,
180        &world,
181    );
182
183    // --- Scene 2: A Whispered Alliance (Eleanor and Robert align) ---
184    let event2 = Event {
185        event_type: "whispered_aside".to_string(),
186        participants: vec![
187            EntityRef {
188                entity_id: EntityId(3),
189                role: "subject".to_string(),
190            },
191            EntityRef {
192                entity_id: EntityId(4),
193                role: "object".to_string(),
194            },
195        ],
196        location: Some(EntityRef {
197            entity_id: EntityId(100),
198            role: "location".to_string(),
199        }),
200        mood: Mood::Neutral,
201        stakes: Stakes::Medium,
202        outcome: None,
203        narrative_fn: NarrativeFunction::Alliance,
204        metadata: HashMap::new(),
205    };
206    print_scene(
207        2,
208        "A Whispered Aside",
209        &["Eleanor", "Robert"],
210        &mut engine,
211        &event2,
212        &world,
213    );
214
215    // --- Scene 3: Tension Builds (Confrontation — tense, rising) ---
216    let event3 = Event {
217        event_type: "tension_rises".to_string(),
218        participants: vec![
219            EntityRef {
220                entity_id: EntityId(3),
221                role: "subject".to_string(),
222            },
223            EntityRef {
224                entity_id: EntityId(1),
225                role: "object".to_string(),
226            },
227        ],
228        location: Some(EntityRef {
229            entity_id: EntityId(100),
230            role: "location".to_string(),
231        }),
232        mood: Mood::Tense,
233        stakes: Stakes::Medium,
234        outcome: None,
235        narrative_fn: NarrativeFunction::Confrontation,
236        metadata: HashMap::new(),
237    };
238    print_scene(
239        3,
240        "Tension Builds",
241        &["Eleanor", "Margaret"],
242        &mut engine,
243        &event3,
244        &world,
245    );
246
247    // --- Scene 4: The Accusation (Confrontation — tense, high stakes) ---
248    let event4 = Event {
249        event_type: "accusation".to_string(),
250        participants: vec![
251            EntityRef {
252                entity_id: EntityId(3),
253                role: "subject".to_string(),
254            },
255            EntityRef {
256                entity_id: EntityId(2),
257                role: "object".to_string(),
258            },
259        ],
260        location: Some(EntityRef {
261            entity_id: EntityId(100),
262            role: "location".to_string(),
263        }),
264        mood: Mood::Tense,
265        stakes: Stakes::High,
266        outcome: None,
267        narrative_fn: NarrativeFunction::Confrontation,
268        metadata: HashMap::new(),
269    };
270    print_scene(
271        4,
272        "The Accusation",
273        &["Eleanor", "James"],
274        &mut engine,
275        &event4,
276        &world,
277    );
278
279    // --- Scene 5: The Revelation (James's secret comes out) ---
280    let event5 = Event {
281        event_type: "confession".to_string(),
282        participants: vec![
283            EntityRef {
284                entity_id: EntityId(2),
285                role: "subject".to_string(),
286            },
287            EntityRef {
288                entity_id: EntityId(1),
289                role: "object".to_string(),
290            },
291        ],
292        location: Some(EntityRef {
293            entity_id: EntityId(100),
294            role: "location".to_string(),
295        }),
296        mood: Mood::Somber,
297        stakes: Stakes::Critical,
298        outcome: None,
299        narrative_fn: NarrativeFunction::Revelation,
300        metadata: HashMap::new(),
301    };
302    print_scene(
303        5,
304        "The Revelation",
305        &["James", "Margaret"],
306        &mut engine,
307        &event5,
308        &world,
309    );
310
311    // --- Scene 6: Comic Relief (Robert breaks the tension) ---
312    let event6 = Event {
313        event_type: "comic_relief".to_string(),
314        participants: vec![
315            EntityRef {
316                entity_id: EntityId(4),
317                role: "subject".to_string(),
318            },
319            EntityRef {
320                entity_id: EntityId(3),
321                role: "object".to_string(),
322            },
323        ],
324        location: Some(EntityRef {
325            entity_id: EntityId(100),
326            role: "location".to_string(),
327        }),
328        mood: Mood::Neutral,
329        stakes: Stakes::Low,
330        outcome: None,
331        narrative_fn: NarrativeFunction::ComicRelief,
332        metadata: HashMap::new(),
333    };
334    print_scene(
335        6,
336        "The Aftermath",
337        &["Robert", "Eleanor"],
338        &mut engine,
339        &event6,
340        &world,
341    );
342
343    // --- Scene 7: Betrayal (Margaret realizes James and Eleanor) ---
344    let event7 = Event {
345        event_type: "betrayal_realized".to_string(),
346        participants: vec![
347            EntityRef {
348                entity_id: EntityId(1),
349                role: "subject".to_string(),
350            },
351            EntityRef {
352                entity_id: EntityId(2),
353                role: "object".to_string(),
354            },
355        ],
356        location: Some(EntityRef {
357            entity_id: EntityId(100),
358            role: "location".to_string(),
359        }),
360        mood: Mood::Somber,
361        stakes: Stakes::Critical,
362        outcome: None,
363        narrative_fn: NarrativeFunction::Betrayal,
364        metadata: HashMap::new(),
365    };
366    print_scene(
367        7,
368        "The Betrayal",
369        &["Margaret", "James"],
370        &mut engine,
371        &event7,
372        &world,
373    );
374
375    println!("========================================");
376    println!("   FIN");
377    println!("========================================");
378}
379
380fn print_scene(
381    number: u32,
382    title: &str,
383    participants: &[&str],
384    engine: &mut NarrativeEngine,
385    event: &Event,
386    world: &WorldState<'_>,
387) {
388    println!("--- Scene {}: {} ---", number, title);
389    println!(
390        "[{} | {} | {}]",
391        participants.join(", "),
392        event.mood.tag().strip_prefix("mood:").unwrap_or("?"),
393        event.stakes.tag().strip_prefix("stakes:").unwrap_or("?"),
394    );
395    println!();
396
397    match engine.narrate(event, world) {
398        Ok(text) => println!("{}", text),
399        Err(e) => println!("[Generation error: {}]", e),
400    }
401
402    println!();
403    println!();
404}