Торговец
Каждый день торговец Гуго проезжает на телеге мимо фермы Эммы и покупает урожай. Его цены меняются каждый день. Когда телега пуста, он платит за каждую единицу урожая на 2 монеты больше, чем рынок. На следующий день, когда она наполовину полна, — на 1 монету больше. На третий день она полна, и он платит ровно столько, сколько рынок. Затем он увозит всё в город, и всё начинается снова: 2, 1, 0, 2, 1, 0…
Правило Эммы простое: если Гуго платит больше рынка, она продаёт ему всё, что лежит в сарае. Иначе она оставляет всё себе, и в конце сезона это уходит на рынок.
Дни Гуго — работа для сопрограммы, как в уроке про сопрограммы: функция, которая каждый день выполняется немного и останавливается на coroutine.yield. coroutine.wrap превращает её в функцию, которая её продолжает: каждый вызов запускает её до следующего yield и возвращает значение, переданное в yield. Например, чем весь день занят пёс Рекс:
local function rexScript()
while true do
coroutine.yield("охраняет сарай")
coroutine.yield("спит у колодца")
end
end
local rex = coroutine.wrap(rexScript)
for day = 1, 3 do
print("День " .. day .. ": Рекс " .. rex())
endОн выведет:
День 1: Рекс охраняет сарай
День 2: Рекс спит у колодца
День 3: Рекс охраняет сарайЦикл while true никогда не заканчивается, но здесь это нормально. На каждом yield сопрограмма останавливается, а программа идёт дальше. Сопрограмма запускается снова только тогда, когда её вызывают, и продолжает с того места, где остановилась, здесь — посреди своего цикла. Сценарий Гуго будет таким же, только внутри него будет цикл for от 2 до 0. Не забудьте про его шаг, -1. Без него цикл for не выполнится ни разу, while true никогда не дойдёт до yield, и программа будет работать, пока сайт не остановит её через 5 секунд.
Сценарий Гуго должен выполняться как сопрограмма — через coroutine.wrap (или coroutine.create и coroutine.resume). Если вызвать hugoScript() напрямую, это не сопрограмма, и yield некуда возвращаться: attempt to yield from outside a coroutine (на этот раз без номера строки в начале). И создавайте сопрограмму только один раз, над циклом по дням. Если создать её внутри цикла, она каждый день будет начинаться заново, и Гуго всегда платил бы на 2 монеты больше.
Функции sell нужны ещё два параметра: кто покупает (buyer) и на сколько монет больше рынка он платит (extra). Задайте им значения по умолчанию, как в уроке про функции: buyer = buyer or "Рынок" и extra = extra or 0. Тогда вызов sell(barn) в конце сезона работает, как раньше.
sell должна ещё и опустошать сарай: barn[name] = nil убирает проданную культуру. Без этого Гуго покупал бы одну и ту же пшеницу в другие дни, рынок — ещё раз в конце, и Эмма закончила бы сезон с 390 монетами. Это слишком хорошо, чтобы быть правдой. Удалять ключи сарая внутри цикла можно, потому что цикл идёт по отдельному списку из sortedNames.
В первый день Гуго платит на 2 монеты больше, но сарай ещё пуст, и sell вывела бы Гуго: = 0. Поэтому пусть она выводит свою строку, только если итог больше 0.
Задание
- 1
Под
sellнапишите функциюhugoScript()с бесконечным цикломwhile true. Внутри него циклforидёт от2до0(с шагом-1) и отдаёт каждое число вcoroutine.yield. - 2
Измените
sell. Добавьте ей параметрыbuyerиextraсо значениями по умолчанию"Рынок"и0, прибавляйтеextraк цене каждой культуры, начинайте строку сbuyerвместоРыноки убирайте каждую проданную культуру из сарая. Выводите строку, только когда итог больше 0. Вывод пока не меняется. - 3
В главной программе создайте сопрограмму Гуго над циклом по дням:
local hugo = coroutine.wrap(hugoScript). Каждый день после строки дня получайте надбавку Гуго изhugo(). Если она больше 0, продайте ему всё, что лежит в сарае, с помощьюsell(barn, "Гуго", extra)и прибавьте монеты. Теперь сезон выглядит так:Не хватает монет: клубника x2 Монеты: 6 День 1 (солнечно): морковь 1/3, пшеница 1/2, тыква 1/6 День 2 (солнечно): морковь 2/3, пшеница 2/2, тыква 2/6 Гуго: пшеница 6 x 4 = 24 День 3 (дождливо): морковь 3/3, пшеница 2/2, тыква 4/6 День 4 (облачно): морковь 1/3, пшеница 1/2, тыква 5/6 Гуго: морковь 4 x 7, пшеница 6 x 5 = 58 День 5 (солнечно): морковь 2/3, пшеница 2/2, тыква 6/6 Гуго: пшеница 6 x 4, тыква 2 x 21 = 66 День 6 (облачно): морковь 3/3, пшеница 1/2, тыква 1/6 Рынок: морковь 4 x 5 = 20 Конец сезона. Монеты: 174Если Гуго каждый день платит на 2 монеты больше (
пшеница 6 x 5во 2-й день), вы создаёте его сопрограмму внутри цикла.