Module:Grind/doc
This is the documentation page for Module:Grind
Module:Grind was created to solve grind optimisation and estimation problems. It uses a custom object encoding: GRON (grind object notation).
GRON format[edit]
Strings[edit]
- Simple form: "abc" ->
abc
.- Note that the following characters are forbidden in simple form:
,:;()"
.
- Note that the following characters are forbidden in simple form:
- Full form: "abc" ->
"abc"
.,:;()
are allowed in full form.- To use
"
, escape it with \:"\"I myself am my only true friend!\""
- To use
\
, escape it with another \.
GRON objects[edit]
GRON objects consist of:
- An opening bracket
(
; - A
;
-separated list of entries;- Each entry is one of the following:
- A numbered value: a string in any form or another GRON object.
- Internally, these values are numbered. You do not need to provide any number with the value, and there is no way to do it explicitly.
- If a GRON object ends with
;)
, the last numbered value will be an empty string.
- A named value, consisting of a key (a string in any form),
:
and a value (a string in any form or another GRON object).- You may provide key-value pairs in any order and place them between numbered values (only the relative order of numbered values determines how the GRON object is interpreted).
- A special tuple syntax is supported for values. A tuple is a
,
-separated list of (non-tuple) values. It is equivalent to a GRON with numbered values:(a:b,c)
<->(a:(b;c))
.
- A numbered value: a string in any form or another GRON object.
- Each entry is one of the following:
- A closing bracket
)
.
Formulae[edit]
Some of GRON objects will accept formulae instead of numeric constants.
A formula is a GRON object of the form: (formula; <FORMULA_STRING>)
, where the formula string is a string as defined above.
Formula strings have the structure usual for expressions in many programming languages and support:
- unary operators
+-
; - binary operators
+-*/
; - brackets
()
; - numeric constants, both integers and floats;
- variables
$(VAR)
;- Variable names shall not contain symbols
()"
. - Whitespace symbols are not removed from variable names:
$( Watchful )
is valid but incorrect. - Variables with non-provided values are considered to be 0.
- The usual naming notation rules apply to variable names. In particular, the prefix
Input:
makes the variable value to be filled from the corresponding input value.
- Variable names shall not contain symbols
- function calls
f(A,B,C)
;err($(MESSAGE))
is a special function-like pattern which parses directly into an error with messageMESSAGE
.- The following mathematical functions are supported:
min(a,b)
: minimum of two values.max(a,b)
: maximum of two values.exp(a)
: exponent.ln(a)
: natural logarithm.pow(a,b)
: a^b.sqrt(a)
: square root.sign(a)
: signum (negative: -1, zero: 0, positive: 1).abs(a)
: absolute value.round(a)
: rounding to the nearest integer.floor(a)
: rounding to the nearest integer <=a.ceil(a)
: rounding to the nearest integer >=a.sin(a)
: sine.cos(a)
: cosine.tan(a)
: tangent.pi()
: pi (constant).
random.range(A, B)
is the uniform distribution of integers A, A+1, A+2, ..., B-1, B.- All distributions described in a formula are considered to be independent.
- You may pass the distribution to other functions (including
random.range()
itself) to create more complex distributions. - To approximate the continuous uniform distribution, use
random.range(0,C)/C
with a sufficiently large constantC
.
Examples:
random.range(1,$(Watchful))
.floor($(Persuasive)/3)
.
Supported GRON objects[edit]
Conventions
- The first numbered argument of a basic block is its name in lower case.
- If a block
action
accepts a named argumentchallenge
, the former will sometimes be referred to as(action)
and the latter as(action).challenge
.
- If a block
- Wherever a range is required, you may provide one in the following forms:
1
: exact value.1-3
: exact range.-4--3
: exact range with negative numbers.
1-
: from 1 to infinity.-3
: from 0 to 3.-
: from 0 to infinity.
- Wherever a boolean value is required, it must be one of the following strings:
true
/false
yes
/no
on
/off
1
/0
- Wherever a pyramidal quality is specified, you should provide CP amounts and values instead of levels.
- Wherever a number is required, you may provide a formula (without
random.range
calls). Wherever a distribution is accepted, you may userandom.range
as well.- All variables used must be static: progress qualities for other blocks cannot be used.
- Variable prefix and suffix notation:
- (input) names require suffixes specifying the type of the input (which affects both calculator inputs and input interpretation during substitution):
:GRON
: GRON input.:String
: string input.:Number
: number input.:Boolean
: boolean input (will be interpreted as 0 or 1).
- Formula variables corresponding to inputs must have an
Input:
prefix and might have a numeric type suffix (:Number
,:Boolean
). Is no type suffix is encountered, number is assumed.(input; Test:Number)
is the same as(formula; "$(Input:Test:Number)")
.
- You may use numeric type suffixes for (action).challenge quality, (req).target, (pswitch).target, (gate).target and formula variables corresponding to items and qualities. If none is encountered, number is assumed, unless there is special handling for this particular item or quality.
- (input) names require suffixes specifying the type of the input (which affects both calculator inputs and input interpretation during substitution):
(import)[edit]
Signature: (import; <TARGET>[; late:<LATE>; assume:<ASSUME>]).
Imports and substitutes the GRON object from the specified page's Has grind definition
SMW property.
Required arguments:
- The second named argument: string. The title of the target page.
Optional arguments:
late
: boolean. Default: false. If true, the actual import will happen during evaluation. Might be used to reduce SMW properties length.assume
: a GRON object. Each key is player stat or a quality or an item, each value is a number. If set, these will be substituted into the imported object immediately.
(input)[edit]
Signature: (input; <NAME>).
A placeholder indicating that an input is expected.
Required arguments:
- The second named argument: string. ID of the input placeholder.
- You should specify the type of input with the relevant suffix.
- The string shall not contain anything except letters, numbers and the type suffix.
(ref)[edit]
Signature: (ref; <ID>).
A local reference. Expands into the element with the corresponding ID. References are resolved before imports, so you cannot reference imported GRON objects.
Required arguments:
- The second named argument: string. ID of the target element.
- The element must be located somewhere in the GRON object and have the
id
argument set.- The
id
argument is not mentioned elsewhere since it is only used for references; it is supported for all GRON objects.
- The
- The element must be located somewhere in the GRON object and have the
(action)[edit]
Signature: (action[; title:<TITLE>; link:<LINK>; a:<A>; comment:<COMMENT>; challenge:<CHALLENGE>; success:<SUCCESS>; failure:<FAILURE>; alt_success:<ALT_SUCCESS>; alt_success_p:<ALT_SUCCESS_P>; alt_failure:<ALT_FAILURE>; alt_failure_p:<ALT_FAILURE_P>]).
Optional arguments:
title
: a string. The title to be displayed. If a page with this title exists (or thelink
parameter is specified), the title will be formatted as a link during formatting.link
: a page. The link to the action. Default:title
, if such page exists.a
: a string. Action cost. Default: 1.comment
: a string. A comment for this action.challenge
: a GRON object consisting of key-value pairs. The challenge associated with this action.- The key is the tested quality.
- The value is either:
- A string: challenge level. If the quality is
Luck
, it is the percentage of success. For other qualities, it is assumed it is a broad challenge. - A tuple of two strings. The first value is challenge level, the second one is
broad
/narrow
. Note that narrow difficulty is interpreted as the level one needs to get 50% probability of success; broad difficulty is interpreted as the level one needs for 60%. - A tuple of three strings. The third is the narrow difficulty step.
- A string: challenge level. If the quality is
success
: GRON. The provided object is a set of named values, where keys are quality/item names and values correspond to how many is added/removed. For qualities, always use CP. More complex assignments are currently not supported in effects.- You may put an input placeholder instead of a value.
- You may put a value distribution instead of a value.
failure
: GRON. Same as above.alt_success
: GRON. Same as above. Used as an alternative/rare success effect, which, should the challenge be passed or absent, is applied with probabilityalt_success_p
.alt_success_p
: number string, from 0 to 100. Default: 0. The probability of the corresponding alternative/rare success in %.alt_failure
: GRON. Similar.alt_failure_p
: number string, from 0 to 100. Default: 0. Similar.
(nop)[edit]
Signature: (nop[; avoid:<AVOID>]).
Equivalent to (action;a:0;title:"Do nothing")
if used without arguments.
Optional arguments:
avoid
: boolean string. Default: false. If set, (best) blocks will avoid choosing this option whenever possible.
(seq)[edit]
Signature: (seq; <ITEM_1>; <ITEM_2>; <...>).
A sequence of actions or other GRON objects; individual items are not repeated.
Numbered arguments, starting with the second one, are GRON objects.
(airs)[edit]
Signature: (airs; <ITEM_1>; <ITEM_2>; <...>; ranges:<RANGES>[; range:<RANGE>; target:<TARGET>]).
A randomiser.
Required arguments:
ranges
: a tuple of airs ranges. The number of ranges shall be equal to the number of remaining numbered arguments; ranges shall not intersect; ranges shall cover the entirerange
.- Numbered arguments, starting with the second one, are GRON objects.
Optional arguments:
range
: a range. The main range of airs. Default: 1-100.target
: a string. Airs quality name.
(req)[edit]
Signature: (req; <ITEM_1>; <ITEM_2>; <...>; target:<TARGET>; ranges:<RANGES>).
Requirement-dependent behaviour (static requirements only).
Required arguments:
target
: a string. The name of the prerequisite.ranges
: a tuple of ranges. The number of ranges shall be equal to the number of remaining numbered arguments; ranges shall not intersect; ranges should cover the entire range of possibletarget
values.- If a value is not covered by the ranges,
(nop)
is substituted.
- If a value is not covered by the ranges,
- Numbered arguments, starting with the second one, are GRON objects.
One special feature of (req) is that it can be used for non-GRON values as well. See the examples section.
(pswitch)[edit]
Signature: (pswitch; <ITEM_1>; <ITEM_2>; <...>; target:<TARGET>; ranges:<RANGES>; action:<ACTION>).
Progress-dependent resolutions. The action is performed once to gain the progress quality, then, depending on its amount being in the specified ranges, different resolutions are assumed to be applied. For that, the distribution of the progress quality gains is estimated.
Required arguments:
target
: a string. The name of the progress quality/item.ranges
: a tuple of ranges. The number of ranges shall be equal to the number of remaining numbered arguments; ranges shall not intersect; ranges shall cover the entire range of possibletarget
values.action
: a GRON object. The action providing the progress quality. It is not repeated. It is always optimised to maximise the progress quality.- Numbered arguments, starting with the second one, are GRON objects corresponding to the resolutions.
(best)[edit]
Signature: (best; <ITEM_1>; <ITEM_2>; <...>).
Selects the item with the best resource-per-action or the best resource value for the resource in priority.
Numbered arguments, starting with the second one, are GRON objects corresponding to the possible choices.
(gate)[edit]
Signature: (gate; target:<TARGET>; action:<ACTION>[; resolution:<RESOLUTION>; reset:<RESET>; must_succeed:<MUST_SUCCEED>; failure_cost:<FAILURE_COST>; preserve_progress:<PRESERVE_PROGRESS>; optimise:<OPTIMISE>]).
An action with a grindable prerequisite.
Required arguments:
target
: a tuple of two strings. The resource to be collected and the amount required.- The amount might be a distribution.
action
: a GRON object providing the prerequisite quality. It is assumed it can be repeated as much as needed, be it 100 times or 2.15 times. Also see thereset
optional parameter.
Optional arguments:
resolution
: a GRON object. It is assumed that the specified amount of the prerequisite quality is consumed by the action; you should not specify its loss explicitly.reset
: boolean. Default: false. If yes, it will be assumed the resolution (even if not specified) resets the progress quality.must_succeed
: boolean. Default: false. If yes, and if the resolution is an action, it will be repeated as much as needed until success.failure_cost
: string. Default: 0. Ifmust_succeed
, it will be assumed that a failure during the resolution action will cost the player the specified amount of the progress resource.- It might be a distribution.
preserve_progress
: boolean. Default: false. If set, the usual behaviour will be overridden and the progress quality gained will not be removed from the output effect. Generally useful only whenresolution
is undefined.optimise
: boolean. Default: true. If set to false, (gate).action will be optimised against the previous resource in priority rather than for (gate).target.
If you need to grind for more that one prerequisite, use the following pattern:
(seq;(gate;target:<target1>;action:<action1>);(gate;target:<target2>;action:<action2>);<resolution>)
.
(filter)[edit]
Signature: (filter; <ACTION>[; target:<TARGET>]).
An effect output filter.
Required arguments:
- The second numbered argument: GRON. The action to be filtered.
Optional arguments:
target
: either a string or a tuple of strings. Default: empty. The whitelist for the effect outputs.- You cannot avoid considering menace and material costs with (filter): they directly modify the number of actions associated with an (action).
(sell)[edit]
Signature: (sell; action: <ACTION>[; market: <MARKET>; optimise: <OPTIMISE>; <...>]).
A block selling the specified resources in 0 actions.
Required arguments:
action
: a GRON object. The inner action generating the resources to be sold.
Optional arguments:
market
: a string. If specified, market name will be included during formatting. Include "the" if necessary.optimise
: a string. If specified, it should be a name of a resource gained from selling other resources. If specified, the block will make a reasonable attempt to maximise output of the specified resource.- Other named arguments. Keys are resources that can be sold. Values are effects from selling 1 of the corresponding resource in the same format as in (action).success. Note that distributions are currently not supported for sell effects.
Examples[edit]
(best) and (airs)[edit]
(best; <1>; (airs; ranges: 1-50, 51-100; <2>; <3> ) )
- Choose the best: either <1> or the airs-dependent option, which might be <2> or <3>.
(airs; ranges: 1-50, 51-100; (best; <1>; <2> ); (best; <1>; <3> ) )
- Depending on airs, choose the best available option.
(ref)erences[edit]
To avoid repeating <1>
in cases similar to the previous example, you can use references:
(airs; ranges: 1-50, 51-100; (best; (action; id: "literally any string"; title: "A big GRON here" ); <2> ); (best; (ref; literally any string); <3> ) )
(seq; (gate; target: Rostygold, 10; action: (best; id: choice; (action; success: (Rostygold: 1) ); (action; success: (Moon-Pearl: 1) ) ) ); (gate; target: Moon-Pearl, 10; action: (ref; choice) ) )
That (best) object is copied before the preprocessing removes the progress-irrelevant options from it. After preprocessing it will be:
(seq; (gate; target: Rostygold, 10; action: (action; success: (Rostygold: 1) ) ); (gate; target: Moon-Pearl, 10; action: (action; success: (Moon-Pearl: 1) ) ) )
(seq; (ref; nothing); (nop; id: nothing) )
- References may appear before the element with corresponding ID is defined.
(best; id: "we need to go deeper"; (nop); (ref; "we need to go deeper") )
- Oh no! Never do this.
(req) for non-GRON values[edit]
Sometimes you might want to make a non-GRON value stat-dependent. You can do it:
(action; title: "Zail against the Currents"; a: (req; target: "Zailing Speed"; ranges: 45, 55, 75; 5; 4; 3 ) )
(gate).preserve_progress[edit]
Sometimes you might want to specify that:
- a fixed amount of a resource should be collected;
- a GRON subobject should be optimised for a specific resource without it being consumed immediately.
Both cases can be resolved with a (gate) object that would not reset its progress resource in the output effect.
Consider the following fragment from a possible GRON representation of a Night-Whisper grind using Tribute (which is still technically consumed, just in another place).
(gate; target: Night-Whisper, 12; preserve_progress: yes; action: (action; title: "Enjoy a bubbling hookah with the Minister of Culture"; a: 4; success: (Night-Whisper: 1) ) )
The player usually intends to convert all the Tribute there as zailing takes actions. The chosen approximation is the assumption that 240 x Tribute is always spent there, hence 12 x Night-Whisper. It is definitely desirable that those Night-Whispers remain in the output effect.
Now consider the problem: writing a GRON object to optimise gain of some chosen resource.
The initial version could look like this:
(best; (import; "Source 1"); (import; "Source 2"); (import; "Source 3") )
If one of sources has irrelevant outputs associated with irrelevant choices, this grind will have all of those outputs. Most annoyingly, the outputs will be valid options for calculators associated with the GRON object.
(gate) objects specifically optimise (gate).action for their targets, also excluding irrelevant choices. The corrected version would then be:
(gate; target: Resource, 1; preserve_progress: yes; action: (best; (import; "Source 1"); (import; "Source 2"); (import; "Source 3") ) )
(filter)[edit]
To filter out undesired effect outputs completely, use (filter).
(filter; target: Rostygold; (action; success: (Rostygold: 1; Moon-Pearl: 1) ) )
In this example, only the Rostygold output will be considered when scanning GRON metadata and optimising the grind. Moon-Pearls will still be shown in formatted GRON.
Optimisation process[edit]
During optimisation, the following things are tracked: the resource in priority, the distribution of possible effects, the number of actions associated with the effects, optimisation target (which is either absolute resource value or resource per action).
(action)[edit]
Actions are only evaluated. Based on player data, the probability of passing the challenge is computed. Then, a distribution consisting of success and failure effects with their probabilities is returned.
(seq)[edit]
Sequences optimise items independently and return the distribution of the sum of their distributions.
(airs)[edit]
Airs optimise items independently and mix the resulting distributions with the corresponding airs range probabilities.
(pswitch)[edit]
Progress switches optimise the main action against the tracked quality. Then, based on resulting distribution of the quality, probabilities of each range are computed. Each resolution is optimised, and their effect distributions are mixed with the computed probabilities. This distribution is returned.
(best)[edit]
Best blocks optimise each item and choose the one with the highest expected resource-per-action or absolute resource value. The latter depends on whether a (gate) or a (pswitch) is the nearest GRON superobject.
(gate)[edit]
Gates optimise their repeatable action against the tracked resource and compute the expected resource-per-action for it. Based on it, the number of actions spent on gathering the required amount of the tracked resource is estimated. The resolution is optimised, and its distribution of effects is returned.
(sell)[edit]
Sell blocks forward received priorities to the inner action with (sell).optimise undefined.
If it is defined, the block will also try to optimise its action against resources that can be sold. Among all options, (sell) will choose the one that is best for (sell).optimise for the active optimisation target.
Missing features and limitations[edit]
The following features are planned to be implemented:
- Drawing cards.
The following features are not supported by design (which might or might not change):
- Progress qualities in (formula)e and (req)uirements. That would require changes to the optimisation process which would make it as inefficient as simulating distinct states for all possible progress quality values. This could be implemented in a standalone program, but not in a MediaWiki module.
- (pswitch) always optimises its action to maximise the tracked resource. Sometimes a lower range might be more beneficial. But optimising GRON for a specific range of a resource would require iterating all possible choices rather than optimising each against a clear criterion. It would be very inefficient.
- (pswitch) and (gate) cannot optimise for a combination of a number of resources. That would, again, require iterating all possible choices. Therefore there is no good way to build a GRON object for certain Newspaper editions.
- Formulae in range parameters.
- Some of more complex patterns in grind strategies:
- Example: getting tribute, then zailing to the Court of the Wakeful Eye and converting it to other resources (this example can still be approximated).
Using Module:Grind[edit]
The module exports the following functions:
analyse
[edit]
- The main function for grind evaluation.
- Argument 1: string. The placeholder text.
#RPA#
will be replaced with the actual resource-per-action number.#OPTIMAL#
will be replaced with the optimal strategy, nicely formatted.#EFFECT#
will be replaced with the expected effect, nicely formatted.
- Argument 2: string. The resource against which this GRON object will be optimised.
- Argument 3: GRON string.
- Named arguments: player stats.
- Named arguments from the parent frame will be used as well.
- Named arguments starting with
Menace:
orAntiresource:
are interpreted as antiresource specifications; the value is interpreted as a number of actions to remove a single point of that antiresource.- Example:
Menace:Wounds
with value0.5
means that the player can remove 2 CP Wounds per action.
- Example:
- Named arguments starting with
Material:
are interpreted as material specifications; the value is interpreted as a number of actions to acquire a single point of that material. - Named arguments starting with
Input:
and having a type suffix are interpreted as inputs; the value is substituted into the corresponding input placeholder.
- Output: the placeholder text with the specified substitutions.
Usage examples[edit]
Input:
{{#invoke:Grind|analyse|EPA: #RPA# (#EFFECT#) #OPTIMAL#|Echo|(action;title:"Do something";challenge:(Watchful:12);success:(Echo:1.666))|Watchful=12}}
Output:
EPA: 0.9996 (1 action, +99.96 x Penny)
format
[edit]
- Argument 1: GRON string.
- Output: GRON object, nicely formatted.
Usage examples[edit]
Input:
{{#invoke:Grind|format|(action;title:"Do something";success:(Echo:1.4))}}
Output:
- Success: +140 x Penny.
preprocess
[edit]
- Preprocesses the GRON object, removing some pointless branches.
- Argument 1: GRON string.
- Output: GRON string.
Usage examples[edit]
Input:
{{#invoke:Grind|preprocess|(gate;target:Moon-Pearl,100;action:(best;(action; title:"Useful action";success:(Moon-Pearl:10));(action;title:"Useless action";success:(Rostygold:10))))}}
Output:
(gate;target:(Moon-Pearl;100);action:(action;success:(Moon-Pearl:10);title:"Useful action"))
compose
[edit]
- Computes grind composition, substituting provided values into input placeholders.
- Argument 1: GRON string.
- Named arguments: values for input placeholders. The key in a key-value pair must be equal to the ID of the corresponding placeholder
- Named arguments from the parent frame will be used as well.
- The type suffix of the key determines the manner in which the value is interpreted.
- Output: GRON string.
Usage examples[edit]
Input:
{{#invoke:Grind|compose|(input;test)|test=(nop)}}
Output:
(nop)
metainfo
[edit]
- Scans the grind, finds (input) placeholders, determines the outputs, adds SMW qualities and lists both the inputs and the outputs. Used in the {{Grind}}.
- Argument 1: GRON string.
- Output: as stated above.
autocalc
[edit]
- Produces a calculator form for the specified grind page.
- Argument 1: page. This page must have the
Has grind definition
SMW quality. - Argument 2: string. HTML id part associated with the calculator. Shall be unique in the page.
- Title: string. Calculator title. Empty by default.
- Template: string. The Template parameter passed to {{GrindAnalyse}}. Shall not contain
|
and newlines. - GRON: GRON string. The GRON object associated with the specified page. Used to build calculator inputs. It is a workaround to have calculators in sync with GRON data in grind pages. Shall not be used outside of {{Grind}}.
- Named arguments starting with
Extra
: strings. Each value is added to calculator inputs as a quality or an item or an additional GRON input.- Add a
:Boolean
suffix to have a toggleswitch with 0/1 values instead of a float input. - Add an
Input:
prefix and a type suffix for inputs.
- Add a
- Named arguments starting with
Material
: strings. Each value is added to calculator inputs as a material (a quality or an item) with some action cost to acquire. - Output: a calculator form.
Usage examples[edit]
Input:
{{#invoke:Grind|autocalc|Grind:Sunken Embassy Progress|testid}}
Output:
template = GrindAnalyse name = form = form-testid result = result-testid param = 1||Grind:Sunken Embassy Progress|hidden param = Resource|Optimise for:||select|Fragments of Infernal Affairs;Nothing param = RPA||per action|hidden param = maingroup|Main stats||group|Watchful,Shadowy,Dangerous,Persuasive param = Dangerous|Dangerous|100|int|0-500 param = Watchful|Watchful|100|int|0-500 param = advgroup|Advanced skills||group|Kataleptic Toxicology,Monstrous Anatomy,A Player of Chess,Glasswork,Shapeling Arts,Artisan of the Red Science,Mithridacy,Steward of the Discordance,Zeefaring param = Mithridacy|Mithridacy|0|int|0-20 param = menacegroup|Menace costs (in actions per point)||group|Menace:Wounds,Menace:Scandal,Menace:Suspicion,Menace:Nightmares,Menace:A Turncoat,Menace:Irrigo,Menace:Plagued by a Popular Song,Menace:Unaccountably Peckish,Menace:Ravages of Parabolan Warfare param = Menace:Nightmares|Nightmares|0.33|float|0- param = materialgroup|Material costs (in actions per point)||group|Material:Palimpsest Scrap param = Material:Palimpsest Scrap|Palimpsest Scrap|0.2|float|0-
gron_string
[edit]
- Processes the input string and formats it as a GRON string.
- Kills all strip markers: their initial values would be unrecoverable in another context anyway.
- It means some wikitext may be impossible to store this way.
- Argument 1: text.
- Output: GRON string.
Usage examples[edit]
Input:
{{#invoke:Grind|gron_string|{{IL|Watchful|+1 CP}}, "test"}}
Output:
" +1 CP Watchful, \"test\""