Summary
In this lesson, you learned that:
- A coroutine is a function that can pause in the middle and later continue from the same spot, with its local variables still there. Games use coroutines for things that take several turns or frames.
coroutine.create(f)makes a coroutine from the functionf(no parentheses afterf).coroutine.resume(co)runs it until the nextcoroutine.yield()or the end of the function. A coroutine is a value of the typethread, not a function, soco()fails withattempt to call a thread value.coroutine.status(co)issuspended(not started yet, or paused),runningordead(finished).coroutine.yield()outside a coroutine, for example in a function you called yourself, ends withattempt to yield from outside a coroutine.coroutine.yield(v)handsvout:resumereturnstrueandv.coroutine.resume(co, x)handsxin: the firstresumeto the function's parameters, every later one as the result of theyieldthe coroutine is waiting at.- A
while true doloop with ayieldinside isn't endless: it pauses at everyyield. coroutine.wrap(f)returns a generator: a function that resumes the coroutine and returns only the values fromyield. It fits intofor … in, which stops when the coroutine's function ends. A used-up generator can't start over; make a new one.- In a game, each character can have a coroutine with its script. The game loop resumes each of them once per turn. They take turns; they never run at the same time.
- An error inside a coroutine stops only the coroutine:
resumereturnsfalseand the message, and the coroutine isdead. Resuming a dead coroutine givesfalseandcannot resume dead coroutine. So check the first value. A generator fromwrappasses errors on, and the program stops.
In the next lesson, the final project, you'll put the whole course together: a season on Emma's farm, one program built step by step, from buying seeds to selling the harvest. Hugo the trader will be there too, as a coroutine, of course.
But first, practice this lesson. Emma is about to water her field; the list of her plots is in the editor.
Instructions
Write a function thirstyPlots(plots) that returns a generator made with coroutine.wrap. The generator yields every plot of the list plots whose water is more than 0. Loop over thirstyPlots(field) and print each plot's crop and water, like this:
To water: carrots (2 l)
To water: pumpkins (3 l)
To water: potatoes (2 l)
To water: tomatoes (1 l)Emma's watering can is a coroutine. Write a function wateringCan(liters) with a loop that runs forever. In the loop, the can yields how many liters it holds and waits for how many to pour, local amount = coroutine.yield(liters), and then pours them: it subtracts amount from liters. Create a coroutine can from it, start it with coroutine.resume(can, 6) and print how much it holds. Then loop over a new generator thirstyPlots(field), resume can with each plot's water, and print what's left. Below the list from step 1, the program prints (the last two lines are wrong; you'll fix them in the next step):
The can holds 6 l
carrots: 4 l left
pumpkins: 1 l left
potatoes: -1 l left
tomatoes: -2 l leftA can can't pour more water than it holds. In wateringCan, when amount is more than liters, end with error("not enough water", 0). In the loop over the plots, check what resume returns: when it fails, print the crop and the message, and end the loop with break. After the loop, print Emma goes to the well. The whole program prints:
To water: carrots (2 l)
To water: pumpkins (3 l)
To water: potatoes (2 l)
To water: tomatoes (1 l)
The can holds 6 l
carrots: 4 l left
pumpkins: 1 l left
potatoes: not enough water
Emma goes to the well.Start programming for free
6/6