Skip to content

Instantly share code, notes, and snippets.

@tesselode
Created March 21, 2020 06:48
Show Gist options
  • Save tesselode/1dfb1c0e1864da09defd0b8529d877e4 to your computer and use it in GitHub Desktop.
Save tesselode/1dfb1c0e1864da09defd0b8529d877e4 to your computer and use it in GitHub Desktop.
the promise implementation i'm currently using in my puzzle game
local function async(f)
local co
local function await(promise)
if promise:isFinished() then return end
promise:after(function()
local success, message = coroutine.resume(co)
if not success then error(message) end
end)
coroutine.yield()
end
co = coroutine.create(function() f(await) end)
local success, message = coroutine.resume(co)
if not success then error(message) end
return co
end
function Board:rotate(x, y, counterClockwise)
assert(x >= 0 and x <= constant.boardWidth - 2 and y >= 0 and y <= constant.boardHeight - 2,
'trying to rotate tiles out of bounds')
util.async(function(await)
local promises = {}
local topLeft = self:getTileAt(x, y)
local topRight = self:getTileAt(x + 1, y)
local bottomRight = self:getTileAt(x + 1, y + 1)
local bottomLeft = self:getTileAt(x, y + 1)
if topLeft then
table.insert(promises, topLeft:rotate('topLeft', counterClockwise))
end
if topRight then
table.insert(promises, topRight:rotate('topRight', counterClockwise))
end
if bottomRight then
table.insert(promises, bottomRight:rotate('bottomRight', counterClockwise))
end
if bottomLeft then
table.insert(promises, bottomLeft:rotate('bottomLeft', counterClockwise))
end
self.pool:emit('onBoardRotatingTiles', self, x, y, counterClockwise)
local rotateTilesPromise = Promise.all(promises)
if self:willTilesFall() then
self.freeToRotate = false
await(rotateTilesPromise)
await(self:fallTiles())
self.freeToRotate = true
end
local squares, numSquares, numNewSquares = self:checkSquares()
if numSquares > 0 and numNewSquares < 1 then
self.freeToRotate = false
await(rotateTilesPromise)
await(self:clearTiles(squares))
self.freeToRotate = true
end
end)
end
-- this is using classic for object orientation, but you can use any class library you like (or roll your own)
local Object = require 'lib.classic'
local Promise = Object:extend()
function Promise:new(f)
self._onFinish = {}
self._finished = false
if f then
f(function(...) self:finish(...) end)
end
end
function Promise:isFinished()
return self._finished
end
function Promise:finish(...)
for _, f in ipairs(self._onFinish) do
f(...)
end
self._finished = true
end
function Promise:after(f)
table.insert(self._onFinish, f)
return self
end
function Promise.all(promises)
return Promise(function(finish)
if #promises < 1 then
finish()
return
end
local finished = {}
for _, promise in ipairs(promises) do
finished[promise] = false
promise:after(function()
-- mark this child promise as finished
finished[promise] = true
-- if all child promises are finished...
for _, v in pairs(finished) do
if v == false then return end
end
-- finish the parent promise
finish()
end)
end
end)
end
return Promise
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment