How is this JanusNode run?
You can configure your JanusNode's main function- text-generation- in two main ways: by adding or deleting words to the JanusNode's database of words (as described elsewhere), and by adding, deleting, or editing the TextDNA that the JanusNode uses to specify the dynamic structure of its CryptoPsyche (a virtual structure that is analogous to a mind, but stupider). The term 'TextDNA' is an acronym for 'Text-based Delimited Natural-Language Algorithms'. TextDNA is composed of the TextDemons and TextDNA that specifies the manner in which a JanusNode strings together words. In keeping with its simple but utterly idiosyncratic character, a JanusNode uses a simple but utterly idiosyncratic 'language' to specify its textDNA. Your JanusNode comes with tools to automatically generate its own textDNA. With your JanusNode to help guide you, you can have the pleasure of generating your own textDNA even if you know nothing about software control of the symbiot hardware on which a JanusNode runs.
A JanusNode stores its textDNA in text files in a folder named 'textDNA' insides the 'JanusNode Resources' folder. You can edit or create any textDNA file (or any other text file) from within your JanusNode, since your JanusNode can retrieve and display text files in any of its editable fields (that is, any of the eight built-in BrainFood fields, as well as the 'textDNA' field itself).
The textDNA used by your JanusNode can call textDemons, which
are very similar to textDNA in their structure, but which must
defined as part of one line of textDNA in order to be used. The
main purpose of textDemons is to allow you, the user, to manipulate
arbitrarily complex chunks of the textDNA as a single unit. For
example, most single lines of textDNA will encode what human life
forms refer to as 'a noun phrase'. It is convenient to define
a noun-phrase textDemon which can be called in each line of the
textDNA, rather than re-defining the noun phrase every time we
want to use one. TextDemons are described in detail in the next
section.
We begin here with a description of the textDNA itself.
Along with the any of the names from the text files in the 'BrainFood' folder, the following symbols are recognized in textDNA:
TextDNA may also contain the names of built-in functions and user-defined textDemons. The built-in functions are described below. The textDemons are totally user-configurable and so cannot be specified in this documentation, but their characteristics are defined below.
All of these symbols must always be separated from each other with a space.
Asterisks serve as comment markers. Any line containing an asterisk
is simply ignored by a JanusNode. For this reason your JanusNode
cannot produce asterisks directly. If you really need them. let
me know: there is a way to do it indirectly, but it is too esoteric
to get into here.
When it encounters one of the BrainFood file-names in a line of
TextDNA, a JanusNode randomly chooses a word from that file. File
names (and, indeed, any other item) must always be followed in
textDNA by an integer between 1 and 100, indicating a percentage
likelihood that a word from that file will be printed. For example,
the phrase 's_nouns 90' appearing in textDNA will cause a singular
noun to be printed with a 90% certainty. There is therefore a
10% chance that nothing will be printed.
The word 'punctuate' indicates that JanusNode should randomly
punctuate. JanusNode punctuates with either a period or a comma
80% of the time. The remaining 20% of the time, it will use either
a dash, an ellipsis, or a colon. The word 'punctuate' must also
be followed by a number representing the likelihood of the punctuation
being printed. You should be aware that there are several other
ways of punctuating in JanusNode, which are explained later in
this documentation.
The word 'return' indicates that JanusNode should insert a linefeed
(a 'carriage return', to use an anachronism). It too must be followed
by a percentage likelihood.
Words or phrases surrounded by quotes (and followed by the obligatory
likelihood) are inserted verbatim (minus the quotes) by a JanusNode.
JanusNodes recognize most words that require special treatment when adding 'ing', 's', or 'ed'- so, for example, adding 'ed' after 'go' will be properly recognized as indicating 'went', and so on. However, English is extremely irregular and your JanusNode is certain to make the occasional mistake in dealing with these irregularities. After trying for some time to write a comprehensive function myself, I gave up and instead added user-configurable correction and extension resources to your JanusNode. You can correct any errors yourself, by adding them to the relevant files in the 'Irregulars' folder inside your 'JanusNode Resources' folder. There are three files, named 'Ing'.'S', and 'Ed'. When a JanusNode encounters any of the corresponding three key words, it checks inside the relevant files to see if there is a entry for the word under consideration. If there is, it uses that entry. If there is not, it proceeds to use its built-in functions, which will regularize irregulars. The entries in each 'Irregulars' folder are very simple: each entry (one per line) consists of the word to be dealt with, followed by a comma and its proper handling. For example, in the 'S' file there is an entry:
platypus,platypi
This tells your JanusNode that the proper plural for 'platypus' is 'platypi'.
If the 'Not English' button in the Control Panel is checked, the three keywords 'ing', 's' and 'ed' are not treated specially.
Non-English users will note that they can use the 'Irregulars' files to add their own conjugations and pluralizations- though they will have to list every one they want to use, unless their language overlaps with English in its treatment of the various special categories.
The above constitutes the 'bare bones' of the structure of TextDNA. Other than lines containing asterisks, every line has the same format. Each line begins with a number (see the next paragraph), which is then followed by an optional subject marker (also described below) which must be the first element after the number. After this every line of TextDNA consists of pairs made up of a keyword (i.e., one of the word-list file names, or the word 'punctuate', or 'return', or any word or phrase within quote marks) and a the number representing a percentage likelihood. A line is terminated with a carriage return. Note that a single line of TextDNA may look like several lines because TextDNA is automatically wrapped at the end of the field. The paragraph that you are now reading, for example, is only a single line long, since it has only one carriage return in it, but (unless you are viewing it on an extraordinarily wide screen!) it has been wrapped to cover several lines.
The number which must appear at the beginning of each TextDNA
specifies a percentage likelihood that the TextDNA as a whole
will be used once it has been chosen. For example, if the first
number of a line is '25', then that TextDNA will be used one quarter
of the time that it is chosen by JanusNode. Each TextDNA is chosen
with a likelihood equal to 1/(the number of lines of TextDNA)-
that is, it is chosen randomly from among all possible lines of
TextDNA. The first element of each line of TextDNA thus allows
you to 'weight' certain lines of TextDNA less heavily, thereby
favouring some lines of TextDNA over others. If you want to increase
a line's likelihood of being randomly chosen, you can simply insert
multiple copies of that line into the TextDNA file.
The optional subject marker which must be the second element of
a TextDNA if it appears lets your JanusNode know which subjects
the TextDNA is to be filed under. The syntax for this marker is
the word 'subject', followed by a list, in parentheses, of all
subjects, separated by commas. There may be no spaces anywhere
in the marker; if there is, an error will be flagged. For example,
the marker 'subject(love,life,My_Favourite_TextDNAs)' signals
to a JanusNode that the current TextDNA is to be chosen if the
current subject is 'love', 'life', or 'My_Favourite_TextDNAs'.
There are no pre-set subjects and no limits on how many subjects
a TextDNA can belong to. You may classify any line of TextDNA
under any subjects you like. When a JanusNode activates its TextDNA,
it automatically indexes every subject it finds, and puts them
all in the subject menu, where you may choose them. The subject
menu is just below the Janus icon. If you choose a subject from
that menu, then JanusNode will choose only TextDNAs which belong
to that subject when it generates poetry.
There are three 'special' choices in the subject menu- the 'Tell Fortune', 'Spell Poem', and 'Multiple TextDNA Files' options. The first two of these will be discussed below.
'Multiple TextDNA Files' mode
Let us consider the 'Multiple TextDNA Files' mode now. When this option is chosen from the 'Subject:' menu (the right-most choice on the window bar), then the user is presented with a list of all the available TextDNA files from the 'TextDNAs' folder. You can choose one or more of these files (hold down the command-key to make a discontinuous selection). Your JanusNode will henceforth choose TextDNA from all the files you have selected. It does so by weighting the files probabilistically according to the number of lines of TextDNA they contain. For example, if you choose three TextDNA files, one of which contains 90 lines and the other two of which contain 5 lines each, then TextDNA will be selected from the first file 90% of the time, and from each of the other two files 5% of the time. If you are using multiple TextDNA files, you cannot choose your subject- you will see 'No subjects available' in the subjects menu. Selecting that as your topic has no effect (i.e. it is the same as choosing 'Multiple TextDNA Files').
When you first turn on the 'Multiple TextDNA files' mode (or every
time you leave the TextDNA field if the mode is selected) JanusNode
needs to 'compile' the TextDNA files, which means it needs to
read through every available TextDNA file once. This can be a
time-consuming operation, depending on how many files there are,
how big they are, how complex the TextDNA is, and how fast your
hardware symbiot is.
Note that, in multiple-TextDNA-files mode, JanusNode loads in
the TextDNA files to its TextDNA field. This means that there
is no guarantee that JanusNode will be in the same state when
you turn the 'Multiple TextDNA files' mode off as it was when
you turned it on. To use a single specific TextDNA file, you must
go to the TextDNAsfile and use the 'Open file' menu command to
read in the file you want, and then make sure that the 'Multiple
TextDNA files' mode is not selected from the 'Subject:' menu.
Alternatively, just put that file in its own folder within the
'TextDNA' folder.
A simple examples of a TextDNA
An example of a TextDNA will make the simple syntax clear. Consider the following line of TextDNA:
100 subject(simple_TextDNA,MyTextDNA) s_articles 20 adjectives 5 s_nouns 100 s_verbsnob 100 punctuate 70
This line will be classified under two subjects: 'simple_TextDNA' and 'MyTextDNA', which will both appear in the subject menu. This means that the TextDNA will only be considered if the subject is either one of these, or if it is the default, 'None'. The TextDNA will fire 100% of the time that it is randomly chosen, since the first element of the line is 100. It will then insert a singular article 20% of the time, followed 5% of the time by an adjective. The next two elements of the TextDNA, a singular noun and a verb which needs no object, will always be inserted when the TextDNA is chosen, since they are both given a 100% chance of being inserted. Finally, this sample sentence will be punctuated, as described earlier, 70% of the time. Thus one possible outcome of this TextDNA is the creation of the sentence:
Note that it is almost always necessary to have some elements
of a line of TextDNA inserted with 100% probability, in order
to guarantee that there will be a basic syntactically-sensible
structure underlying the sentence which is generated. One might,
on the other hand, might go in for really 'modern' poetry that
does not even follow the rules of syntax.
The rest of the characters which are allowed in TextDNAs allow for greater flexibility in TextDNA writing.
Repetition Brackets [ ]
The square brackets are for
repeating certain parts of the TextDNA. Everything contained within
square brackets will be repeated a random number of times (but
not less than once and not more than five times).
For example, consider the following line of TextDNA:
100 "You" 100 [ s_verbsnon 100 adverbs 100 "," 100 ]
This TextDNA will always fire when chosen, because the first element is 100. The first printable item- the word 'You'- will be printed every time the TextDNA fires. The phrase within the square brackets- a verb followed by an adverb and a comma- will be printed at least once, and up to five times. One possible outcome of this TextDNA is the creation of the phrase:
Choice brackets {}
The curly brackets allow for
alternative choices to be inserted in TextDNAs. Alternatives are
separated with the '|' character. When a TextDNA containing alternatives
fires, JanusNode will randomly choose one the alternatives. You
can put as many alternatives as you like.
Once again, an example will make the simple idea clear. Consider
this line of TextDNA:
This TextDNA will always fire
when chosen, because the first element is 100. The first printable
item- the word 'You'- will be printed every time the TextDNA fires.
After that, one of the two choices between the curly brackets
will be randomly chosen. Either the word 'dream' will be printed,
followed by an adverb, or else a verb taking 'to' will be printed,
followed by the word 'me'.
Thus, two possible outcomes of this TextDNA are equally likely.
The TextDNA will either print a sentence like:
or it will print a sentence like
Function brackets and built-in functions <>
The triangular brackets ('<'
and '>') mark off function calls. JanusNode expects to see
a function call between the brackets, followed by percent probability
of calling that function. If the function is called, JanusNode
will print whatever the function call returns.
For example, you can make a call to a random number generator
in the middle of the TextDNA. A TextDNA which does so might look
like this:
This TextDNA would improve upon Jim Morrison's famous line "Love me two times" by substituting a random number between 0 and 20 for the word 'two'. One possible outcome would be:
There are no constraints on the number of arguments the function
can take, but the function call must be printed without any
spaces in it. You can access any HyperTalk function with a
function call (though it is hard for me to see which ones other
than 'random' might be useful!). The main use of the function
call feature, however, is to give you access to a number of useful
functions which have been built in to your JanusNode. Most of
these functions do not currently error-check their arguments very
well, so pay close attention to the syntax.
The 'Assign' & 'Get' Functions
Two important functions built in to JanusNode are the 'assign' and 'get' functions. These allow for the setting and accessing of global variables within a string of TextDNA.
The 'assign' function usually takes two arguments: a name for
the global variable and one of the BrainFood file names. It names
a randomly chosen word from the file with the name. In doing so,
it returns nothing. However, the second argument of the 'assign'
function need nor necessarily be the name of a BrainFood field.
If it is a quoted string of words separated by commas (but containing
no spaces), 'assign' will randomly assign one of the words
in that string to the global variable. For example, the following
is legal:
< assign(AnAnimal,"dog,cat,kitten,cow") 100 >
The 'get' function allows your JanusNode to access varianbls which have been assigned a value using the 'assign' function. It takes a single argument, which should be the name of a previously assigned variable. It returns the value of that variable. If the name is not the name of a previously assigned variable, then the function does not return anything.
Consider the following rather inane example:
100 < assign(MyNoun,s_nouns) 100 > < assign(MyArticle,s_articles) 100 > < get(MyArticle) 100 > < get(MyNoun) 100 > "is not" 100 < get(MyArticle) 100 > < get(MyNoun) 100 >
The first element is the global probability that the the textDNA will be used if it is chosen, as described above. The two function calls after the global probability are assignment statements, which will not result in anything being printed. The first assignment (< assign(MyNoun,s_nouns) 100 >) assigns a singular noun to the variable named 'MyNoun'. The second assignment (< assign(MyArticle,s_articles) 100 >) assigns a singular article to the variable named 'MyArticle'. These two variables are then accessed twice in the body of the TextDNA, sandwiching the phrase "is not". One possible outcome of this TextDNA is the creation of the sentence:
A JanusNode ships with four pre-defined global variables which
are randomly initialized at start-up. These are 'MyNoun' (a singular
noun), 'MyNouns' (a plural noun), 'MySVerb' (a singular verb which
doesn't need an object), and 'MyPVerb' (a plural verb which doesn't
need an object). Since these are given a value at start up, you
can access them in TextDNAs without having to use an assign statement
first. However, you are free re-assign them in the usual way (that
is, by making a call to the 'assign' function) or by clicking
on the 'Initialize Globals' button in the Control Panel, which
will re-set the four globals.
You can also define global variables by clicking on the 'Define
Constant' button in the Control Panel, which will prompt you for
the name and type of the variable you want to create. Variables
created in this way can be used within TextDNA without assigning
them a value first, since they are given a value when they are
created. However, they must be re-created each time you re-start
your JanusNode robot.
The LoadTextDNAFile and UseTextDNA Functions: Power to structure text
Two powerful functions in your JanusNode are the 'LoadTextDNAFile' and 'UseTextDNA' functions. They extremely simple,but extremely useful. Warning: these are 'power user' functions. which require that you have some idea of what you are doing. If you are just getting started with your JanusNode, you may want to leave these two functions until you understand how everything else works. Things will get very hairy if you try to use these functions without having a good idea of how your JanusNode works.
'LoadTextDNAFile' takes a single argument: the name (in quotation
marks to be safe, although they are not necessary if your TextDNAs
files contain only alphabetic and numeric characters) of a TextDNA
file in the TextDNAs folder. It loads that file in to the JanusNode.
Example:
This will load and prepare the TextDNA file called "paragraph.DNA".
If a JanusNode encounters a call to the 'LoadTextDNAFile' function
while it is in 'Multiple TextDNA Files' mode, it will change mode
to single TextDNA file mode. This means that after a function
call to 'LoadTextDNAFile', JanusNode will only know about the
current TextDNA file, not any other TextDNA files which may happen
to be in the TextDNA folder. This a deliberate feature, not a
bug or technical limitation. The function exists to allow users
to have control of how the TextDNA is used, whereas 'Multiple
TextDNA Files' mode does not allow such control (since you cannot
set a subject or method in that mode).
In concert with the 'UseTextDNA' function (described next), the
'LoadTextDNAFile' function is an extremely powerful tool whose
implementation makes it possible to make your JanusNode generate
long, highly structured, coherent texts, which may use literally
thousands of TextDNAs and BrainFood files in a systematic way.
The 'UseTextDNA' function takes a single argument, which is the
name of a subject by which at least one line of TextDNA in the
current TextDNA set is classified. It simply sets the current
subject to the specified subject, thereby ensuring that next TextDNA
chosen will come from that set. Having this capability makes it
possible to string together sets of TextDNAs (or a single line
of TextDNAs, since a set can consist of just one line) one after
another, thereby gaining complete control over the order on which
your TextDNA fires. This makes it possible for your JanusNode
to do many things that would otherwise be tricky or impossible,
such as writing rhyming verses with a repetitive structure, writing
long coherent narratives, and much more.
An example of the syntax of this function is
Whenever this function call is encountered in TextDNA, the next
line of TextDNA will be drawn from all the lines of TextDNA that
are classified under the subject 'MyTextDNA'.
Note that you can also use this function to make probabilistic
jumps between TextDNA sets. For example, consider the following:
Here there are two function calls, one after another, of which
the first will certainly fire (since it is specified as having
a 100% chance of firing) and the second of which will fire 50%
of the time. After encountering this in a line of TextDNA, a JanusNode
will use the TextDNA set named 'MyTextDNA2' 50% of the time, and
the TextDNA set named 'MyTextDNA1' the other 50% of the time.
The RepriseTextDNA Function
RepriseTextDNA is another powerful meta-level control function, which allows the 'UseTextDNA' function to use indirect reference. The function takes a single argument which is the name of a variable, and fires a line of TextDNA which has the same name as _the value_ of that variable. You will usually set the value of the argument which is passed to RepriseTextDNA using the 'Assign' function.
For example:
100 < assign(CurrentDNA,"MyTextDNA") 100 >
*** The above line will assign the value 'MyTextDNA' to the variable 'CurrentDNA'
100 < RepriseTextDNA(CurrentDNA) 100 >
*** The above line will fire a (randomly-selected) line of TextDNA which has the subject
*** 'MyTextDNA', which is the _value_ of the variable 'CurrentDNA'.
RepriseTextDNA makes it possible to have repeated elements in an output text (for example, choruses in a song- see the RobotJohnson files for many examples) and to have a logical flow to texts, since you can set the values of future text in TextDNA which has fired. For example, you might have two rules with the same name which lead to different paths using the RepriseTextDNA function, as follows:
100 Subject(HeroineEnd) "And then she died." 100 < RepriseTextDNA(DeadHeroineDNA) 100 >
***
100 Subject(HeroineEnd) "And then she had a baby." 100 < RepriseTextDNA(PrinceIsBornDNA) 100 >
In this case, prior rules might call either one of these two rules using the UseTextDNA function, since they both have the same subject. However, clearly things are likely to develop differently if the heroine dies than if she has a child. The DeadHeroineDNA variable contains the name of one set of TextDNA which continues (or completes) the text with a dead heroine, while the PrinceIsBornDNA contains the names of a set of TextDNA which continues the text with a child. Note that if there were only a single relevant rule-set in either case you could just use the UseTextDNA function- the RepriseTextDNA function would be used in this case if (as in real life!) there were multiple possible paths through birth and death.
The GetRhyme function
The GetRhyme function takes two arguments: a variable name, and a suffix. It returns a randomly-selected entry from a BrainFood file that has the name of the _value_ of the variable, plus the suffix. Although it may prove useful in many different circumstances, its main purpose is to make it possible to write rhyming verse which uses any one of a number of rhymes. If you define a number of files 'x.verb', 'x.noun', 'x.exclamation' (where 'x' takes multiple values- i.e. 'dog', 'cat', 'pig') then you can always call a word which rhymes in the proper place, without always writing poems which use the same rhyme. For example:
100 Subject(AnimalPoemSetUp) < assign(Cur,"dog,cat,pig") 100 >
100 Subject(ShortAnimalPoem) "A" 100 < GetRhyme(Cur,noun) 100 > "likes to" 100 < GetRhyme(Cur,verb) 100 > "!" 100
The first line of TextDNA sets the value of the variable 'cur' to either 'dog', 'cat', or 'pig'. Assuming the existence of the appropriate BrainFood files (which, incidentally, do not actually exist- you'd have to make them to run this example), the second line writes a short poem alleging that the animal in question likes to do something that rhymes with its name. One possible outcome of firing these two lines of TextDNA might be:
However, it is equally possible that the identical lines might produce:
The 'GetSubject' Function
The 'GetSubject' function can be used to personalize your JanusNode's creations with a single name and matching pronoun and possessive. The function usually takes one of four arguments: 'name','pronoun','possessive', or 'object'. It will return the correct name, pronoun, possessive, or object as determined by its question at start-up or by the information garnered when you click on the 'Set Subject' button in the Control Panel. The 'GetSubject' function can also be used to change the name or sex of the current subject from within a line of TextDNA. If the argument is 'he', then the gender of the subject will be set to male. If the argument is 'she', then the gender if the argument will be set to female. If the argument is anything else, then the name of the subject will be set to the argument. In all three of these latter cases, nothing is returned.
Consider the following example:
100 < getSubject(Jane) 100 > < getSubject(name) 100 > s_verbs_from 100 < getSubject(possessive) 100 > s_nouns 100
This TextDNA will always change the subject's name to 'Jane', since the first call to the 'getSubject' function has 'Jane' as an argument, and is guaranteed to fire. After that, it will print the new name, 'Jane', since the second call has 'name' as an argument, and is also guaranteed to fire. This will be followed by a verb which takes the word 'from', a possessive, and a noun. On possible outcome of thus TextDNA is the production of the phrase:
However, note that this snippet of TextDNA might also print:
It will do so if the last subject was a male, since there is nothing in this TextDNA which sets the sex of 'Jane' - and a JanusNode is far too dumb to figure things like that out for itself. We could have remedied this by adding the function call '< getSubject(she) 100 >' anywhere before the call '< getSubject(possessive) 100 >'. This would set the subject.
The 'backspace' function
The 'backspace' function exists to allow for the suppression of the space that a JanusNode normally inserts between words: i.e. it deletes the last character that was output, and prints from the new end. There are many situations in which this might be useful- for example, if you want to write a string of TextDNA which uses parentheses, or which creates compound words, or if you want to keep sentences in paragraphs. The function takes no arguments and returns nothing.
Example:
This string of TextDNA will ask you to imagine a new compound noun. For example, it might print:
You may certainly feel free to develop this idea commercially.
'Backspace' has one counter-intuitive (but rather useful) behavior, which is that it will erase as many spaces and returns as it finds (It will never erase more than one single non-whitespace character, and will erase even a single one only if the last character printed happens to be non-whitespace.) This is useful because your JanusNode automatically inserts a linefeed after firing any line of textDNA, even lines that have no actually printing in them. If you want that textDNA to be 'transparent' (have no effect at all on output), then terminate the line with a call to the backspace function. If you want to see an example of why this might be useful, look at the vocabulary-morphing rule in, for example, file '0RJ.I' in the RobotJohnson textDNA folder.
The 'quotation' function
The quotation function allows the user to use (straight or curly) quotation marks within a string of TextDNA, so that your random texts can cite other random texts. It takes one of two arguments, "o" or "c", or no argument. If the argument is "o" the function will return an opening curly quote. If it is "c" the argument will return a closing curly quote. If there is no argument, the function return a straight quote.
Example:
This TextDNA makes use of TextDemons, which are defined in the following section of this documentation. This string of TextDNA will print quote a verb phrase and a noun phrase following a verbatim introductory phrase. One possible outcome of the TextDNA is the creation of the phrase:
Profound, huh?
The 'UseFont', 'UseStyle', and 'UseSize' Functions
The 'Font-o-matic' feature
(described elsewhere in this documentation) allows you to get
JanusNode to randomize the font type, font size, and font style.
However, you can also use built-in functions to control (or randomize)
these aspects of text presentation from with TextDNAs, using the
'Usefont', 'UseStyle', and 'UseSize' functions. They all have
the same syntax: each one takes either a valid argument for what
it does (e.g. a font name, a font style, or a font size respectively)
and sets the current display font to that size, style, and font.
All three arguments may also take the argument 'random', in which
case the relevant value is set randomly.
Legal font styles are 'bold', 'italic', 'extend', 'underline',
'outline' and 'plain'. Legal font names and sizes are system-dependent;
in general, you can usually use font sizes between about 10 and
127 if your system uses true type fonts.
Example: An example of a TextDNA using these functions is:
100 < UseFont(chicago) 100 > <UseSize(14) 100 > "This is" 100 < UseSize(24) 100 > < UseStyle(italic) 100 > "really" 100 < UseSize(14) 100 > < UseStyle(plain) 100 > "dumb TextDNA." 100
This self-referential string of TextDNA will print the sentence 'This is really dumb TextDNA.' in plain 14-point Chicago type, except for the word 'really', which will appear in italic 24-point Chicago.
The 'CapitalizeNext' Function
The 'CapitalizeNext' function takes no arguments. It simply ensures that the item which follows it will start with a capital letter.
Example:
100 "This is a name:" 100 < CapitalizeNext() 100 > syllables 100 < backspace() 100 > syllables 70
This string of TextDNA will print out "This is a name:" followed by a one or two-syllable nonsense word which starts with a capital letter. One possible outcome is:
The 'BecomePassive' Function
The 'BecomePassive' function takes no arguments. When it is called, processing stops and your JanusNode enters a passive, receptive state. Please note that a JanusNode must fire all functions before it can print a line of TextDNA, since most functions are intended to return printable components of that line. For this reason, the 'BecomePassive' function should not appear with any text that you wish to print. If it does, that text will never get printed, since your JanusNode wil become passive before it gets to printing it.
Here is an example of a full line of textDNA:
100 Subject(End) < BecomePassive() 100 >
When this line fires, processing will halt.
Limitations
There is no practical limit to the quantity of TextDNA you can define, since you can have approximately as many TextDNA files as you wish. Since TextDNA can call specific lines of TextDNA, even when they are in another file, there is no limit to how complex your production's connections and structure can be.
Error-checking
A JanusNode dynamically checks the syntax of each line of TextDNA as it is processed. Some kinds of major syntax errors errors are flagged with a description. The description includes the line number, the offending element in the TextDNA, and a copy of the text of the offending TextDNA. Click on the error message field to make it disappear when you have corrected the error in the TextDNA field. JanusNodes do not stop processing for most errors (i.e. the most common errors of a mis-named BrainFood file-name or a missing probability afer an element in TextDNA). If it encounters an error of this type, a JanusNode will print an error message in its output field and will attempt to keep processing. It can often recover from such errors, but sometimes it will print a very large number of error messages before it recovers. If your JanusNode prints nothing but error messages, the most likely cause is either that your 'BrainFood' folder is missing or mis-named, or that you have an extraneous element (or a missing element) early on in your TextDNA (for example: a missing probability after a BrainFood file name).
Nesting TextDNA Elements
Nesting of repeats, functions, and alternatives is not currently allowed: that is, you cannot put square brackets within square brackets, curly brackets within curly brackets, or function calls within function calls. This wil be remedied in a future version of Janus. You can nest repeats, functions, and alternatives within each other. For example, the following is a perfectly legal line of TextDNA:
100 < getSubject(name) 100 > [ { s_verbs_from 100 < getsubject(possessive) 100 > s_nouns 100 | s_verbs_to 100 s_objects 100 } "," 100 ] return 100
One outcome of this TextDNA
might be the creation of the phrase "Linda runs from her
playmate, accepts from her estimation, receives from her community,
steals from her era,", while another might be "Linda
takes to everything, shows to her, takes to him, gives to me,".
The inability to nest repeats, functions, and alternatives within
themselves (and the limitations imposed by the order in which
JanusNode parses each of these) are not hard-wired, however. You
can use TextDemons to nest anything within anything, and to gain
complete control over how your TextDNAs are parsed. We now turn
our attention to TextDemons.
TextDemons
TextDemons are very similar to TextDNA. The main difference is that TextDemons are not directly chosen by a JanusNode from the field where they are defined, but must rather be part of a TextDNA string. TextDemons are defined in the 'TextDemons' field. They have a similar format to TextDNA, except that they don't begin with a global likelihood of being chosen, but rather with a name which must always begin with the string 'TextDemon'. Examples of acceptable names are 'TextDemonAdverbPhrase' or 'TextDemonMyTextDemon'. After the name a TextDemon can contain anything that TextDNA can contain: indeed, their structure is identical except for the first item.
Once a TextDemon has been defined and 'compiled' (which is taken
care of automatically) then you can use TextDemons in any string
of TextDNA (or in any TextDemon) in just the same way you use
any other item: by writing the name of the TextDemon followed
by a percentage likelihood of it being chosen.
For example, we might define a TextDemon in the TextDemon field
as follows:
We can then use this TextDemon in a line of TextDNA, defined in the TextDNA field, as follows:
The TextDemon defines a noun-verb phrase (possibly modified with one or more adverbs). The above TextDNA might generate the sentence:
TextDemons provide great flexibility for your TextDNA. You can
use them to define constants, to define commonly-used text chunks,
and to gain finer control over the way units are repeated or chosen.
One word of warning: Although JanusNode does correctly parse TextDemons
which contain quotes, it must, for technical reasons, parse such
TextDemons character-by-character rather than word-by-word. For
this reason, TextDemons containing quotes are MUCH slower to compile
than TextDemons which contain no quotes. In order to get around
this, two special symbols have been defined for use in the TextDemon
field: 'Q1' and 'Q2'. These can be used to substitute for opening
and closing quotes respectively in TextDemons which contain only
one pair of quotes. I recommend that you use this method of quoting
in all TextDemons. If you want to quote more than one element
in a TextDemon, define each of the quoted elements as a separate
TextDemon.
Every JanusNode ships with many pre-written TextDemons in the
TextDemon field. Since they are subject to change and open for
tinkering by any user, they are not documented officially. You
will have to take a look at them if you want to see what they
do. However, you should be careful, since theTextDNA which is
distributed with your JanusNode depends on the TextDemons which
came with it. You are welcome to delete all the TextDemons that
come with your JanusNode, but do not do so unless you understand
what you are doing, as much of your TextDNA will be non-functional
without the appropriate TextDemons.
Limitations
The 'TextDemons' field is currently limited by an internal limit on the size of a text field (32K). In the future (maybe when I retire in about thirty years) Janus will be re-written to avoid this limit. If it gets to be a problem for you before that time, let Janus know- you're a power-user with whom Janus would like to be in contact!