String Parsing Optimization

From Flexible Survival
Revision as of 18:12, 15 August 2017 by Songbird (talk | contribs) ([random x to y])
Jump to: navigation, search


String Parsing is a powerful language for designing content on the Flexible Survival MUCK. The language permits read functions, write functions, and allows users to create dynamic content based on a combination of those functions. Its semantics were originally designed by Damaged and later rewritten by Fauna for increased performance.

String Parsing, like other markup languages, does cause a hit in performance when inserted into plain text. This article exists to provide solutions for those seeking to squeeze the most performance out of their code without reducing readability. For information on how to write parsing, see the wiki article on String Parsing and review the in-game manual.


Performance: Why should I care?

Performance is important for a number of reasons.

Optimized code reduces the perceived latency of navigation in a MUCK. Doing so should be enjoyable on even the most sluggish of connections.
Optimized code reduces the Flexible Survival server load, thus permitting us to provide more and more detailed user-visible content.
Optimized code reduces the memory cost of programs and #dbrefs. In the case of a fatal memory spike or other unforeseen circumstances, the chances of services ceasing function are reduced when baseline memory is kept to a reasonable minimum.

How does this relate to String Parsing?

String Parsing is a markup language found throughout many aspects of the game. From transformation messages, to sex scenes, to exploration, to NPC interaction, and more, String Parsing is used to provide fresh and dynamic content. As a result, it's important to ensure that this code is clean, readable, and swift to execute.

Strictly speaking, a more important language to keep optimized is the MUF backend that Flexible Survival is based upon. However, since this guide is targeted at a general audience (who cannot edit MUF code in programs), String Parsing will be the focus.

For the subsequent sections, please use the in-game @viewparse command to indent and colorize markup for better legibility.

Conditionals

[if ][end if]


A basic [if ] statement is prone to some syntactic errors, but little in terms of optimization woes.


Always use the template [if [target] is <gender>] and [if time is

[if [target] = <gender>]
[if time = <time of day/season>]
[if [target] is <gender>]
[if time is <time of day/season>]

Do not check for integers with the '=' sign. This is a function designed to check a string. Use '==' instead. Benchmarks have shown that checking directly for an integer is both faster and cleaner.

[if stat cocks of [target] = 1]
[if stat cocks of [target] == 1]

Avoid not statements when possible. For example, [if time is not night] is the same as [if time is day].

[if time is not night]
[if time is not day]
[if time is day]
[if time is night]


[if ][else][end if]


[else] creates potential for redundancy if a coder is not paying attention. Here is a small before-and-after list of sentences, followed by clear instruction.


[if time is day]A woman in tight jeans and an unassuming blouse mans the counter. She's twirling a pen in her fingers, seemingly disinterested in her body of work.[else]A woman in tight jeans and an unassuming blouse would normally man the counter. However, she doesn't appear to be here right now.[end if]
A woman in tight jeans and an unassuming blouse [if time is day]mans the counter. She's twirling a pen in her fingers, seemingly disinterested in her body of work[else]would normally man the counter. However, she doesn't appear to be here right now[end if].


In the above example, repeated text has been removed from the [if ] statement itself and added as prefix. This provides the exact same user-visible output with less characters. Processing requirements are almost identical, but the text fits in less space and is just as readable.

Note: It's generally preferred to not cut off letters in words. Punctuation can be moved outside, but chopping up words results in text that is much less legible to people with screen readers.

[if ][else if ][else][end if]


[else if ] introduces further potential for code slowdown. Please read the following steps carefully to avoid that.


You [if [player] is male]try not to grow aroused by the Skunk Girl's sumptuous body, whining in protest.[else if [player] is female]easily ignore the Skunk Girl's attempts to seduce you.[else]easily ignore the Skunk Girl's attempts to seduce you. Neuters 4ever![end if]
You [if [player] is male]try not to grow aroused by the Skunk Girl's sumptuous body, whining in protest[else]easily ignore the Skunk Girl's attempts to seduce you[end if].[if [player] is neuter] Neuters 4ever![end if]


In the above example, a lengthy [if ][else if ][else][end if] statement is deconstructed into [if ][else][end if][if ][end if].

Converge the [else if ] and [else] statements into a single [else]. Move the neuter check into a separate [if ] statement at the end. Move the trailing periods in the [if ][else][end if] statement before the start of the neuter check.


The [if time is morning]sun is rising, stirring all forms of life into motion[else if time is afternoon]sun is high, baking the earth with its furious light[else if time is evening]sun is starting to set, casting the land in long shadows[else]moon shines over the land[end if].
The [if time is night]moon shines over the land[else if time is morning]sun is rising, stirring all forms of life into motion[else if time is evening]sun is starting to set, casting the land in long shadows[else]sun is high, baking the earth with its furious light[end if].


In the above example, a couple optimizations are made.

Place [if time is night] at the front. This is the longest period of time outside of 'day' (which is not used here), and ensuring it triggers first saves execution costs throughout most of the 24-hour cycle. Use the check for 'afternoon' as the final [else], because even though it is just as long a period as morning and evening, the name has more characters in it.

[case ]


Case-statements are useful where lengthy [if ][else if ][end if] statements would result in redundancy.


[case stat X of [target] ==][when (target) 1]A[end when][when (target) 2]B[end when][when (target) 3]C[end when][when (target) 4]D[end when][when 1]E[end when]
[case [stat X of [target]] ==][when (target) 1]A[end when][when (target) 2]B[end when][when (target) 3]C[end when][when (target) 4]D[end when][when 1]E[end when]


If something is valid parsing on its own, such as '[stat X of [target]]' and '[the mutation X of [target]]', use that, so the statement will only have to be parsed once instead of in every [when ]-statement.


[if stat blah/bluh/bleh of [target] == 1]A[else if stat blah/bluh/bleh of [target] == 2]B[else if stat blah/bluh/bleh of [target] == 3]C[else if stat blah/bluh/bleh of [target] == 4]D[else if stat blah/bluh/bleh of [target] == 5]E[else]F[end if]
[case [stat blah/bluh/bleh of [target]] ==][when (target) 1]A[end when][when (target) 2]B[end when][when (target) 3]C[end when][when (target) 4]D[end when][when (target) 5]E[end when][when 1]F[end when][end case]


In the above example, a complex [if ][else if ][end if] statement is optimized.

Convert the code to a basic case-statement. Since all comparisons are alike, remove them from their [when ] statements and append one to [case (target)]. Add brackets around 'stat blah/bluh of [player]' to avoid computing that in every [when ] statement.

Randomization

The following functions display content at random. Input is separated by [or].

[one of][or][at random]


The standard [one of][or][at random] statement is prone to redundancy.


Sometimes, a man's gotta man. [one of]Other times,[or]Sometimes,[at random] he doesn't.
Sometimes, a man's gotta man. [one of]Other times[or]Sometimes[at random], he doesn't.


In the above example, redundancy is fixed by moving a comma after [at random].


[with odds: ]

[with odds: ] allows you to simplify many longer [one of] statements.


[one of]1[or]1[or]1[or]1[or]1[or]2[at random]
[one of]1[or]2[with odds: 5 1]

or

[one of]1[or]1[or]1[or]2[or]2[or]3[at random]
[one of]1[or]2[or]3[with odds: 3 2 1]

[random x to y]


This function is more specialized than [one of][or][at random], lending itself well to optimization. Note that it only accepts numerical input (negatives included) and that 'y' should be greater than 'x'.


[one of]1[or]2[or]3[or]4[or]5[or]6[at random]
[random 1 to 6]


A complex [one of][or][at random] statement converted into a [random x to y] statement.






This document is a work in progress and is thus subject to change. All views and opinions expressed in here are solely Song's. Please only modify with either A) explicit permission to do so, or B) a fix for known factual inaccuracy / grammar errors.