Doing Multiple Things at Once
Tags: miniscript, minimicro, programming, beginners
Published: 2023-05-13 02:16:45


This post is inspired by a real-life (or at least, school-life) problem encountered by my son in his engineering class.  His group's task was to write a program to sort balls in a Vex Robotics machine.  They had a routine which controlled the motor to send one ball at a time down the ramp.  And they had a routine which could use the sensor to check the color of a ball and kick it into the correct path.

But they were stumped on _how to do both at once_.  If they called the motor routine, by the time it returned, the ball had already rolled past the sensor.  And if they programmed the sensor to just wait for a ball to appear, none would ever appear because the motor routine wasn't running.

This is a very common problem in programming: how do you make a computer do multiple things at once?  Despite fancy video cards and multi-core machines, in most ordinary programming, the computer is essentially a _serial_ processor: it does one thing at a time.  Indeed, when running a program, the computer steps through your code, step by step; it's always at exactly one point in your program, not two or more places.  So how can it possibly being doing more than one thing at a time?

The secret: it doesn't.  **A computer program only does one thing at a time.** But you can make it _look_ like it's doing multiple things at once, by switching between them very fast.

Let's illustrate with an example in [Mini Micro](https://miniscript.org/MiniMicro/).

## The Setup

First, suppose we have a program to make a heart that beats once per second:

```miniscript
clear
heart = new Sprite
heart.image = file.loadImage("/sys/pics/Heart.png")
heart.x = 800
heart.y = 400
display(4).sprites.push heart

// Make the heart beat.
updateHeart = function
	heart.scale = 1.2
	wait 0.3
	heart.scale = 1
	wait 0.7
end function

// main loop
while true
	updateHeart
end while
```

Simple enough, right?  We even have an "update" function that's called by a "main loop," because we've heard this is good program design and should save us grief later.  When run, this program produces a display like we wanted:

![Heart beating once per second](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xb9km12kzktsnr4tpzc0.gif)

Now, separately, we write a program to make a wumpus jump:

```miniscript
clear
wumpus = new Sprite
wumpus.image = file.loadImage("/sys/pics/Wumpus.png")
wumpus.x = 300
wumpus.y = 100
display(4).sprites.push wumpus

// Make the wumpus jump
updateWumpus = function
	dy = 30
	while true
		wumpus.y = wumpus.y + dy
		if wumpus.y < 100 then break
		dy = dy - 1
		yield
	end while
	wumpus.y = 100
end function

// main loop
while true
	updateWumpus
end while
```

Again we have an "update" method called from a main loop.  And when run, the wumpus correctly jumps over and over.

![Jumping Wumpus](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sx20k2c1k6lvg5geqxx6.gif)

But now, how can we do both of these things at once?  We want the wumpus to jump continously, while the heart also beats once per second, all at the same time.  This is like my son's school challenge, where they needed to control the motor and the check the sensor at the same time; or like any video game, where you have lots of sprites moving around and doing their own thing, including the one controlled by the player.

## A First Try

So, what to do?  A first try might be to simply call both update functions from the main loop.

```miniscript
clear
heart = new Sprite
heart.image = file.loadImage("/sys/pics/Heart.png")
heart.x = 800
heart.y = 400
display(4).sprites.push heart

wumpus = new Sprite
wumpus.image = file.loadImage("/sys/pics/Wumpus.png")
wumpus.x = 300
wumpus.y = 100
display(4).sprites.push wumpus

// Make the heart beat.
updateHeart = function
	heart.scale = 1.2
	wait 0.3
	heart.scale = 1
	wait 0.7
end function

// Make the wumpus jump
updateWumpus = function
	dy = 30
	while true
		wumpus.y = wumpus.y + dy
		if wumpus.y < 100 then break
		dy = dy - 1
		yield
	end while
	wumpus.y = 100
end function

// main loop
while true
	updateHeart
	updateWumpus
end while
```

The trouble with this is, it doesn't update the heart and the wumpus at the same time.  First, the heart beats, which takes about a second; and then the wumpus jumps, which takes several more seconds.  Then the heart beats again, and then the wumpus jumps.  They're taking turns.

![Wumpus jumps, then heart beats, and repeat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtep4zqzh8z6e5s9snd6.gif)

## The Correct Approach

To fix this, we need to think differently about our "update" functions.  In almost all cases, an update function needs to **return very quickly, whether its task is "done" or not**.

So let's consider each of our update methods one at a time, starting with the wumpus.  This one is fairly easy, because it already contains an internal `while` loop that we can unpack.  Instead of doing the whole loop, our new and improved `updateWumpus` function will do just _one_ step of that loop.  The only tricky part is `dy`, which was a local variable before; now it needs to stick around between update calls, so we'll make it a global.

```miniscript
// Update the wumpus to continue its jump
dy = 30
updateWumpus = function
	wumpus.y = wumpus.y + dy
	if wumpus.y < 100 then
		wumpus.y = 100
		globals.dy = 30
	end if
	globals.dy = dy - 1
end function
```

If we replace `updateWumpus` in the previous listing with this one, at first it seems worse: the wumpus is now moving in very jittery fashion, taking one step per beat of the heart.  It's painfully slow because its update rate now depends on how fast `updateHeart` returns, and that one is still taking a full second on every call.

![Wumpus updates only once per second, with each heart beat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vfr0bjndwpeqnj4qbrm.gif)

So let's tackle that one next.  This one is a little trickier because it involves `wait` calls, and that's simply a no-no in an update routine.  Update methods need to return as quickly as possible so other parts of the program can do their thing.  So instead of waiting, you check the `time`, and use that to know when to do your next step.  In this case, we want the heart to be scale 1.2 for 0.3 seconds, and scale 1 for 0.7 seconds, so we can write it like this:

```miniscript
// Update the heart to beat every second
nextHeartTime = 0
updateHeart = function
	if time < nextHeartTime then return  // not time yet!
	if heart.scale == 1 then
		heart.scale = 1.2
		globals.nextHeartTime = time + 0.3
	else
		heart.scale = 1
		globals.nextHeartTime = time + 0.7
	end if
end function
```

Note that we again need a variable that lives outside the method to keep track of state; in this case, that is `nextHeartTime`, which is the time at which the heart should next change its size.  When [`time`](https://miniscript.org/wiki/Time) exceeds that value, we change the scale of the heart, and update `nextHeartTime` accordingly.

There is one more change we need to make at this point: our original `updateWumpus` method contained a `yield` call, but we've refactored that away.  Now that everything in the main loop returns very quickly, it actually happens too fast!  We fix that by inserting a `yield` in our main loop, where it almost always belongs.  The final program looks like this:

```miniscript
clear
heart = new Sprite
heart.image = file.loadImage("/sys/pics/Heart.png")
heart.x = 800
heart.y = 400
display(4).sprites.push heart

wumpus = new Sprite
wumpus.image = file.loadImage("/sys/pics/Wumpus.png")
wumpus.x = 300
wumpus.y = 100
display(4).sprites.push wumpus

// Update the heart to beat every second
nextHeartTime = 0
updateHeart = function
	if time < nextHeartTime then return  // not time yet!
	if heart.scale == 1 then
		heart.scale = 1.2
		globals.nextHeartTime = time + 0.3
	else
		heart.scale = 1
		globals.nextHeartTime = time + 0.7
	end if
end function

// Update the wumpus to continue its jump
dy = 30
updateWumpus = function
	wumpus.y = wumpus.y + dy
	if wumpus.y < 100 then
		wumpus.y = 100
		globals.dy = 30
	end if
	globals.dy = dy - 1
end function

// main loop
while true
	updateHeart
	updateWumpus
	yield
end while
```

And when run, we can see that the wumpus is jumping, and the heart is doing a steady 60 beats per second, all at the same time.  Huzzah!

![Correct display: wumpus jumps and heart beats simultaneously](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghemy150vs05bqea8gw8.gif)

## Conclusion

The approach described here is the magic common to virtually all real-time programs.  Sure, some environments hide some of the details from you in one way or another, but at some level they're just doing something like this: calling a bunch of little update functions, each responsible for updating one part of the program.  And critically, these update functions need to return as quickly as possible, so they don't block any _other_ update functions.

Now that you know the secret, you'll be able to find it in many Mini Micro games, including built-in demos like **flappyBat**, **platformer**, **mochiBounce**, and more.  And you'll be able to apply it to your own games and programs, too.  Happy coding!