Search code examples
sortinglua2dlove2d

Sorting 2D boxes into larger boxes to fill in the most efficient and complete manner


Background:
Hello, so I've been working on this function for a bit and I'm stumbling. Ultimately, what I'm trying to accomplish is to have an application where a user inputs larger boxes, and also inputs a list of smaller boxes. (All 2 dimensional, by the way). The program then processes this, and tries to fill as completely as possible the larger boxes with the smaller ones. For those curious, this is for a theater platform application.

Code stuff:
I have this function here that takes "box", which is a table of larger boxes created by the user, and "platforms", which is a table of smaller boxes. As seen in the comments, I've already written the part where if a platform fits perfectly into a box, then it does so. It then reduces the quantity of the given size of that platform, and marks that box as filled.

Problem:
The problem I can't figure out is how to programmatically fit two platforms into one larger box in the most efficient manner. I considered using the x side of the box and filling that up with the x values of a given set of platforms, and then interplacing different platforms with the same x values in that set, but with different y values but there's several problems there.
Any pointers on where I should go from here?

userInterfaceCall()
    squares[#squares+1] = {x1=x, y1=y, x2 = nil, y2 = nil, f=false}
    --x1,y1 and x2,y2 are coordinates for two opposite points in a square
    --f is the boolean that is marked true when a square (box) is completely filled
end

platforms[1] = {x=4, y=4, q=2} --example user data
platforms[2] = {x=4, y=6, q=2} --x and y are platform dimensions
platforms[3] = {x=6, y=2, q=1} --q is quantity
platforms[4] = {x=8, y=4, q=1} 

process(squares,platforms) --this is called by a UI element

function process(box,platforms)
for i,box in ipairs(box) do                     --for every square do
    if box.f == false then                      --if the box already has a given platform, don't do shit
        for i,platform in ipairs(platforms) do  --for each platform for each box
            boxX = math.abs(box.x1-box.x2)/scale  --Ignore this, this is working with scaling from-
            boxY = math.abs(box.y1-box.y2)/scale  --pixel size to feet to compare to list of platforms
            if boxX == platform.x and boxY == platform.y and platform.q > 0 then        --Test if any platform fits directly in the box
                placements[#placements+1] = {x1 = box.x1, y1 = box.y1, x2 = box.x2, y2 = box.y2, s = ''} --Creates a new placement of a given platform, which is then drawn
                platform.q = platform.q - 1 --we reduce the quantity, cause we used one
                box.f = true --yes, we just filled the box completely
            elseif boxY == platform.x and boxX == platform.y and platform.q > 0 then    --Test for switched x and y
                placements[#placements+1] = {x1 = box.x1, y1 = box.y1, x2 = box.x2, y2 = box.y2, s = ''}
                platform.q = platform.q - 1
                box.f = true
            elseif
                --put multiple platforms in one box, Help
            else
                setPrompt('Could not find for box: '..boxX..','..boxY)
            end
        end
    end
end

end


Solution

  • You found a variant of the Multi-dimensional Knapsack Problem, which is known to be NP-complete. So no, there is no simple "best" solution, however, a number of strategies have been found to yield acceptable results in acceptable time. Please see the linked article for further explanation.