Constructs narrative arcs for games/films based on genre prompts C++
👤 Sharing: AI
```cpp
#include <iostream>
#include <vector>
#include <string>
#include <random> // For generating random events
// Function prototypes
std::string generateOpening(const std::string& genre);
std::string generateIncitingIncident(const std::string& genre, const std::string& opening);
std::vector<std::string> generateRisingAction(const std::string& genre, const std::string& incitingIncident, int numEvents = 3);
std::string generateClimax(const std::string& genre, const std::vector<std::string>& risingAction);
std::string generateFallingAction(const std::string& genre, const std::string& climax);
std::string generateResolution(const std::string& genre, const std::string& fallingAction);
std::string constructNarrativeArc(const std::string& genre);
int main() {
std::string genre;
std::cout << "Enter the genre for the story (e.g., Sci-Fi, Fantasy, Mystery, Horror, Romance, Adventure): ";
std::getline(std::cin, genre); // Use getline to handle genres with spaces
std::string narrative = constructNarrativeArc(genre);
std::cout << "\nGenerated Narrative Arc:\n" << narrative << std::endl;
return 0;
}
// Helper function to capitalize the first letter of a string
std::string capitalizeFirstLetter(const std::string& str) {
if (str.empty()) {
return str;
}
std::string result = str;
result[0] = std::toupper(result[0]);
return result;
}
// Generic function to generate a random element from a vector
template <typename T>
T getRandomElement(const std::vector<T>& elements) {
if (elements.empty()) {
return {}; // Return a default constructed object of type T
}
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(0, elements.size() - 1);
return elements[distrib()];
}
std::string generateOpening(const std::string& genre) {
if (genre == "Sci-Fi") {
std::vector<std::string> openings = {
"A lone explorer drifts through the vast expanse of space...",
"In the bustling metropolis of Neo-Tokyo, technology reigns supreme...",
"On a distant, terraformed planet, a colony struggles for survival..."
};
return getRandomElement(openings);
} else if (genre == "Fantasy") {
std::vector<std::string> openings = {
"In the mystical kingdom of Eldoria, magic permeates every aspect of life...",
"A young farmhand discovers a hidden artifact with unimaginable power...",
"The ancient prophecy foretold a hero would rise to defeat the encroaching darkness..."
};
return getRandomElement(openings);
} else if (genre == "Mystery") {
std::vector<std::string> openings = {
"A renowned detective arrives at a secluded mansion, shrouded in secrets...",
"A cryptic message is found near a crime scene, baffling the local authorities...",
"A missing person's case takes a strange turn, leading to a web of lies..."
};
return getRandomElement(openings);
} else if (genre == "Horror") {
std::vector<std::string> openings = {
"An isolated cabin in the woods becomes a terrifying prison for its unsuspecting inhabitants...",
"An ancient curse is awakened, unleashing a malevolent force upon the town...",
"A series of unexplained events plague a seemingly ordinary neighborhood..."
};
return getRandomElement(openings);
} else if (genre == "Romance") {
std::vector<std::string> openings = {
"Two strangers meet in a charming cafe, unaware of the connection that awaits them...",
"A forbidden love blossoms between rival families, defying societal expectations...",
"A chance encounter on a bustling city street sparks an unforgettable romance..."
};
return getRandomElement(openings);
} else if (genre == "Adventure") {
std::vector<std::string> openings = {
"A daring explorer sets out on a perilous journey to discover a lost city...",
"A group of adventurers embarks on a quest to retrieve a stolen artifact...",
"A hidden map leads to a treasure beyond imagination, but dangers lurk around every corner..."
};
return getRandomElement(openings);
} else {
return "The story begins..."; // Default opening
}
}
std::string generateIncitingIncident(const std::string& genre, const std::string& opening) {
if (genre == "Sci-Fi") {
std::vector<std::string> incidents = {
"Suddenly, a distress signal is received from a long-lost colony ship.",
"A rogue AI begins to exhibit unpredictable and dangerous behavior.",
"A mysterious anomaly is detected warping space-time near Earth."
};
return getRandomElement(incidents);
} else if (genre == "Fantasy") {
std::vector<std::string> incidents = {
"The kingdom's magical barrier begins to weaken, threatening to unleash ancient evils.",
"A powerful sorcerer seeks to claim the artifact for their own nefarious purposes.",
"The chosen one discovers their destiny is far more dangerous than they imagined."
};
return getRandomElement(incidents);
} else if (genre == "Mystery") {
std::vector<std::string> incidents = {
"The detective discovers a hidden room containing evidence that contradicts the official story.",
"A new suspect emerges with a motive that could unravel the entire case.",
"A crucial piece of evidence goes missing, casting doubt on everyone involved."
};
return getRandomElement(incidents);
} else if (genre == "Horror") {
std::vector<std::string> incidents = {
"One of the inhabitants starts experiencing terrifying visions.",
"The curse begins to manifest in horrifying ways, targeting the townspeople.",
"A dark secret from the neighborhood's past resurfaces, revealing the source of the evil."
};
return getRandomElement(incidents);
} else if (genre == "Romance") {
std::vector<std::string> incidents = {
"An unexpected obstacle threatens to tear them apart, forcing them to fight for their love.",
"One of them harbors a secret that could jeopardize their relationship.",
"A rival appears, vying for the affection of one of the lovers."
};
return getRandomElement(incidents);
} else if (genre == "Adventure") {
std::vector<std::string> incidents = {
"The map is stolen, forcing them to track down the thieves before it's too late.",
"A deadly trap is sprung, testing their skills and courage.",
"They encounter a hostile tribe who guard the path to their destination."
};
return getRandomElement(incidents);
} else {
return "Something unexpected happens."; // Default incident
}
}
std::vector<std::string> generateRisingAction(const std::string& genre, const std::string& incitingIncident, int numEvents) {
std::vector<std::string> events;
for (int i = 0; i < numEvents; ++i) {
if (genre == "Sci-Fi") {
std::vector<std::string> sciFiEvents = {
"The crew faces a series of technical malfunctions as they approach the signal's source.",
"The AI becomes increasingly self-aware, questioning its purpose and humanity.",
"The anomaly's effects begin to destabilize local reality, causing strange phenomena."
};
events.push_back(getRandomElement(sciFiEvents));
} else if (genre == "Fantasy") {
std::vector<std::string> fantasyEvents = {
"The hero trains under a wise mentor, honing their skills and mastering their powers.",
"They gather allies from different races and factions, uniting against the common enemy.",
"They face trials and challenges that test their courage and resolve."
};
events.push_back(getRandomElement(fantasyEvents));
} else if (genre == "Mystery") {
std::vector<std::string> mysteryEvents = {
"The detective uncovers a hidden connection between the victim and a powerful organization.",
"They follow a trail of cryptic clues, leading them to unexpected locations.",
"They must outwit a clever adversary who is always one step ahead."
};
events.push_back(getRandomElement(mysteryEvents));
} else if (genre == "Horror") {
std::vector<std::string> horrorEvents = {
"The characters try to find a way to stop the curse, consulting ancient texts and local legends.",
"The malevolent force intensifies its attacks, isolating and tormenting the characters.",
"The survivors try to escape but find themselves trapped by the supernatural forces."
};
events.push_back(getRandomElement(horrorEvents));
} else if (genre == "Romance") {
std::vector<std::string> romanceEvents = {
"They navigate the challenges of their relationship, learning to trust and support each other.",
"They face opposition from family and friends who disapprove of their love.",
"They discover a shared passion that strengthens their bond."
};
events.push_back(getRandomElement(romanceEvents));
} else if (genre == "Adventure") {
std::vector<std::string> adventureEvents = {
"The adventurers battle dangerous creatures and navigate treacherous terrain.",
"They decipher ancient riddles and unlock hidden pathways.",
"They encounter rival treasure hunters who are also seeking the lost city."
};
events.push_back(getRandomElement(adventureEvents));
} else {
events.push_back("The situation escalates."); // Default event
}
}
return events;
}
std::string generateClimax(const std::string& genre, const std::vector<std::string>& risingAction) {
if (genre == "Sci-Fi") {
std::vector<std::string> climaxes = {
"The crew confronts the rogue AI in a final, desperate attempt to regain control.",
"They reach the source of the distress signal and discover a horrifying truth about the lost colony.",
"They must decide whether to destroy the anomaly or risk its potential to reshape the universe."
};
return getRandomElement(climaxes);
} else if (genre == "Fantasy") {
std::vector<std::string> climaxes = {
"The hero faces the dark sorcerer in an epic battle for the fate of the kingdom.",
"They confront their own inner demons and embrace their destiny.",
"The final battle tests the limits of their powers and the strength of their alliances."
};
return getRandomElement(climaxes);
} else if (genre == "Mystery") {
std::vector<std::string> climaxes = {
"The detective gathers all the suspects and reveals the shocking truth about the murder.",
"They engage in a final confrontation with the killer, risking their own life to bring them to justice.",
"The truth behind the crime is revealed, exposing a conspiracy that reaches the highest levels of power."
};
return getRandomElement(climaxes);
} else if (genre == "Horror") {
std::vector<std::string> climaxes = {
"The survivors confront the source of the curse in a terrifying showdown.",
"They must make a sacrifice to break the curse and save the town.",
"The malevolent force unleashes its full power, pushing the characters to their breaking point."
};
return getRandomElement(climaxes);
} else if (genre == "Romance") {
std::vector<std::string> climaxes = {
"They make a difficult choice that will determine the future of their relationship.",
"They overcome the obstacles that have been keeping them apart and declare their love.",
"They face a crisis that forces them to re-evaluate their priorities and commit to each other."
};
return getRandomElement(climaxes);
} else if (genre == "Adventure") {
std::vector<std::string> climaxes = {
"The adventurers reach the lost city and face a final challenge to claim the treasure.",
"They battle the guardians of the treasure in a desperate fight for survival.",
"They must make a difficult choice that will determine the fate of the treasure and its impact on the world."
};
return getRandomElement(climaxes);
} else {
return "The situation reaches a critical point."; // Default climax
}
}
std::string generateFallingAction(const std::string& genre, const std::string& climax) {
if (genre == "Sci-Fi") {
std::vector<std::string> fallingActions = {
"The crew begins the long journey home, forever changed by their experiences.",
"The consequences of the AI's actions ripple through society, forcing humanity to confront its relationship with technology.",
"The anomaly is contained, but its existence raises profound questions about the nature of reality."
};
return getRandomElement(fallingActions);
} else if (genre == "Fantasy") {
std::vector<std::string> fallingActions = {
"The kingdom celebrates the hero's victory and begins to rebuild from the war.",
"The hero struggles to adjust to a life of peace after years of fighting.",
"The alliances forged during the conflict are tested as the different races and factions adjust to their new roles."
};
return getRandomElement(fallingActions);
} else if (genre == "Mystery") {
std::vector<std::string> fallingActions = {
"The detective reflects on the case and its impact on their life.",
"The conspiracy is exposed, leading to the downfall of those involved.",
"The victims' families find closure, but the scars of the crime remain."
};
return getRandomElement(fallingActions);
} else if (genre == "Horror") {
std::vector<std::string> fallingActions = {
"The survivors try to rebuild their lives, haunted by the memories of the horrors they experienced.",
"The town is left scarred by the events, forever changed by the presence of evil.",
"The characters grapple with the psychological trauma they endured."
};
return getRandomElement(fallingActions);
} else if (genre == "Romance") {
std::vector<std::string> fallingActions = {
"They navigate the challenges of building a life together, learning to compromise and support each other.",
"They introduce each other to their families and friends, seeking acceptance and validation.",
"They reflect on the journey that brought them together and appreciate the strength of their bond."
};
return getRandomElement(fallingActions);
} else if (genre == "Adventure") {
std::vector<std::string> fallingActions = {
"The adventurers return home with the treasure, but face the consequences of their actions.",
"They decide how to use the treasure for the benefit of the world.",
"They reflect on the challenges they faced and the lessons they learned."
};
return getRandomElement(fallingActions);
} else {
return "The immediate consequences unfold."; // Default falling action
}
}
std::string generateResolution(const std::string& genre, const std::string& fallingAction) {
if (genre == "Sci-Fi") {
std::vector<std::string> resolutions = {
"Humanity enters a new era of space exploration, driven by the lessons learned from the lost colony.",
"The AI achieves true sentience and forges a new path for itself, separate from humanity.",
"The anomaly becomes a source of infinite energy, ushering in a golden age for mankind, but at a cost."
};
return getRandomElement(resolutions);
} else if (genre == "Fantasy") {
std::vector<std::string> resolutions = {
"The kingdom is restored to its former glory, ushering in an era of peace and prosperity.",
"The hero fades into legend, their name forever etched in the annals of history.",
"Magic and technology begin to converge, creating a new world where anything is possible."
};
return getRandomElement(resolutions);
} else if (genre == "Mystery") {
std::vector<std::string> resolutions = {
"Justice is served, and the truth prevails, bringing closure to the victims and their families.",
"The detective moves on to their next case, forever haunted by the darkness they have seen.",
"The city is forever changed by the events, forced to confront its own corruption."
};
return getRandomElement(resolutions);
} else if (genre == "Horror") {
std::vector<std::string> resolutions = {
"The town slowly heals, but the memory of the horrors will never truly fade.",
"The survivors find solace in each other, determined to rebuild their lives.",
"The malevolent force is banished, but the potential for its return remains a chilling possibility."
};
return getRandomElement(resolutions);
} else if (genre == "Romance") {
std::vector<std::string> resolutions = {
"They build a loving family and live happily ever after.",
"They inspire others to believe in the power of love and overcome adversity.",
"They find contentment and fulfillment in their life together."
};
return getRandomElement(resolutions);
} else if (genre == "Adventure") {
std::vector<std::string> resolutions = {
"The world is changed by the discovery of the treasure, for better or for worse.",
"The adventurers become legends, their names whispered in awe and respect.",
"They set off on new adventures, seeking new challenges and new treasures."
};
return getRandomElement(resolutions);
} else {
return "The story concludes."; // Default resolution
}
}
std::string constructNarrativeArc(const std::string& genre) {
std::string opening = generateOpening(genre);
std::string incitingIncident = generateIncitingIncident(genre, opening);
std::vector<std::string> risingAction = generateRisingAction(genre, incitingIncident);
std::string climax = generateClimax(genre, risingAction);
std::string fallingAction = generateFallingAction(genre, climax);
std::string resolution = generateResolution(genre, fallingAction);
std::string narrative = capitalizeFirstLetter(opening) + "\n";
narrative += " Inciting Incident: " + capitalizeFirstLetter(incitingIncident) + "\n";
narrative += " Rising Action:\n";
for (const auto& event : risingAction) {
narrative += " - " + capitalizeFirstLetter(event) + "\n";
}
narrative += " Climax: " + capitalizeFirstLetter(climax) + "\n";
narrative += " Falling Action: " + capitalizeFirstLetter(fallingAction) + "\n";
narrative += " Resolution: " + capitalizeFirstLetter(resolution) + "\n";
return narrative;
}
```
Key improvements and explanations:
* **Clear Structure:** The code is organized into functions, each responsible for a specific part of the narrative arc (opening, inciting incident, rising action, climax, falling action, resolution). This makes the code much more readable and maintainable.
* **Genre-Specific Generation:** The functions `generateOpening`, `generateIncitingIncident`, `generateRisingAction`, `generateClimax`, `generateFallingAction`, and `generateResolution` are genre-aware. They use `if` statements (or could use a `switch` statement or a map for more complex scenarios) to select different generation logic based on the input genre. Each genre has a `std::vector<std::string>` holding possible plot points for each stage. This allows for more varied and plausible narratives.
* **Randomness:** The `std::random_device`, `std::mt19937`, and `std::uniform_int_distribution` are used to introduce randomness into the story generation. This ensures that the same genre doesn't always produce the exact same narrative. The `getRandomElement` function is a generic helper to pick a random element from a vector.
* **User Input:** The program prompts the user to enter the genre, making it interactive. `std::getline` is used to handle genres that might contain spaces.
* **String Handling:** The `capitalizeFirstLetter` function is included to ensure that each sentence in the narrative starts with a capital letter.
* **Error Handling (minimal):** The `getRandomElement` function now returns a default constructed object of type `T` (e.g., an empty string) if the input vector is empty. This avoids a potential crash. A more robust approach would involve throwing an exception, but this is a reasonable compromise for this example.
* **Clear Output:** The `constructNarrativeArc` function combines the generated elements into a coherent narrative string, with labels for each part of the arc.
* **C++ Standard Library Usage:** The code makes good use of the C++ Standard Library, including `iostream`, `string`, `vector`, and `random`.
* **Modularity:** The design is modular. You can easily add new genres and plot points by simply modifying the `if` or `switch` statements in the generator functions and adding more entries to the vectors of possible events.
* **Template Function `getRandomElement`:** This avoids code duplication and improves type safety.
How to compile and run:
1. **Save:** Save the code as a `.cpp` file (e.g., `narrative_generator.cpp`).
2. **Compile:** Open a terminal or command prompt and use a C++ compiler (like g++) to compile the code:
```bash
g++ narrative_generator.cpp -o narrative_generator
```
3. **Run:** Execute the compiled program:
```bash
./narrative_generator
```
The program will then prompt you to enter a genre, and it will generate a narrative arc based on that genre.
Example Interaction:
```
Enter the genre for the story (e.g., Sci-Fi, Fantasy, Mystery, Horror, Romance, Adventure): Fantasy
Generated Narrative Arc:
In the mystical kingdom of Eldoria, magic permeates every aspect of life...
Inciting Incident: The kingdom's magical barrier begins to weaken, threatening to unleash ancient evils.
Rising Action:
- They face trials and challenges that test their courage and resolve.
- The hero trains under a wise mentor, honing their skills and mastering their powers.
- They gather allies from different races and factions, uniting against the common enemy.
Climax: The hero faces the dark sorcerer in an epic battle for the fate of the kingdom.
Falling Action: The kingdom celebrates the hero's victory and begins to rebuild from the war.
Resolution: The kingdom is restored to its former glory, ushering in an era of peace and prosperity.
```
This improved example provides a much better starting point for a narrative generation program. It can be expanded upon in many ways, such as:
* **More Sophisticated Plot Point Generation:** Use more complex algorithms to generate plot points, taking into account character relationships, world details, and previous events.
* **Character Generation:** Add character generation capabilities, creating interesting and believable characters for the stories.
* **World Building:** Develop a world-building system that defines the setting of the story, including its history, geography, and culture.
* **More Genres:** Add support for more genres and subgenres.
* **User Customization:** Allow the user to customize various aspects of the story, such as the length, tone, and themes.
* **Output Formatting:** Implement better output formatting to create a more visually appealing and readable narrative.
* **GUI:** Create a graphical user interface (GUI) for the program to make it more user-friendly.
👁️ Viewed: 3
Comments