ASH Plural Typed Constants

jasonharper

Developer
r7525 introduces an experimental new ASH feature: plural typed constants. These allow you to easily do something with a list of specified objects, without having to replicate code or laboriously build up an array of the objects so that you can iterate over it. Here's a quick example:
Code:
foreach weapon in $items[star sword, star staff, star crossbow] {
	if (available_amount(weapon) > 0) {
		equip(weapon);
		break;
	}
}

The syntax is basically the same as the existing typed constant feature, but with an "s" or "es" after the type name. (The "es" case is there so that you can properly pluralize "class".) The text between the square brackets is interpreted as a comma-separated list of elements, each of which is converted to the specified type as if it were an individual constant. More details:
* The list can span multiple lines.
* Whitespace before or after elements is ignored.
* Completely empty elements are ignored (so that you can leave a comma at the end of the list).
* You can include a comma or closing square bracket in an element by writing it as "\," or "\]".
* All the other escape sequences allowed in strings are possible, such as "\n" (newline), "\t" (tab), and "\uXXXX" (Unicode character value). To put an actual backslash in an element, you have to write it as "\\".

The value generated by a plural constant is of type boolean[type], with the keys being the specified elements, and the boolean value always being true - although you won't normally do anything with the boolean, you'd use a foreach loop to iterate over the keys. You can assign a plural constant to a variable declared as that type, but note that the value differs from a normal map in three important respects:
* Since the expression that generates it is syntactically a constant, the value has to be immutable. If you were allowed to change it in any way, those changes would appear in every future use of the same constant.
* There can be multiple instances of the same key - $ints[1,1,2,3,5,8] is perfectly valid, and will result in the value 1 appearing twice in a foreach loop.
* The keys will appear in the order you wrote them, rather than being sorted alphanumerically as maps usually do.

In addition to being used in a foreach loop, plural constants also efficiently support membership testing via the 'contains' operator. Here's another example:
Code:
for hour from 1 to 12 {
	print("It's " + hour + " o'clock.");
	if ($ints[10, 2, 4] contains hour) {
		print("Time to drink a Dr Pepper!");
	}
}
(Yes, that example could just as easily have been done with a switch statement.)

Iterating over an empty list is rather pointless, so plural constants with no elements are given a different meaning: they represent every value of the specified type, where this is practical. (The 'none' value, if defined for a given type, is omitted.) The biggest benefit here is $items[], which lets you loop over every defined item, more efficiently than you could otherwise write in a script (since the list is generated once per session and then cached), and without having to hard-code a maximum item ID number in your script. Example:
Code:
foreach it in $items[] {
	if (autosell_price(it) == 42) print(it);
}

Enumeration of all possible values works with the following types:
* $booleans[] - false and true.
* $items[]
* $locations[]
* $classes[]
* $stats[] - Muscle, Mysticality, Moxie: the substat values are omitted.
* $skills[]
* $effects[]
* $familiars[]
* $slots[] - includes sticker slots and fake hands, which you might not want to consider as normal slots.
* $monsters[]
* $elements[] - includes slime now, and possibly other not-quite-elements like cute in the future.

The remaining types that can be used in plural constants require an explicit list of elements, since there are too many possible values:
* $ints[] - you don't have enough RAM to store a list with 4 billion elements.
* $floats[] - ditto.
* $strings[] - nobody has that much RAM.

Trivia: here are some KoL details that can now be easily determined.
> ash count($items[])

Returned: 4003

> ash count($locations[])

Returned: 196

> ash count($skills[])

Returned: 238

> ash count($monsters[])

Returned: 649
(but note that these counts include some historical locations and monsters that probably no longer exist.)
 
Last edited:

Bale

Minion
There's a script I'm working on right now where it was annoying that I didn't have this feature. Excuse me while I go replace my work-around with plural typed constants. This does make my life happier.
 
Last edited:

Bale

Minion
It's a shame I can't do this

Code:
have_equipped($items[beer helmet, distressed denim pants, bejeweled pledge pin])

to return true if I have the entire outfit equipped, since there is no command to test if you are currently wearing an outfit. But at least I can do this:

Code:
boolean frat_warrior() {
	foreach gear in $items[beer helmet, distressed denim pants, bejeweled pledge pin]
		if(!have_equipped(gear))
			return false;
	return true;
}

PS. You seem to have forgotten to add the constant $zodiacs
 
Last edited:

jasonharper

Developer
You can tell what (standard) outfit you're wearing via string_modifier("Outfit").

There is no ASH zodiac type, and therefore no $zodiac[...] constants, and therefore no possibility of a $zodiacs[] list. How often do you care about the exact sign, beyond what you can already determine via in_muscle_sign(), etc.?
 

Bale

Minion
Well, I've never actually used $zodiac constants, but I assumed that there was an ASH zodiac type because of this.

Thanks for the info on the string_modifier(). I overlooked that amidst the rest of your modifier maximizer updates.
 

Veracity

Developer
Staff member
Huh. I recently put back put_closet_meat() and get_closet_meat(). It looks like I should use polymorphism and just make them put_closet() and get_closet() and depend on int vs. item as argument to decide which one you get.

Tomorrow. :)
 

Bale

Minion
Could we have variables containing a plural typed constant? It would be nice if I could do this...

Code:
[COLOR="Red"]strings players = $string[player1, player2, player3];[/COLOR]

void main() {
	string [string] vars;
	file_to_map("vars_.txt",vars);

	if(vars["daily"] != today_to_string()) {
		foreach p in [COLOR="#ff0000"][B]players[/B][/COLOR]
			vars[p] = "false";
		vars["daily"] = today_to_string();
		map_to_file(vars,"vars_.txt");
	}
	foreach p in [COLOR="Red"][B]players[/B][/COLOR]
	if(!to_boolean(vars[p])) {
		string player_function = replace_string(p, " ", "_");
		call player_function();
		vars[p] = "true";
		map_to_file(vars,"vars_.txt");
	}
}
That way I'd only have to define my list of constants once to be able to reference it as many times as I want instead of having to be careful to change it separately each time it would be referenced.

I'm trying to make a multiple character automator for a friend which can be easily maintained despite her lack of ability at ash programing. It would be nice if she could add another character by adding that character's name in a single place. That way I can just keep all the stuff she doesn't understand at the bottom where it can quietly do the task of making sure that each character is only automated once in case she has to abort the script and restart it later.
 
Last edited:

Bale

Minion
Code:
boolean [slot] acc;
	acc[$slot[acc1]] = false;
	acc[$slot[acc2]] = false;
	acc[$slot[acc3]] = false;
remove acc[$slot[acc1]];
This works just fine. However, the following code does not work:

Code:
boolean [slot] acc = $slots[acc1, acc2, acc3]; 
remove acc[$slot[acc1]];

[COLOR="Red"]Cannot modify constant value (Universal_recovery.ash, line 403)[/COLOR]
I thought that I could save a few lines there. Is this a bug or a necessary part of the feature?
 

jasonharper

Developer
Necessary part of the feature. The plural constant's value is generated once, when the script is loaded. If you were allowed to modify it in any way, those modifications would be present in every subsequent use of the same constant. Assuming that your code was inside a loop (or in a function called multiple times), and that you removed a different slot in different cases, the value would eventually become empty.
 

StDoodle

Minion
Ok, again, I don't know what I'm doing... but what's the correct way to specify an entry for "$strings" where the string itself includes a comma? Do all such entries need to be saved in their own variable first?

/me is confused...

Wouldn't it probably be easier if you assigned a plural type of string with:
Code:
boolean [string] = $strings["words","morewords"];
Instead of:
Code:
boolean [string] = $strings[words,morewords];
Or am I just utterly confused?
 

jasonharper

Developer
You can put a comma in a $strings[] constant the same way you'd put a closing bracket, or a quote mark in a normal string constant: precede it with a backslash.
 
I need some help. What is wrong with the following syntax:

Code:
slot test = $slot[weapon];
boolean[slot] constant = $slots[test];
returns - Bad slot value: "test"

Does this have to do with it being immutable? I don't want to change the constants value, I just want to create a plural-typed constant from some existing variables. Is this possible?
 

StDoodle

Minion
You can't directly build a plural using variables as the data; you can do
PHP:
boolean [slot] constant = $slots[weapon];
, or you could do
PHP:
slot test = $slot[weapon];
boolean [slot] constant;
constant[test] = true;
but that's it.
 
This seems as appropriate place as any to ask.
What I'm trying to do is get a random item from all the possible items.

Problem is, at any given point in time, I don't know how many item numbers are skipped.

So
Code:
item rItem=random(count($items[])).to_item();
Is short of the maximum (currently by ~170).

Is there some quick or painless method to get the last item in $items[] (assuming they are stored by number)

Also, everything I just said, but for all the other KoL-specific types that change with content.
 
Top