Hello! I just recently started messing around with pico-8 and am currently trying to make a fill detection function for a drawing game im working on
this function will take a 96x80 table (drawing_board) of either true or false values and will locate all enclosed loops of true values and fill them in.
My code works albeit very inefficiently (takes about 3 seconds with a sparse canvas) so any tips/suggestions to improve my functions would be greatly appreciated
-- Fill functions function fill_enclosed_areas(drawing_board) local enclosed_areas = check_enclosed_areas(drawing_board) for i = 1, #enclosed_areas do fill_area(drawing_board, enclosed_areas[i]) end return drawing_board end function check_enclosed_areas(drawing_board) local visited = {} local enclosed_areas = {} local enclosed_areas_coords = {} -- need to copy the drawing board to visited for x = 1, 96 do visited[x] = {} for y = 1, 80 do visited[x][y] = drawing_board[x][y] end end for x = 1, 96 do for y = 1, 80 do if visited[x][y] == false then visited, enclosed_areas_coords = fill_area(visited, {x=x, y=y}) if #enclosed_areas_coords > 0 then add(enclosed_areas, enclosed_areas_coords[1]) end end end end return enclosed_areas end function fill_area(drawing_board, coords) drawing_board[coords.x][coords.y] = true local stack = {} local enclosed = true local enclosed_areas = {} add(stack, {x=coords.x, y=coords.y}) while #stack > 0 do local current = stack[#stack] -- check up if current.y > 1 then if drawing_board[current.x][current.y - 1] == false then add(stack, {x = current.x, y = current.y - 1}) drawing_board[current.x][current.y - 1] = true end else enclosed = false end -- check down if current.y < 80 then if drawing_board[current.x][current.y + 1] == false then add(stack, {x = current.x, y = current.y + 1}) drawing_board[current.x][current.y + 1] = true end else enclosed = false end -- check left if current.x > 1 then if drawing_board[current.x - 1][current.y] == false then add(stack, {x = current.x - 1, y = current.y}) drawing_board[current.x - 1][current.y] = true end else enclosed = false end -- check right if current.x < 96 then if drawing_board[current.x + 1][current.y] == false then add(stack, { x = current.x + 1, y = current.y}) drawing_board[current.x + 1][current.y] = true end else enclosed = false end del(stack, current) end if enclosed then add(enclosed_areas, {x = coords.x, y = coords.y}) end return drawing_board, enclosed_areas end |
First, I recommend using pset()
and pget()
to make the purpose and result clear.
By doing this, you can omit the two-dimensional table drawing_board by using the screen buffer, which should make the code easier to read.
(The next steps will help you to make your code the shortest and fastest.)
https://www.lexaloffle.com/dl/docs/pico-8_manual.html#PSET
https://www.lexaloffle.com/dl/docs/pico-8_manual.html#PGET
You also need to run 'cls()' beforehand to clean the screen.
@bbread, do you need the list of enclosed areas or just the coloring ?
If it's just the coloring, you could add a 1 tile border to the array, do a flood fill from a corner, converting false to a third value "border", and after that , going over the array, turning "border" to false and the unattained false to true.
For the flood fill itself, since you seek performance rather than tokens, you should deal with horizontal segments (the board is wider than it's tall) rather than single cells. (span filling).
[Please log in to post a comment]