module BoxPacker
Public Class Methods
break_up_space(space, placement)
click to toggle source
# File box_packer.rb, line 88 def break_up_space(space, placement) [ { dimensions: [ space[:dimensions][0] - placement[:dimensions][0], space[:dimensions][1], space[:dimensions][2] ], position: [ space[:position][0] + placement[:dimensions][0], space[:position][1], space[:position][2] ] }, { dimensions: [ placement[:dimensions][0], space[:dimensions][1] - placement[:dimensions][1], space[:dimensions][2] ], position: [ space[:position][0], space[:position][1] + placement[:dimensions][1], space[:position][2] ] }, { dimensions: [ placement[:dimensions][0], placement[:dimensions][1], space[:dimensions][2] - placement[:dimensions][2] ], position: [ space[:position][0], space[:position][1], space[:position][2] + placement[:dimensions][2] ] } ] end
pack(container:, items:)
click to toggle source
# File box_packer.rb, line 3 def pack(container:, items:) packings = [] items.each do |item| # If the item is just too big for the container lets give up on this raise 'Item is too heavy for container' if item[:weight].to_f > container[:weight_limit].to_f # Need a bool so we can break out nested loops once it's been packed item_has_been_packed = false packings.each do |packing| # If this packings going to be too big with this # item as well then skip on to the next packing next if packing[:weight].to_f + item[:weight].to_f > container[:weight_limit].to_f packing[:spaces].each do |space| # Try placing the item in this space, # if it doesn't fit skip on the next space next unless placement = place(item, space) # Add the item to the packing and # break up the surrounding spaces packing[:placements] += [placement] packing[:weight] += item[:weight].to_f packing[:spaces] -= [space] packing[:spaces] += break_up_space(space, placement) item_has_been_packed = true break end break if item_has_been_packed end next if item_has_been_packed # Can't fit in any of the spaces for the current packings # so lets try a new space the size of the container space = { dimensions: container[:dimensions].sort.reverse, position: [0, 0, 0] } placement = place(item, space) # If it can't be placed in this space, then it's just # too big for the container and we should abandon hope raise 'Item cannot be placed in container' unless placement # Otherwise lets put the item in a new packing # and break up the remaing free space around it packings += [{ placements: [placement], weight: item[:weight].to_f, spaces: break_up_space(space, placement) }] end packings end
place(item, space)
click to toggle source
# File box_packer.rb, line 60 def place(item, space) item_width, item_height, item_length = item[:dimensions].sort.reverse permutations = [ [item_width, item_height, item_length], [item_width, item_length, item_height], [item_height, item_width, item_length], [item_height, item_length, item_width], [item_length, item_width, item_height], [item_length, item_height, item_width] ] permutations.each do |perm| # Skip if the item does not fit with this orientation next unless perm[0] <= space[:dimensions][0] && perm[1] <= space[:dimensions][1] && perm[2] <= space[:dimensions][2] return { dimensions: perm, position: space[:position], weight: item[:weight].to_f } end return nil end