scmJS docs

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.

scmJS 0.8.5 · Generated from the repository. The source is under the MIT license, which does not cover what ATTRIBUTION.md lists. StarCraft and Brood War are trademarks of Blizzard Entertainment; this project ships none of their data.