Mad Libs

From Rosetta Code
Mad Libs is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Write a program to read a multiline story from the input. The story will be terminated with a blank line. Then, find each replacement to be made within the story, ask the user for a word to replace it with, and make all the replacements. Stop when there are none left and print the final story.

The input should be in the form:

<name> went for a walk in the park. <he or she>
found a <noun>. <name> decided to take it home.

It should then ask for a name, a he or she and a noun. (<name> gets replaced both times with the same value.)

C++

<lang cpp>#include <iostream>

  1. include <string>

using namespace std;

int main() {

 string story, input;
 //Loop
 while(true)
 {
   //Get a line from the user
   getline(cin, input);
   //If it's blank, break this loop
   if(input == "\r")
     break;
   //Add the line to the story
   story += input;
 }
 //While there is a '<' in the story
 int begin;
 while((begin = story.find("<")) != string::npos)
 {
   //Get the category from between '<' and '>'
   int end = story.find(">");
   string cat = story.substr(begin + 1, end - begin - 1);
   //Ask the user for a replacement
   cout << "Give me a " << cat << ": ";
   cin >> input;
   //While there's a matching category 
   //in the story
   while((begin = story.find("<" + cat + ">")) != string::npos)
   {
     //Replace it with the user's replacement
     story.replace(begin, cat.length()+2, input);
   }
 }
 //Output the final story
 cout << endl << story;
 return 0;

} </lang>

Pike

this solution uses readline to make editing more convenient. it also adds an extra feature to define variables while writing, show the story written so far and continue adding to the story until exit is called. <lang Pike>#!/usr/bin/pike

Stdio.Readline readln = Stdio.Readline();

void print_help() {

   write(#"Write a Story.

Names or objects in the story can be made variable by referencing them as <person> <object>, etc.

After you introduce variables you may name them as: (person is called Michael) (object is a bag)

End the story with an empty line. If there are any undefined variables you will be reminded to name them.

Type help to see this message again. Type show to see your story. Type exit to quit.

");

   if (sizeof(variables))
   {
       write("you have used the following variables:\n");
       foreach(variables; string name; string value)
       {
           write("%s is %s\n", name, value);
       }
       write("\n");
   }

}

void add_line(string input) {

   parse_for_variables(input);
   story += input+"\n";

}

void parse_for_variables(string input) {

   array vars = Array.flatten(array_sscanf(input, "%*[^<>]%{<%[^<>]>%*[^<>]%}%*[^<>]"));
   foreach(vars;; string name)
   {
       if (!variables[name])
       {
           variables["<"+name+">"]="<"+name+">";
           write("Found new variable \"%s\"\n", name);
       }
   }

}

int(0..1) add_variable(string input) {

   array var = array_sscanf(input, "(%s is called %s)");
   if (sizeof(var) != 2)
       var = array_sscanf(input, "(%s is a %s)");
   if (sizeof(var) == 2)
       if (variables["<"+var[0]+">"] == "<"+var[0]+">")
       {
           variables["<"+var[0]+">"] = variables[var[1]];
           write("Defining %s as \"%s\"\n", var[0], var[1]);
           return true;
       }
   return false;

}

int check_variables() {

   int new;
   foreach(variables; string name; string value)
   {
       if (value == name)
       {
           new++;
           string new_value = readln->read(sprintf("Please give a name for %s: ", name));
           if (new_value != "")
               variables[name] = new_value;
       }
   }
   return new;

}

void show_story() {

   check_variables();
   write("\n"+replace(story, variables));

}

void do_exit() {

   exit(0);

}

mapping variables = ([]); mapping functions = ([ "help":print_help,

                      "show":show_story,
                      "exit":do_exit,
                    ]);

string story = "";

void main() {

   Stdio.Readline.History readline_history = Stdio.Readline.History(512);
   readln->enable_history(readline_history);

   string prompt="> ";

   print_help();
   while(1)
   {
       string input=readln->read(prompt);
       if(!input)
           exit(0);
       if(input == "")
           show_story();
       else if (functions[input])
           functions[input]();
       else if (!add_variable(input))
           add_line(input);
   }

}</lang>

Sample output:

Write a Story.

Names or objects in the story can be made variable by 
referencing them as <person> <object>, etc.

After you introduce variables you may name them as:
(person is called Michael)
(object is a bag)
End the story with an empty line. 
If there are any undefined variables you will be reminded to name them.

Type help to see this message again.
Type show to see your story.
Type exit to quit.

> <person> is a programmer.
Found new variable "person"
> <he or she> created <website> for all of us to enjoy.
Found new variable "he or she"
Found new variable "website"
> 
Please give a name for <website>: RosettaCode
Please give a name for <he or she>: he
Please give a name for <person>: Michael

Michael is a programmer.
he created RosettaCode for all of us to enjoy.
> exit