# Loops

## How loops work

Experiments done with infants and toddlers usually consist of a series of trials, in which the stimuli used or side of presentation may vary from trial to trial, but the core structure of every trial is the same. Rather than writing a long protocol file that separately specifies every trial with a unique set of steps, you can specify the trial structure once, then use a **loop** to repeat it.

A **LOOP statement** will cause the steps in between the specified step number and the step in which the `LOOP` statement is defined to be executed. This occurs repeatedly, until the loop statement's terminating conditions have been satisfied.

```
LOOP STEP <number>
UNTIL <terminating condition>
```

The following example is the entire test phase of a preferential looking study with trials shown in a fixed order. The entire study runs via looping over a set of 3 steps that comprise an attention getter and a trial.

```
STEP 1
Phase Test Start

STEP 2
VIDEO CENTER attentiongetter LOOP
UNTIL KEY X

STEP 3
VIDEO CENTER OFF

STEP 4
Trial Start
LET trial_stim = (TAKE stim_list FIRST)
VIDEO CENTER trial_stim ONCE
UNTIL FINISHED

STEP 5
Trial End
LOOP STEP 2
UNTIL 23 TIMES

STEP 6
Phase End
```

When running the protocol, we begin, as always, at `STEP 1`. The test phase starts, and the first attention getter video plays until the experimenter indicates the participant is ready for a trial.   The first trial stimulus is chosen from the list of stimuli, displayed, and played to the end. The **loop step** (the step that contains the `LOOP` statement) is `STEP 5`. When it is reached, execution jumps back to `STEP 2`, and proceeds again through steps 3 and 4, and onto 5. Upon reaching the `LOOP` statement again, it again jumps back to 2, and proceeds through the steps. This repeats a total of 23 times, displaying a total of 24 attention-getters and trials (the one original execution of steps 2-4, _plus_ the 23 times it looped over that sequence.)

Loops can be **nested** within each other, allowing for concise specification of experiments with a block structure. Below is the test phase of a headturn preference study that consists of 3 blocks. Each block is comprised of 4 trials, for a total of 12 trials. Before each trial, the participant is oriented to a neutral position (center), and then the trial begins once they reorient in the direction where the light has begun flashing and from which the audio will play.

```
...
STEP 9
Phase Test Start

STEP 10
LET thisblock = (TAKE testblocks FIRST)

STEP 11
LIGHT CENTER BLINK 200
UNTIL KEY C

STEP 12
LIGHT CENTER OFF

STEP 13
LET side1 = (FROM testsides RANDOM {with max 2 repeats in succession})
LIGHT side1 BLINK 200
UNTIL KEY L
UNTIL KEY R

STEP 14
Trial Start
LET trialaudio = (TAKE thisblock RANDOM)
AUDIO side1 trialaudio ONCE
UNTIL FINISHED
UNTIL SINGLELOOKAWAY trialaudio GREATERTHAN 2000

STEP 15
Trial End
AUDIO side1 OFF
LIGHT side1 OFF

STEP 16
LOOP STEP 11
UNTIL 3 TIMES

STEP 17
LOOP STEP 10
UNTIL 2 TIMES

STEP 18
Phase End
```

Steps 11-15 specify a sequence of centering the participant and playing a trial, which is a unit that repeats throughout the experiment. These steps are looped over in `STEP 16`, which specifies to execute this sequence three additional times so that the first block contains four trials. Once the first block is finished, the `LOOP` statement in `STEP 17` is reached, which has it jump back to `STEP 10` to select the next block of stimuli to present. The inner loop in `STEP 16` is executed just as before, playing the four trials in this block also. `STEP 17` is reached again, and execution jumps back to `STEP 10` to select the third block, and the nested loops work in the same way to play four trials here. Now that `STEP 17` has had its loop repeated the required two times, we move to `STEP 18` and the phase ends.

{% hint style="warning" %}
Be careful with trial/phase start and stop flags, in relation to where loops are placed. In the above example, `STEP 9` contains only the flag to start the test phase, and we loop to `STEP 10` to repeat a block. If we had started the test phase in the step that was looped to, we would repeat it at every block - and we want the phase to only start once. Therefore, it should be outside the loop.
{% endhint %}

## Loop terminating conditions

Just like [step terminating conditions](step-terminating-conditions), loop terminating conditions can be combined together for more complex end conditions. They can be joined by an AND, such that both conditions must be met:

```
LOOP STEP <number>
UNTIL <terminating condition 1> and <terminating condition 2>
```

Or by an OR, such that only one condition need be met before ending the loop.

```
LOOP STEP <number>
UNTIL <terminating condition 1>
UNTIL <terminating condition 2>
```

### TIMES looped

```
LOOP STEP <number>
UNTIL <number> TIMES
```

This loops back to the specified step, executes all the intervening steps in order, and loops again until it has completed the entire loop the specified number of times. For example,

```
STEP 1
LET dog = (TAKE dogs RANDOM)
IMAGE CENTER dog
UNTIL 5000

STEP 2
LOOP STEP 1
UNTIL 5 TIMES
```

The above loop would execute `STEP 1` five times, in addition to the first execution before the loop step was reached. Therefore, we would select and display an image from the group `dogs` a total of 6 times.

### EMPTY

Rather than specifying a set number of times to loop, you can also loop until a particular group has no remaining options for selection.

```
LOOP STEP <number>
UNTIL <group tag> EMPTY
```

For example,&#x20;

```
LET dogs = {dalmatian, deerhound, boxer, bulldog, beagle, whippet}

STEP 1
LET dog = (TAKE dogs RANDOM)
IMAGE CENTER dog
UNTIL 5000

STEP 2
LOOP STEP 1
UNTIL dogs EMPTY
```

The above loop would run until all the tags in `dogs` have been marked as selected, and none are eligible to be chosen by the `TAKE` statement - in this case, the loop would repeat 5 times, in addition to the first selection, for a total of 6 items displayed.

### TIME elapsed

It is also possible to execute a loop until _at least_ a certain amount of time has elapsed since the looping began.

```
LOOP STEP <number>
UNTIL TIME <time in milliseconds>
```

```
STEP 1
LET dog = (FROM dogs RANDOM)
IMAGE CENTER dog
UNTIL 5000

STEP 2
LOOP STEP 1
UNTIL TIME 55000
```

In the above example, images are selected randomly (with replacement) and displayed for 5 seconds each, with the section looped for a total of 55 seconds. Importantly, the timer for the loop begins when the  `UNTIL` statement is reached for the first time - which is after the first tag from `dogs` is selected and displayed for 5 seconds. Therefore, images of dogs are displayed for a total of 60 seconds.

Like all loop termination conditions, `UNTIL TIME` conditions are only evaluated when execution reaches the loop step (`STEP 2`, in the above example) again. If the specified time is met in the middle of a loop sequence, the current run of the loop will be allowed to finish before the terminating condition is met and execution continues to later steps in the protocol file.

{% hint style="info" %}
As an illustration of the above point: If each image in the example above were shown for 6 seconds rather than 5, the 55-second timer would be met 1 second into displaying the 10th image (9th from within the loop). This last image would continue to be displayed for its full 6 seconds, _then_ the timer would be checked upon reaching `STEP 2`. Therefore we would be displaying images for a total of 66 seconds (6 from the initial execution of `STEP 1` + 55 seconds of the loop + 5 seconds to finish the in-progress loop sequence).
{% endhint %}

### KEY

As of BITTSy version 1.33, you can also loop until a particular key is currently active.

```
LOOP STEP <number>
UNTIL KEY <key>
```

It is important again to note that loop terminating conditions are evaluated only when execution reaches the loop step. Therefore, if the loop was set to run `UNTIL KEY X`, and the experimenter pressed X followed by another key while the loop was still executing, the loop would not end: when the terminating condition was checked, some other key was the most recent key.

This terminating condition is useful in cases in which you wish to use a loop to run through a set of trials until an experimenter makes some judgment that the child is "done." For example, this could be used for an experimenter to end a phase if some more desirable terminating condition (e.g. accumulated looking time) cannot be met, while still allowing the child to continue to participate in the subsequent parts of a study. It can also be used for studies in which the variable of interest is how many trials are shown before the child makes some overt behavioral response, such as imitating a person on a screen, pointing, or saying an answer.

### Looking-controlled end conditions

Often we want to repeat the presentation of a stimulus or set of stimuli until the child has reached a particular level of attention toward the stimuli - either they've looked a set amount, or they've reached a particular point of boredom or inattention. This can be achieved by setting up these trials within a loop, and looping until some looking-controlled end condition is met.

#### TOTALLOOK

```
LOOP STEP <number>
UNTIL TOTALLOOK <tag> GREATERTHAN <time in milliseconds> THIS PHASE
```

This loop terminating condition is met when the time a participant spends looking toward a tag, totaled across all its presentations in a given [phase](../phases-trials-and-steps#phases) of the experiment, meets the given threshold.

```
LOOP STEP 2
UNTIL TOTALLOOK trainingmusic1 GREATERTHAN 25000 THIS PHASE and TOTALLOOK trainingmusic2 GREATERTHAN 25000 THIS PHASE
```

The example above is a common one used in [HPP studies](../goals-and-capabilities/paradigms/the-headturn-preference-procedure), where two training stimuli alternate until both reach a fixed criterion. But this has at times been criticized because if one of the two music files reaches criterion and the other does not, it will continue to loop - and the loop could mean that it keeps playing the stimulus that had already reached criterion, rather than the one that still needed to do so. This could result in OVER familiarizing one of the two stimuli (or habituating to it) before the other one reaches criterion. This can be solved with `JUMP` statements - see [the example here](../jump#presenting-an-event-based-on-accumulated-looking-time) for a solution to this exact problem.

#### TOTALLLOOKAWAY

```
LOOP STEP <number>
UNTIL TOTALLOOKAWAY <tag> GREATERTHAN <time in millseconds> THIS PHASE
```

This works identically to `TOTALLOOK`, but rather than totaling up time when an experimenter indicated the participant was looking at the given tag as it was presented, uses the time spent _not_ looking toward the tag. Time when the tag was not active (not being displayed/played) does not count as time looking away from that tag; only time when the child _could_ have been looking at it but was recorded as looking some other way (with any key that was not assigned to the tag's current side) is counted.

#### CRITERIONMET

```
LOOP STEP <number>
UNTIL CRITERIONMET
```

See the section on [habituation](habituation/meeting-a-criterion) for more about the `CRITERIONMET` condition.
