Lists and maps
Lists
A list (I call it an array) goes in square brackets. You read an item with parentheses, and positions start at 0.
scores = [10, 20, 30]
PRINT scores, LEN(scores)
PRINT scores(0), scores(2)
scores(1) = 25
PRINT scores
[10, 20, 30] 3
10 30
[10, 25, 30]
Yes, parentheses: scores(0). Square brackets only ever make a list.
Reaching past the end is an error:
scores = [10, 20, 30]
PRINT scores(3)
+ and - give you a new list. PUSH, POP, QUEUE and DEQUEUE change
the list itself.
scores = [10, 20]
PRINT scores + [30] // joined on
PRINT scores + 1 // one more empty place
PRINT scores // ...and scores is as it was
PUSH scores, 30 // onto the end
PRINT scores
PRINT POP(scores), scores // off the end
line = ["ada", "grace"]
QUEUE line, "linus" // onto the end
PRINT DEQUEUE(line), line // off the front
[10, 20, 30]
[10, 20, 0]
[10, 20]
[10, 20, 30]
30 [10, 20]
ada [grace, linus]
A piece of a list
Give a range where the position goes and you get a new list of those items — both ends included, as ranges always are. A range that counts down reads backwards.
scores = [10, 20, 30, 40, 50]
PRINT scores(1 ... 3)
PRINT scores(0 ... 1), scores(4 ... 0)
top = scores(3 ... 4)
PUSH top, 60 // a new list: scores isn't touched
PRINT top, scores
[20, 30, 40]
[10, 20] [50, 40, 30, 20, 10]
[40, 50, 60] [10, 20, 30, 40, 50]
Both ends have to be there. Asking for scores(3 ... 9) is an error, just as
scores(9) would be.
Lists in lists
Lists can hold lists. Reach in with one pair of parentheses.
grid = [[1, 2, 3], [4, 5, 6]]
PRINT grid(1, 2), grid(0)
6 [1, 2, 3]
Grids of numbers
A list of rows of numbers is a matrix. I’m built for games, and matrices
are how games turn, stretch and move things — so they get three operators of
their own: @*, @+ and @-. (Plain + on two lists joins them, remember.
The @ says “do the math instead”.)
a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
PRINT a @* b // each row on the left meets each column on the right
PRINT a @+ b, b @- a // part by part
PRINT a @* 2 // a number scales every part
PRINT a + b // ...and plain + still joins
[[19, 22], [43, 50]]
[[6, 8], [10, 12]] [[4, 4], [4, 4]]
[[2, 4], [6, 8]]
[[1, 2], [3, 4], [5, 6], [7, 8]]
Multiply a matrix by a coordinate and the coordinate goes through it. This one is a quarter turn:
turn = [[0, -1], [1, 0]]
ship = (3, 4)
PRINT turn @* ship
PRINT turn @* turn @* ship // two quarter turns: facing the other way
PRINT turn @* ((0, 0) -> (1, 0)) // a vector has both ends turned
(-4, 3)
(-3, -4)
(0, 0) -> (0, 1)
A matrix can’t move a point of its own size — that takes one more row and column. So when the matrix is one bigger than the coordinate, I treat the coordinate as having a 1 on the end, and take it off again afterwards. One 3 by 3 matrix can then turn, stretch and move a 2D point all at once.
// Twice the size, then 10 across and 20 down.
place = [[2, 0, 10],
[0, 2, 20],
[0, 0, 1]]
FOR corner = [(0, 0), (1, 0), (1, 1), (0, 1)]
PRINT corner, "goes to", place @* corner
END FOR
(0, 0) goes to (10, 20)
(1, 0) goes to (12, 20)
(1, 1) goes to (12, 22)
(0, 1) goes to (10, 22)
The sizes have to meet. If the left one isn’t as many across as the right one is down, I’ll stop and tell you both numbers.
PRINT [[1, 2], [3, 4]] @* [[1, 2, 3]]
From Python:
@*is NumPy’s@, with nothing to install, and@+and@-are what+and-do on its arrays.
From JavaScript and Lua: No library and no nested loops. It’s built in.
From BASIC:
MAT C = A * B, if you go back that far!
You can also ask for a list of a size, every item starting as its type starts. A coordinate for the size gives you rows.
slots = 3:INTEGER
names = 2:STRING
board = (2, 3):INTEGER
board(1, 2) = 7
PRINT slots, names, board
[0, 0, 0] [, ] [[0, 0, 0], [0, 0, 7]]
From BASIC:
DIM scores(10) AS INTEGERisscores = 10:INTEGER, and that’s 10 items, numbered 0 to 9.
From Python:
scores[1:4]isscores(1 ... 3): the end is included. There are no negative positions, and a slice past the end is an error.
From JavaScript: Reading past the end is an error, where you’d get
undefined.scores.slice(1, 4)isscores(1 ... 3).
From Lua: Positions start at 0. I know. I’m sorry.
Maps
A map goes in braces: names and their values. It’s JSON, so you can paste JSON straight in.
player = {
name: "Ada",
hp: 100,
items: ["sword", "map"],
home: {x: 3, y: 4},
}
PRINT player.name, player.items(0), player.home.x
player.hp = player.hp - 10
player.level = 2 // a new key is made by giving it a value
PRINT player
PRINT player.missing // a key that isn't there is NULL
Ada sword 3
{home: {x: 3, y: 4}, hp: 90, items: [sword, map], level: 2, name: Ada}
NULL
Read a key with a dot when you know its name, and with parentheses when the name is in a variable or isn’t a plain word.
key = "hp"
stats = {hp: 100, "top speed": 12, (key + "_max"): 150}
PRINT stats(key), stats("top speed"), stats.hp_max
100 12 150
From Python: A bare key is its own name:
{hp: 100}has the key"hp". For a key from a variable, wrap it in parentheses:{(key): 100}.
From JavaScript: Just like your object literals, with
(key)where you’d write[key].
From Lua:
{hp = 100}is{hp: 100}. Your one table is two things here: a list and a map.
One list, many names
A list or a map is one thing with possibly many names. Give it to another variable and both names mean the same list.
mine = [1, 2]
yours = mine
PUSH yours, 3
PRINT mine // the same list, so it changed too
copy = mine + [] // + always makes a new one
PUSH copy, 4
PRINT mine, copy
[1, 2, 3]
[1, 2, 3] [1, 2, 3, 4]
Numbers, text and coordinates are plain values: each variable has its own.