Listing Contents of a Pseudo-Container

Fyrdraca
27 Dec 2015, 07:32
So I have an object with several integer attributes; let's say, for argument's sake, object “treasure_chest”, with integer attributes “doubloons”, “jewels”, “ingots”, “artifacts”, and “idols”. I want to list the attributes like this:
“The treasure chest has 230 doubloons and 6 ingots,” or “The treasure chest has 17 jewels, 2 artifacts, and 1 idol.”
I want to create an algorithm where
1) it won't list the attribute if it doesn't have a value above zero,
2) it will adjust to the singular if the value is one,
3) it will print a comma after the attribute in question UNLESS it's the LAST attribute to have a value above zero, in which case it will
4) print a period after the attribute in question, and
5) print an “and” before the number UNLESS it's the ONLY attribute to have a value above zero.
6) Also, I've implemented a feature where it won't place a comma if two and only two attributes have values above zero.
My game has several of these pseudo-containers; I'll spare you the explanation for why they work with the dynamics of the game, sate to say that they do. This is what I have right now (which I assign to a command), and it does technically work, but it doesn't feel very elegant. My own code is hurting my eyes. Add onto that that some of these pseudo-containers will have dozens of these attributes, and you're looking at a lot of work. If anyone has a clever alternate approach, I'm all ears.

// set to command "check"
if ((treasure_chest.doubloons = 0) and (treasure_chest.jewels = 0) and (treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
msg ("The treasure chest is empty. Poor, disappointed pirate!")
}
else {
inv_count = 0
if (treasure_chest.doubloons > 0) {
inv_count = inv_count + 1
}
if (treasure_chest.jewels > 0) {
inv_count = inv_count + 1
}
if (treasure_chest.ingots > 0) {
inv_count = inv_count + 1
}
if (treasure_chest.artifacts > 0) {
inv_count = inv_count + 1
}
if (treasure_chest.idols > 0) {
inv_count = inv_count + 1
}
OutputTextNoBr ("Inside the chest you see ")
if (treasure_chest.doubloons > 0) {
if (treasure_chest.doubloons = 1) {
OutputTextNoBr ("1 doubloon")
if ((treasure_chest.jewels = 0) and (treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
else {
OutputTextNoBr (treasure_chest.doubloons + " doubloons")
if ((treasure_chest.jewels = 0) and (treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
}
if (treasure_chest.jewels > 0) {
if (treasure_chest.jewels = 1) {
if ((treasure_chest.doubloons > 0) and ((treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0))) {
OutputTextNoBr (" and ")
}
OutputTextNoBr ("1 jewel")
if ((treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
else {
if ((treasure_chest.doubloons > 0) and ((treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0))) {
OutputTextNoBr (" and ")
}
OutputTextNoBr (treasure_chest.jewels + " jewels")
if ((treasure_chest.ingots = 0) and (treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
}
if (treasure_chest.ingots > 0) {
if (treasure_chest.ingots = 1) {
if (((treasure_chest.doubloons > 0) or (treasure_chest.jewels > 0)) and ((treasure_chest.artifacts = 0) and (treasure_chest.idols = 0))) {
OutputTextNoBr (" and ")
}
OutputTextNoBr ("1 ingot")
if ((treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
else {
if (((treasure_chest.doubloons > 0) or (treasure_chest.jewels > 0)) and ((treasure_chest.artifacts = 0) and (treasure_chest.idols = 0))) {
OutputTextNoBr (" and ")
}
OutputTextNoBr (treasure_chest.ingots + " ingots")
if ((treasure_chest.artifacts = 0) and (treasure_chest.idols = 0)) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
}
if (treasure_chest.artifacts > 0) {
if (treasure_chest.artifacts = 1) {
if (((treasure_chest.doubloons > 0) or (treasure_chest.jewels > 0) or (treasure_chest.ingots > 0)) and (treasure_chest.idols = 0)) {
OutputTextNoBr (" and ")
}
OutputTextNoBr ("1 artifact")
if (treasure_chest.idols = 0) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
else {
if (((treasure_chest.doubloons > 0) or (treasure_chest.jewels > 0) or (treasure_chest.ingots > 0)) and (treasure_chest.idols = 0)) {
OutputTextNoBr (" and ")
}
OutputTextNoBr (treasure_chest.artifacts + " artifacts")
if (treasure_chest.idols = 0) {
OutputTextNoBr (".")
}
else {
if (inv_count <> 2) {
OutputTextNoBr (", ")
}
}
}
}
if (treasure_chest.idols > 0) {
if (treasure_chest.idols = 1) {
if ((treasure_chest.doubloons > 0) or (treasure_chest.jewels > 0) or (treasure_chest.ingots > 0) or (treasure_chest.artifacts > 0)) {
OutputTextNoBr (" and ")
}
OutputTextNoBr ("1 idol.")
}
else {
if ((treasure_chest.doubloons > 0) or (treasure_chest.jewels > 0) or (treasure_chest.ingots > 0) or (treasure_chest.artifacts > 0)) {
OutputTextNoBr (" and ")
}
OutputTextNoBr (treasure_chest.idols + " idols.")
}
}
}


I'm including for you the bit of code I run at the beginning of this game to test this algorithm, which I also assign to a command.

// set to command "reroll"
doubloons_dice = DiceRoll("1d5")
jewels_dice = DiceRoll("1d5")
ingots_dice = DiceRoll("1d5")
artifacts_dice = DiceRoll("1d5")
idols_dice = DiceRoll("1d5")
if (doubloons_dice = 5){
treasure_chest.doubloons = DiceRoll("1d5") + 1
}
else if (doubloons_dice = 4){
treasure_chest.doubloons = 1
}
else{
treasure_chest.doubloons = 0
}
if (jewels_dice = 5){
treasure_chest.jewels = DiceRoll("1d5") + 1
}
else if (jewels_dice = 4){
treasure_chest.jewels = 1
}
else{
treasure_chest.jewels = 0
}
if (ingots_dice = 5){
treasure_chest.ingots = DiceRoll("1d5") + 1
}
else if (ingots_dice = 4){
treasure_chest.ingots = 1
}
else{
treasure_chest.ingots = 0
}
if (artifacts_dice = 5){
treasure_chest.artifacts = DiceRoll("1d5") + 1
}
else if (artifacts_dice = 4){
treasure_chest.artifacts = 1
}
else{
treasure_chest.artifacts = 0
}
if (idols_dice = 5){
treasure_chest.idols = DiceRoll("1d5") + 1
}
else if (idols_dice = 4){
treasure_chest.idols = 1
}
else{
treasure_chest.idols = 0
}

jaynabonne
27 Dec 2015, 11:44
Here's one way to do it (attached and inline below).

To use this code, you must add an attribute named "contents" to your pseudo-container which is a string list of attributes, without the "s" on each. For example, if you have "doubloons", "ingots", and "idols" in your container, then you would have a list with elements "doubloon", "ingot" and "idol". It will append the "s" as needed to lookup the attribute and to make plurals. (See the "treasure_chest" object for an example.)

There are three added functions. The only one you need to worry about calling is GetPseudoObjectContents. But the other two are used by GetPseudoObjectContents and must be included as well.

I hope this code makes your eyes hurt a bit less. :)

The code works by first building a dictionary of values to include in the output, with the key being the type (e.g. "doubloon") and the value being the current count. Only existing, non-zero values end up in the dictionary. (That code is in the function GetPseudoObjectDisplayValues.) Then the rest of the code is just formatting the output string. The function GetPseudoValueString takes the dictionary and a key and returns a single string for that key, handling plurals (e.g. "1 doubloon", "2 ingots", etc).

<!--Saved by Quest 5.6.5783.24153-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="psuedotest">
<gameid>8a93393e-a1df-4067-8e35-f3fc09f6ea27</gameid>
<version>1.0</version>
<firstpublished>2015</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<object name="treasure_chest">
<inherit name="editor_object" />
<contents type="stringlist">
<value>doubloon</value>
<value>jewel</value>
<value>ingot</value>
<value>artifact</value>
<value>idol</value>
</contents>
</object>
</object>
<command>
<pattern>reroll</pattern>
<script>
doubloons_dice = DiceRoll("1d5")
jewels_dice = DiceRoll("1d5")
ingots_dice = DiceRoll("1d5")
artifacts_dice = DiceRoll("1d5")
idols_dice = DiceRoll("1d5")
if (doubloons_dice = 5) {
treasure_chest.doubloons = DiceRoll("1d5") + 1
}
else if (doubloons_dice = 4) {
treasure_chest.doubloons = 1
}
else {
treasure_chest.doubloons = 0
}
if (jewels_dice = 5) {
treasure_chest.jewels = DiceRoll("1d5") + 1
}
else if (jewels_dice = 4) {
treasure_chest.jewels = 1
}
else {
treasure_chest.jewels = 0
}
if (ingots_dice = 5) {
treasure_chest.ingots = DiceRoll("1d5") + 1
}
else if (ingots_dice = 4) {
treasure_chest.ingots = 1
}
else {
treasure_chest.ingots = 0
}
if (artifacts_dice = 5) {
treasure_chest.artifacts = DiceRoll("1d5") + 1
}
else if (artifacts_dice = 4) {
treasure_chest.artifacts = 1
}
else {
treasure_chest.artifacts = 0
}
if (idols_dice = 5) {
treasure_chest.idols = DiceRoll("1d5") + 1
}
else if (idols_dice = 4) {
treasure_chest.idols = 1
}
else {
treasure_chest.idols = 0
}
msg ("The treasure chest contains " + GetPseudoObjectContents(treasure_chest) + ".")
</script>
</command>

<function name="GetPseudoObjectDisplayValues" parameters="object" type="dictionary">
values = NewDictionary()
contents = object.contents
foreach(item, contents) {
attribute = item + "s"
if (HasAttribute(object, attribute)) {
value = GetAttribute(object,attribute)
if (value > 0) {
dictionary add(values, item, value)
}
}
}
return(values)
</function>

<function name="GetPseudoValueString" parameters="values, value" type="string">
<![CDATA[
item_count = DictionaryItem(values, value)
item_s = item_count + " " + value
if (item_count <> 1) {
item_s = item_s + "s"
}
return(item_s)
]]>
</function>

<function name="GetPseudoObjectContents" parameters="object" type="string">
<![CDATA[
values = GetPseudoObjectDisplayValues(object)
count = DictionaryCount(values)
if (count = 0) {
return("nothing")
}

s = ""
index = 0
foreach (value, values) {
item_s = GetPseudoValueString(values, value)
if (index > 0) {
if (index = count-1) {
s = s + " and "
} else {
s = s + ", "
}
}
s = s + item_s
index = index + 1
}
return (s)
]]>
</function>
</asl>

Fyrdraca
27 Dec 2015, 18:37
Thanks Jay, I appreciate you taking the time.