As covered in Part 1, a grammar is a set of symbols and some rules to follow. When using Tracery, these are feed to the createGrammar() function to tell it what symbols to use and their possible options.
In Tracery, symbols and their choices are defined as an object literal. Each property within the object is an array where the property is the symbol name and the array is all of its possible choices.
These symbols are passed to the createGrammar() function as part of the Tracery object. This takes the properties of the object passed to it to create associations where the property names can be substituted for one of their possible values in the next step.
The createGrammar() function also returns a grammar object that can be feed some text with certain values to substitute for the property names of the object passed to it.
The flatten() function of the object returned by createGrammar() has a function, flatten(), that “flattens” all of the possible choices for each symbol into one randomly chosen from its choices.
This function returns a text representing any textual substitutions made based on what was passed to it. For any symbols wrapped in hashes (#animals# in this example) it is switched for one of its choices.
And More Grammars!
Through adding more symbols, more complicated output can be achieved. Beyond using #animals#, a second symbol, #locations# could be added.
Adding new symbols with new rules does not change the basic output of the example. However, Tracery also understands symbols within symbols.
Complex rules can be created that will take symbols and expand them based on other, existing symbols.
Knowing that flatten() will give one of the choices of a symbol can be helpful in using it to set the initial values of an interaction between parties. Through using conditional statements, multiple uses of flatten() can be used to set and test values to create a very basic interaction.
As a more expanded example, the symbols could be used as keywords and then “flattened” to queue up different responses based on the history of the conversation and the rules established by the grammars. While this example uses the same grammar, different ones could be created and run against each other, prompting repeating usage of flatten() to choose the response based on the symbol each time.