Google Groups Home
Help | Sign in
Message from discussion [SOLUTION] Packing (#62)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
horndud...@gmail.com  
View profile
 More options Jan 16 2006, 12:31 am
Newsgroups: comp.lang.ruby
From: horndud...@gmail.com
Date: 15 Jan 2006 21:31:05 -0800
Local: Mon, Jan 16 2006 12:31 am
Subject: [QUIZ][SOLUTION] Packing (#62)
Here's my solution. I keep track of the positions of the boxes in each
truckbed and generate the ascii only when it is printed. I was trying
to be fancy with the insertion points, but it became too difficult to
maintain so I just added every point and removed those covered by and
surrounding a box during insertion. I sort the boxes by size to put the
biggest ones in first. I'm fairly happy with my solution. Thanks for
the quiz!

-----Horndude77

class TruckBed
    def initialize(width,height)
        @width,@height = width,height
        @boxes = {}

        #This list maintains where it is possible to add boxes
        @insertion_points = [(0...width).to_a * height,
(0...height).map{|i| [i]*width}.flatten].transpose
        sort_insertion_points
    end

    def insert(box)
        @insertion_points.each do |pos|
            [box, box.reverse].each do |curr_box|
                if fits_at? curr_box, pos then
                    @boxes[pos] = curr_box
                    (-1).upto(curr_box[0]) do |x|
                        (-1).upto(curr_box[1]) do |y|
                            @insertion_points.delete [x+pos[0],
y+pos[1]]
                        end
                    end
                    sort_insertion_points
                    return true
                end
            end
        end
        false
    end

    #Stable sort: keep relative order
    #This way we control where insertions happen
    def sort_insertion_points
        n = 0
        @insertion_points.sort_by{|x| n+=1; [x[1], n]}
        @insertion_points.sort_by{|x| n+=1; [x[0], n]}
    end

    #See if box fits at pos
    def fits_at?(box, pos)
        box_min = pos
        box_max = [pos[0]+box[0]-1, pos[1]+box[1]-1]
        return false if (box_max[0] >= @width) || (box_max[1] >=
@height)
        #check for box intersections
        @boxes.each do |curr_pos, curr_box|
            curr_box_min = [curr_pos[0]-1, curr_pos[1]-1]
            curr_box_max = [curr_pos[0]+curr_box[0],
curr_pos[1]+curr_box[1]]
            return false if box_min[0] <= curr_box_max[0] && box_max[0]

>= curr_box_min[0] &&

                    box_min[1] <= curr_box_max[1] && box_max[1] >=
curr_box_min[1]
        end
        true
    end

    def to_s
        bed = Array.new(@width) { Array.new(@height) {'-'} }
        @boxes.each do |pos,box|
            box[0].times do |x|
                box[1].times do |y|
                    bed[x+pos[0]][y+pos[1]] = 'X'
                end
            end
        end
        bed.transpose.reverse.map {|r| r.join }.join("\n")
    end
end

class String
    def to_dims
        split('x').map {|i| i.to_i}
    end
end

truck_bed_dims = ARGF.gets.to_dims
boxes = ARGF.gets.split.map {|box| box.to_dims.sort.reverse}.sort
{|a,b| a[0]*a[1] <=> b[0]*b[1]}

truck_beds = [TruckBed.new(*truck_bed_dims)]

while boxes.size > 0
    box = boxes.pop
    truck_beds.each do |bed|
        if(bed.insert box) then
            box = nil
            break
        end
    end
    if(box) then
        bed = TruckBed.new(*truck_bed_dims)
        bed.insert(box)
        truck_beds << bed
    end
end

puts
puts truck_beds.join("\n\n")


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2008 Google