PICO-8 100 Doors Problem
By Michael Doornbos
- 3 minutes read - 533 wordsIntroduction
Second only to the 10PRINT problem is the 100 Doors problem.
We’ve done it on many platforms, but my favorite is still the first one I did it on, the VIC-20.
PICO-8
We need to do a little more work than just poking onto the screen for this one, but it’s still easy to follow.
Slow down
One problem you’ll have is that a PICO-8 system on a modern compter can run this faster than you can see it. That’s cool if you just want the results, but we’re looking for a cool visual to follow along with.
In this version, we’re using PICO-8’s built-in game loop to naturally pace the animation.
Let me explain.
PICO-8 automatically runs the _update()
function 30 times per second. Instead of using an explicit delay or sleep function, we’re leveraging this by processing just one door change per frame.
Here’s how it works:
function _update()
-- These variables persist between frames
if not pass then pass = 1 end
if not door then door = pass end
if pass <= 100 then
-- Only handle ONE door each time _update() is called
door_states[door] = not door_states[door]
-- Draw just this one door
local x = (door-1)%16*8 + 4
local y = flr((door-1)/16)*8 + 4
circfill(x, y, 3, door_states[door] and 12 or 7)
-- Move to next door for the next frame
door += pass
Each time _update()
runs (30 times per second):
- We only toggle and redraw ONE door
- We save where we are (which pass and door) for the next frame
- Then we wait until PICO-8 calls
_update()
again
If we wanted to slow it down even more, we could add a frame counter like this:
function _init()
frame_count = 0
end
function _update()
frame_count += 1
if frame_count % 2 == 0 then -- Only process a door every other frame
-- rest of the code
end
end
Make sense?
The code
function _init()
-- Clear screen
cls()
-- Initialize door states table
door_states = {}
for i=1,100 do
door_states[i] = false -- all doors start closed
circfill((i-1)%16*8 + 4, flr((i-1)/16)*8 + 4, 3, 7)
end
end
function _update()
-- Static variable to keep track of progress
if not pass then pass = 1 end
if not door then door = pass end
-- Process one door per frame
if pass <= 100 then
-- Toggle door state in our table
door_states[door] = not door_states[door]
-- Draw the circle
local x = (door-1)%16*8 + 4
local y = flr((door-1)/16)*8 + 4
circfill(x, y, 3, door_states[door] and 12 or 7)
-- Move to next door
door += pass
-- Move to next pass if we're done with current one
if door > 100 then
pass += 1
if pass <= 100 then
door = pass
end
end
else
-- Only print numbers once at the end
print("open doors:", 0, 110, 7)
local x = 0
local y = 118
for i=1,100 do
if door_states[i] then
print(i.." ", x, y, 7)
x += 12
if x > 120 then
x = 0
y += 6
end
end
end
end
end
function _draw()
end
How’d we do?
This is ALMOST as satisfying as the VIC-20 version ;-)