Maps
Before this: Lists
Next steps: Looping Over a Map, Ready Check, Per-Player State
Parts that use this: Welcome Zone, Teleporter Pad, Item Dispenser, Keycard Door, Checkpoints, Shop
A list finds a value by its slot number. Often what you know is something else: which player walked in, or which team scored. A map files each value under a key you choose, like a phone number filed under a name in an address book. Give it the key and it gives back the value.
Contents
zone "Zone Ref" -> chip room
Code
import { escape } from "sanitize"
@left in room: zone
var visits: Map<string, int>
on ZoneEntered(zone = room) -> (character) {
let id = character.GetUserId()
let before = visits.get(id)
let count = if before.Found then before.Value + 1 else 1
visits.set(id, count)
character.ShowChatMessage("Visit number ${count}, ${escape(character.GetDisplayName())}")
}
Map<string, int>is a map withstringkeys andintvalues. The first type in the<>is the key, the second is the value.character.GetUserId()is the player’s user id, a string that stays the same for that player on every visit. It is the key.visits.get(id)looks the key up and gives two things:.Found, whether the key was there at all, and.Value, the value filed under it.if before.Found then before.Value + 1 else 1picks one of two values: one more than the old count if the player has been here before, 1 if not.visits.set(id, count)files the new count under the id, replacing any old one.escape(...)makes a name the player chose safe to show in chat.
You walk into the zone three times, then a friend walks in for the first time. What does the friend’s message say?
Run
- Compile the chip and paste it in-game. Give a brick an Attached Zone.
- Wire the Attached Zone’s Zone Ref to
room. - Walk in and out a few times. Each visit, you get a chat message with your count. A second player gets their own count, starting at 1.
Under the Hood
Open the chip. visits is one Map Var gate, and it stays one gate however
many players it holds. Its Map Var Ref output is wired into each gate that
reads or writes the map.
The handler is a chain. Get User Id turns the character into an id. Get Map Element looks the id up, and Set Map Element files the new count. Both take their Key from the same Get User Id. Between them, an Add works out one more than the old count, and a Select picks it when the Found output is true, or 1 when it is false. The message is a Get User Display Name, a Replace in String for the escape, a Format String and a Show Chat Message. That is eleven gates, plus the zone pin.
Like an array, a map has no pure gate that reads it. Every map gate has an exec input, so a read outside a handler is an error:
var visits: Map<string, int>
@right out first = visits.get("a").Value
Error: [WS007] map read 'visits.get(...)' outside an exec context
To show something from a map on a sign, copy it into a var inside the
handler, and wire the sign from that.
Keys can be int, string, a reference to a thing in the world, or a
brick. Anything else is an error:
var heights: Map<float, int>
Error: [WS039] map key type must be int, string, an object (entity/character/controller) or a brick, got float
Modify
-
Show how many different players have visited. Add
var players: int = 0, and at the end of the handler setplayers = visits.length().length()gives the number of keys. Wire@right out sign = "${players.Value} players have visited"to a Text Decal. -
Add a second zone that makes the chip forget you.
hasasks only whether a key is there, andremovetakes a key and its value out:@left in room: zone @left in forget: zone var visits: Map<string, int> on ZoneEntered(zone = room) -> (character) { let id = character.GetUserId() let before = visits.get(id) let count = if before.Found then before.Value + 1 else 1 visits.set(id, count) character.ShowChatMessage("Visit number ${count}") } on ZoneEntered(zone = forget) -> (character) { let id = character.GetUserId() if visits.has(id) { visits.remove(id) character.ShowChatMessage("Forgotten.") } else { character.ShowChatMessage("I don't know you yet.") } }After the forget zone, your next visit is number 1 again.
-
Give prizes on some visits. The keys of a map do not have to be players: this one is keyed by the visit number, and only three numbers have a prize. A list would need a slot for every number in between.
@left in room: zone var visits: Map<string, int> var prizes: Map<int, string> = { 1 => "a sticker", 5 => "a hat", 10 => "a crown" } on ZoneEntered(zone = room) -> (character) { let id = character.GetUserId() let before = visits.get(id) let count = if before.Found then before.Value + 1 else 1 visits.set(id, count) let prize = prizes.get(count) if prize.Found { character.ShowChatMessage("Visit ${count}: you win ${prize.Value}!") } }{ 1 => "a sticker", ... }fills the map when you compile. Eachkey => valuepair is one entry, and the entries are stored in the Map Var gate itself, so they cost no extra gates.
Make
Make a lap counter. Walking into a finish zone adds a lap for that player and tells them their lap count. On their third lap they get “You finished!” and their entry is removed, so they can race again from lap 1. A sign shows how many players are racing right now.
zone "Zone Ref" -> chip finish
chip text -> decal Text
Good to Know
- A map starts empty unless its declaration lists constant keys and values.
- A map holds one value per key.
seton a key that is already there replaces its value. - For a key that might be missing, check
.Foundorhas()rather than counting on what.Valueholds. - Every
getis its own gate and its own read. To use one read twice, bind it to alet, asbeforeis above. - Key players by
GetUserId(), not by their character: a player who dies comes back as a new character. Per-Player State compares the keys you could pick and when each one starts over.
See Maps and Map Types in the reference.
Next: pick a lesson from the tree on the Learn page.