Tables, maps and sets
Lists the script made#
A list the script made is a table a program can look things up in.
const price = [50, 100, 150] above the program and price[level] inside it is in the
map once, however often it is read, and cannot be written. A list of records is a table
per field, which is how a wave table works:
const waves = [
{ unit: units.ZergZergling, count: 4 },
{ unit: units.ZergHydralisk, count: 3 },
];
program(() => {
let wave = 0;
while (wave < waves.length) {
createUnit(P2, waves[wave].unit, waves[wave].count, locations.Spawn);
wave += 1;
sleep(seconds(30));
}
});
Tables keyed by an id of the game#
A table keyed by a unit type, a player, a location, a switch, a weapon, an upgrade or a technology has a cell for every id, so looking up a key is one read:
const bounty: Record<UnitType, number> = { [units.ZergZergling]: 5, [units.ZergHydralisk]: 15 };
program(() => {
const score: Record<Player, number> = { [P1]: 0 };
const lost = new Map<UnitType, number>();
const seen = new Set<UnitType>();
for (const u of unitsOf(P2)) {
if (u.hp < 10) {
score[u.owner] += bounty[u.type];
lost.set(u.type, (lost.get(u.type) ?? 0) + 1);
seen.add(u.type);
u.kill();
}
}
});
A Record is read and written by its keys and reads 0 where nothing was stored. A Map
has get (?? d for a key never set), set, has, delete, clear and size; a
Set has add, has, delete, clear and size. for (const [key, value] of lost),
lost.keys() and lost.values() go through the keys that are there, in the order of the
ids. A table made inside the program can be written while the map is played. One made
outside it belongs to the script, and a program only reads it. A Map keyed by a few
texts the script knows, new Map<"red" | "blue", number>(), is kept the same way.
A Map and a Set over any number#
For keys that are no id of the game (a tile packed into one number, a score), use
new Map<number, number>(), new Map<number, boolean>() or new Set<number>(), empty or
with what they start with: new Map([[1, 10], [k, 20]]).
program(() => {
const owner = new Map<number, number>(); // a tile, as x + y * 256, to who holds it
const claimed = new Set<number>();
for (const u of unitsOf(P1, { type: units.TerranMarine })) {
const tile = (u.x >> 5) + (u.y >> 5) * 256;
if (!claimed.has(tile)) { claimed.add(tile); owner.set(tile, 1); }
}
for (const [tile, who] of owner) if (who == 1) print(`tile ${tile % 256}, ${tile >> 8}`);
});
They go through their keys in the order the keys went in, as JavaScript's do: a key
set again stays where it was, and one deleted and set again goes to the end. Finding a key
takes a few steps, where a table keyed by ids of the game is one read, so when the keys
are ids of the game, say so (Map<UnitType, number>). The table lives in the pool the
growing arrays share: it starts at eight slots and doubles as it fills. Values are
numbers, booleans or instances of a class. For a text or a record, keep the place of a row
of an array of records.
Keyed by units#
new Map<Unit, number>() and new Set<Unit>() work the same way: a cooldown per unit, or
the units already dealt with. A unit made where a dead one was is not the dead one's
key. A unit that died stays an entry until it is deleted. In a loop over the table it
reads as no unit, which is the moment to delete it.