-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: GVar Dictionaries (aka variable "options") #773
Conversation
We need to explicitly hide the third row, otherwise it will continue to be displayed. Set third row to `0`.
What's in there looks good!! Question: is there a reason we won't be able to check other characters or global? Long-term they'd be nice to have. I might even prioritize them over other things when we re-evaluate our list. |
Also a suggestion: when you update the to test section it might be good long-term if the comments indicating the output are valid Gem-script since the current ones crash the system. Easy enough to delete so don't bother if it's a hassle. |
Ironically, our wizard hack will allow us to construct the UI to support other characters and global characters, but the sim engine/compile side will not. It occurs to me however, that we could introduce a new keyword similar to
So If you want to set props just for the character, you would just use standard props:
And for tests, we would use:
(but this means we have to introduce a ton of keywords for all the math operations). We probably would not want to use options at all as the constructs would get REALLY hairy.
It's definitely awkward, and I'm not sure this would actually work. I'd have to confer with Sri to see if this is a terrible hack that breaks all kinds of rules. This will probably eat up another week (it'll be another half week to clean up and add support for numbers and strings already). Did you want to revisit the priorities before we do this?
Yeah, good suggestion. I think I'm actually using a working test script, but may have taken a shortcut. |
OH, never mind. I think we are good. I wanted to do the following, in Beaver and both appear to work.
The one other case I can imagine is something like color it might help to do something like the following, possibly even via a feature:
The idea being that it'd sync them up. HOWEVER, I think we have what we need for now, and moving forward on the GUI is ideal next-step? Thanks! |
But accessing options for featProps would still be a problem. For example, assuming we add a Costume featProp called
But we might have to introduce a
Otherwise, as before we'd have to revert to using stack operations:
|
Gotcha.I’d say let’s get the gui working and then revisit our full list given remaining time constraints?
|
If you have specific ideas for how you'd like to set colors we can see which of these approaches would be cleanest. But basically any color work that involves Features will at the very least need some new Feature methods/props to handle colors within agents, and at worse use stack operations across agents. |
Short term, we can use the stack operations and the feature Costume.colorCSS you had listed above (but not implemented) if that is doable? Then we can see what we use, etc, and go from there? Long-term I'd rather we find a way to override color with a color picker (maybe in the next grant)? |
…an ALL prop options in the blueprint)
@jdanish I believe I have numbers and booleans working now. Please see the updated test scripts. |
Looks good! |
See #755 for discussion.
GVar Dictionaries
GVar Dictionaries adds the ability to define multiple static
key
-value
pairings for character (agent) properties and to conduct test operations on the dictionary values.addOption
method for GVars.setToOption
method.keys
using GVar methods. e.g.ifProp character.colour equalToOption RED
checks ifcharacter.colour
value is equal to the dictionary value#f00
(not the keyRED
).Example Scripts:
NOTE GVar dictionaries only work in the context of the current character. You cannot reference global agent properties or properties from other characters.
Methods
General Options Methods
addOption
GVar methodAdd a new option to the designated GVar. Note options values match the GVar type, e.g. a string GVar's option will be a string, a number GVar's option would be string.
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the options in the option methods. e.g. defining a'RED'
option label allows you to use a constant label to set a constant value, e.g....setToOption 'RED'
<optionValue>
is the value that the<optionLabel>
is mapped to, e.g. if theRED
option label is set to the option value#f00
, then setting a prop value to the optionRED
would set the prop to#f00
.Example
setToOption
GVar methodAssign a prop value to the selected option value.
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the options in the option methods. e.g. defining a'RED'
option label allows you to use a constant label to set a constant value, e.g....setToOption 'RED'
.Example
equalToOption
GVar methodEvaluates whether a prop value matches the selected option value. This is generally used with
ifProp
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the option value in the option methods. e.g. testing a property value against a'RED'
option label allows you to see if your property value matches'RED'
's value ('#f00').Example
notEqualToOption
GVar methodEvaluates whether a prop value does not match the selected option value. This is generally used with
ifProp
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the option value in the option methods. e.g. testing a property value against a'RED'
option label allows you to see if your property value does not match'RED'
's value ('#f00').Example
Number Methods
greaterThanOption
number-only GVar methodEvaluates whether a prop number value is greater than the selected option value. This is generally used with
ifProp
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the option value in the option methods. e.g. testing a property value against a'LOW'
option label allows you to see if your property value is greater than'LOW'
's value ('10').Example
greaterThanOrEqualToOption
number-only GVar methodEvaluates whether a prop number value is greater than or equal to the selected option value. This is generally used with
ifProp
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the option value in the option methods. e.g. testing a property value against a'LOW'
option label allows you to see if your property value is greater than or equal to the'LOW'
's value ('10').Example
lessThanOption
number-only GVar methodEvaluates whether a prop number value is less than the selected option value. This is generally used with
ifProp
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the option value in the option methods. e.g. testing a property value against a'LOW'
option label allows you to see if your property value is less than'LOW'
's value ('10').Example
lessThanOrEqualToOption
number-only GVar methodEvaluates whether a prop number value is less than or equal to the selected option value. This is generally used with
ifProp
Syntax
where
<propName>
is the name of a property object reference. e.g. could becharacter.propname
oragent.propname.
or simplypropname
<optionLabel>
is the name of the option. Use this to refer to the option value in the option methods. e.g. testing a property value against a'LOW'
option label allows you to see if your property value is less than or equal to the'LOW'
's value ('10').Example
Use Case
There are three basic needs:
key
that is assigned to avalue
.key
from a list (rather than having to type it).key
(rather than matching it to the dictionaryvalue
).Four example use cases:
value
-- Assign anentityType
property to a character designating it aPRODUCER
,CONSUMER
, orDECOMPOSER
, and use a property operation test to trigger behaviors based on the selectedentityType
. Novalue
is used.value
-- Assign aenergyLevel
property whereLOW
is 0,MEDIUM
is 5, andHIGH
is 10, and use a property operation test to trigger behaviors based on numeric thresholds, e.g. do something ifenergyLevel
is higher thanLOW
.value
-- Assign aentityState
property to a character designating itHUNGRY
,CONTENT
,FULL
, orDEAD
, displaying the selectedvalue
during exectution, e.g.HUNGRY
would be displayed as the valueHungry
.value
and use a Feature property to trigger special operations -- Assign acolour
to a character property whereRED
="#f00"
,GREEN
="#0f0"
, andBLUE
="#00f"
and use thevalue
to set a costume color.Implementation History
1. Original Request
The original request was to provide a way to define constant-like declarations to use as part of GEMSCRIPT. For example:
2. Trying Constants
After conferring with Sri, we felt that a cleaner implementation of "options" would be to emulate the notion of constants. The requested features were less "enums" and more like "dictionaries". We suggested the use of the keywords
addConstants
andconstantPush
as a way to implement dictionaries. The implementation was fairly complex but essentially introduced a new set of agent properties calledconstants
to go along with the existingproperties
andmethods
properties.constants
essentially replicated the functionality ofproperties
as a parallel subsystem.While this implementation does work, the problem was that GEMSCRIPT can only handle assignments and tests to a simple javascript string, number, or boolean. We could not support assignments or tests to objects that are properties of agents or feature properties. e.g. you cannot use
prop character.colour setTo RED
because thesetTo
method only supports the assignment of pure strings, notRED
which would be aconstant
object. e.g. you cannot useifProp character.colour equal RED
for the same reason -- theequal
method can only work with a simple string, notRED
which is aconstant
object. The only way to assign values was to use stack operations. While this implementation "works", it is confusing for students and because of the complexity does not lend itself to "Let's try this" comment instructions.See discussion of constants implementation
3. Hacking in Options + UI
The third approach was to implement a hybrid solution. This involves a two part solution.
First, it adds the ability to add and use "options" to existing GVars like
class-sm-string
,class-sm-number
, andclass-sm-boolean
. By adding options directly to GVars, we can introduce GVar-specific options methods for use within the scope of the GVar. This allows us to do assignments and run tests on options. This also allows the simulation engine to compile and run code that references agent property-specific options during assignments and tests without fundamentally altering how the simulation engine works.Second, although we can introduce "options" methods to GVars that support the simulation engine, using the Script Wizard to construct GEMSCRIPT for "options" manipulation is not as straightforward. The Script Wizard uses a complex system that parses script text into tokens that are then in turn used to construct the wizard UI. The system is designed to work with standard keywords and syntax. But "options" do not quite adhere to the way keywords are handled, as a result, it has no way of constructing a list of user-defined "options" for the user to select -- we can generate lists of properties that have been added via code (e.g. user-defined character properties), but not the derivative methods (where the "options" are defined).
The workaround is to do two things:
This way the code data remains pure, can run on the standard simulation engine, and wizard hacks are confined to the purely visual rendering side.
LIMITATIONS with this approach
Cross-agent options do not work. e.g. you can't define an option for the
global
agent and use it with theFish
agent. Similarly, aFish
agent's option is completely separate from aAlgae
agent's options.We also cannot completely get around the need for some stack operations when working with GVar Dictionaries. E.g. if we're working with a character
prop
and you need to reference afeatProp
, you can only do cross-type assignments using a stack operation. e.g.Technical Aside
[In which Ben tries to document different approaches to the problem and serve as reminders of how the system works...feel free to skip.]
Bundle the option symbols as part of normal compile
One possible approach to streamline the "options" implementation: If we could bundle the "options" definitions as part of the tokens used to render the wizard, then we do not need a extra separate compile cycle.
addProps
figure out the list of newly defined props?addProps
defines new prop names that are listed when editing aprop
script line. So in wizard slot editor, the interpreted bundles do contain a list of the prop names as keys to theprop
object (e.g.props: { colour, scale, ...}
).script-compiler
calls:script-compiler.CompileBlueprint
, which breaks the blueprint into single lines inscript-compiler.CompileStatement
, which breaks down intoscript-compiler.DecodeStatement
, which in turn is broken down into tokens inscript-compiler.DecodeToken
, which returns the single token.addProp colour string 'black'
:a. keyword:
addProp
b. propName:
colour
c. GVar type:
string
d. GVar arg:
black
addProp
, the fourth token for "b. propName" is added to an array of newly defined property names.prop
keyword, we look up the list of previously defined propNames to provide a list of options. This also requires processing 4 tokens (e.g.prop character.colour setToOption 'RED'
):a. keyword:
prop
b. propName:
character.colour
c. GVar method:
setToOption
d. GVar method argument:
RED
class-symbol-interpreter
has to look up the available propNames.symbolize
function that generates all the available symbols). This is fed to...script-bundler.AddSymbols
constructs thefeatures
, andprops
(andconstants
if we keep that) lists from the symbol data generated by the bundler. Everything else is derived from that assymbolData
.EditSymbol_Block.f_renderchoices
generates the list of options fromsymbolData
symbol-utilities.DecodeSymbolViewData
generates lists based onprops
(andconstants
if we keep that).script-bundler.AddSymbols
. We would probably either:constants
(if we decide to implement constants)propOptions
or something like that?prop
keyword (if we're adding symbols to theaddOption
keyword), which is awkward, because we would then be diving down to the next level to process prop methods in order to symbolize values...addConstant
oraddPropOption
keyword that allows us to symbolize the keywords separately. BUT, then we would lose the ability to use prop methods to reference stored dictionary values (since they no longer a part of theprop
object)?SO...we either have a nicely constructed menu of symbols that cannot be compiled, or we have a compilable script but a wizard UI that is not able to generate the list of symbols.
RED
,GREEN
,BLUE
) for the 4th token "d. GVar method argument", we need to look up the options that have been defined for the second token "2. propName".THIS IS WHERE using a
constant
is potentially easier? e.g. rather than having to look up the propName, and then look up the option stuffed into the propName, we can use looking upaddConstant
keyword the same way thataddProp
works. But again, we have nice UI, but the code can't compile because we can't reference the option's value.CONCLUSION: Although it's less than ideal, the "simple" solution is to use the hybrid approach:
a. define options as part of the GVar
b. during wizard construction, scrub the script text to pull out "options" that have been defined in the code
c. inject a menu selection UI into the normal wizard to allow selection of the "option"
d. during code compile and execution, the "option" references the value of the "option" (e.g.
#f00
) rather than the "label" (e.g.RED
).To Test
dev-bl/enum
npm run gem
This should demonstrate:
@jdanish I'm still writing this out, but it's good enough to try out.
number
andboolean
haven't been implemented yet.TO DO
number
andboolean
tests