Looping Over a List
Before this: Counting Loops
Next steps: Looping Over a Map, Ready Check, Persistent Players, Testing, Rotations
Parts that use this: Healing Zone
A for loop can walk through an array, one element per iteration, and
break can stop it as soon as it finds what it is looking for. This lesson
keeps a list of dice rolls and searches it.
Contents
button1 Held -> chip roll
button2 Held -> chip search
chip text -> decal Text
Code
@left in roll: exec
@left in search: exec
var rolls: int[]
var shown: string = "No rolls yet"
@right out text = shown.Value
on roll {
rolls.push(Random(1, 6))
shown = "${rolls.length()} rolls"
}
on search {
var place: int = 0
var found: int = 0
for r in rolls {
place += 1
if r == 6 {
found = place
break
}
}
if found > 0 {
shown = "First six: roll ${found}"
} else {
shown = "No six in ${rolls.length()} rolls"
}
}
for r in rolls { ... }runs its block once for each element ofrolls, first to last, withrholding that element. An empty array runs it zero times.placecounts the iterations, so it says which roll is being looked at.breakstops the loop at once. The handler carries on after the loop, withfoundholding the place of the first six.foundstays 0 when no roll was a six, and the sign says so.
Say the rolls so far are 4, 6, 2 and 6. Which roll does the search report? How many iterations run?
Run
- Compile the chip and paste it in-game. Place two Buttons and a brick with a Text Decal.
- Wire the Buttons’ Held outputs to
rollandsearch, andtextto the Text Decal’s Text. - Roll a few times, then search. Also search before any six comes up. The sign then says how many rolls had no six.
Under the Hood
Open the chip. The loop is a For Each Array microchip. Its Array Var
Ref input is wired from the rolls Array Var, and it runs once per
element.
Inside, the For Each Array Entry gate has three outputs: Body starts
each iteration, Value is r, and Index is the element’s position
(Index and Value uses it). After them come an
Increment Variable for place, an Equal, a Branch, the write to
found, and a Break gate at the end of the chain. When an iteration reaches Break, the loop ends and the For Each
Array’s Completed output fires.
The loop reads the array straight from its gate, so there is no Get Array Element in the chip.
There is no continue to skip the rest of one iteration:
@left in search: exec
var rolls: int[]
var sixes: int = 0
on search {
for r in rolls {
if r != 6 { continue }
sixes += 1
}
}
Error: [WS078] `continue` does not exist in this language, and there is no gate a loop plane could lower it to. Restructure the rest of the body under an `if`.
Put the rest of the iteration under an if instead: if r == 6 { sixes += 1 }.
Modify
-
Show the total of all rolls. In the
rollhandler, after the push, add a loop with nobreak:@left in roll: exec var rolls: int[] var shown: string = "No rolls yet" @right out text = shown.Value on roll { rolls.push(Random(1, 6)) var total: int = 0 for r in rolls { total += r } shown = "${rolls.length()} rolls, total ${total}" } -
Count the sixes instead of finding the first one: drop the
break, and add one to asixesvariable each timer == 6. -
Search for any number. Add a third button that steps a
targetvariable through 1 to 6 (target = target % 6 + 1), show it on the sign, and search fortargetinstead of 6.
Make
Make a streak finder. After every roll, search the list for two sixes in a
row, and light a Point Light when there are. Keep the previous element in
a variable declared before the loop, and compare it with r.
button Held -> chip roll
chip streak -> light Enabled
Good to Know
- A loop over an empty array runs zero times and goes straight to the code after it. Plan for “nothing found”.
breakends the whole loop, not only the current iteration. Nothing after thebreakin the block runs.- A read like
rolls[i]past the end of the array gives a stale value, butfor r in rollsvisits only the elements that are there, so it never reads past the end. - When the test is plain equality, an array can answer in one gate.
rolls.find(6).Indexis the index of the first 6 (-1when there is none), androlls.sum()is the total. A loop is for tests one gate cannot do, such as the streak in Make.
See break in the reference.
Next: Looping Over a Map.