use strict; use warnings; use Data::Dumper; my $area = [ [ 10, 20 ] ]; my $rect = [ [ 5, 12 ], [ 4, 8 ], [ 12, 2 ] ]; foreach my $r (@$rect) { my $leftover = []; foreach (@$area) { my ($n1, $n2) = fit_rect_in_area($r, $_); next if !defined $n1; $leftover = [ @$leftover, @$n1, @$n2 ]; } $area = $leftover; } # # +------------------------+ # | | # | | # +---------------+ | # | | | # | | | # +---------------+--------+ # # two left over area options => # # +------------------------+ +--------+ # | | + | | # | | | | # +------------------------+ +--------+ # # or # # +---------------+ +--------+ # | | + | | # | | | | # +---------------+ | | # | | # | | # +--------+ # sub fit_rect_in_area { my ($rect, $area) = @_; if (canfit($rect, $area)) { print rectstr($rect) . " can fit inside " . rectstr($area) . "\n"; my ($n1, $n2) = fitrect($rect, $area); print "leftover option 1: " . join(" and ", map { rectstr($_) } @{$n1}) . "\n"; print "leftover option 2: " . join(" and ", map { rectstr($_) } @{$n2}) . "\n"; return ($n1, $n2); } elsif (canfit(rotate($rect), $area)) { print rectstr($rect) . " can fit inside " . rectstr($area) . " after rotation\n"; my ($n1, $n2) = fitrect(rotate($rect), $area); print "leftover option 1: " . join(" and ", map { rectstr($_) } @{$n1}) . "\n"; print "leftover option 2: " . join(" and ", map { rectstr($_) } @{$n2}) . "\n"; return ($n1, $n2); } else { print rectstr($rect) . " can not fit inside " . rectstr($area) . "\n"; return (); } } # place rect on area sub fitrect { my ($rect, $area) = @_; my $a1 = [ $area->[0] - $rect->[0], $area->[1] ]; my $a2 = [ $rect->[0], $area->[1] - $rect->[1] ]; my $b1 = [ $area->[0] - $rect->[0], $rect->[1] ]; my $b2 = [ $area->[0], $area->[1] - $rect->[1] ]; return ([ $a1, $a2 ], [ $b1, $b2 ]); } # check if a rect can fit sub canfit { my ($rect, $area) = @_; return $rect->[0] <= $area->[0] && $rect->[1] <= $area->[1]; } # rotate a rectangle sub rotate { my $rect = shift; return [ $rect->[1], $rect->[0] ]; } # return textual representation of rectangle sub rectstr { my $rect = shift; return sprintf "R(W=%d, H=%d)", $rect->[0], $rect->[1]; } #### R(W=5, H=12) can fit inside R(W=10, H=20) leftover option 1: R(W=5, H=20) and R(W=5, H=8) leftover option 2: R(W=5, H=12) and R(W=10, H=8) R(W=4, H=8) can fit inside R(W=5, H=20) leftover option 1: R(W=1, H=20) and R(W=4, H=12) leftover option 2: R(W=1, H=8) and R(W=5, H=12) R(W=4, H=8) can fit inside R(W=5, H=8) leftover option 1: R(W=1, H=8) and R(W=4, H=0) leftover option 2: R(W=1, H=8) and R(W=5, H=0) R(W=4, H=8) can fit inside R(W=5, H=12) leftover option 1: R(W=1, H=12) and R(W=4, H=4) leftover option 2: R(W=1, H=8) and R(W=5, H=4) R(W=4, H=8) can fit inside R(W=10, H=8) leftover option 1: R(W=6, H=8) and R(W=4, H=0) leftover option 2: R(W=6, H=8) and R(W=10, H=0) R(W=12, H=2) can not fit inside R(W=1, H=20) R(W=12, H=2) can fit inside R(W=4, H=12) after rotation leftover option 1: R(W=2, H=12) and R(W=2, H=0) leftover option 2: R(W=2, H=12) and R(W=4, H=0) R(W=12, H=2) can not fit inside R(W=1, H=8) R(W=12, H=2) can fit inside R(W=5, H=12) after rotation leftover option 1: R(W=3, H=12) and R(W=2, H=0) leftover option 2: R(W=3, H=12) and R(W=5, H=0) R(W=12, H=2) can not fit inside R(W=1, H=8) R(W=12, H=2) can not fit inside R(W=4, H=0) R(W=12, H=2) can not fit inside R(W=1, H=8) R(W=12, H=2) can not fit inside R(W=5, H=0) R(W=12, H=2) can not fit inside R(W=1, H=12) R(W=12, H=2) can not fit inside R(W=4, H=4) R(W=12, H=2) can not fit inside R(W=1, H=8) R(W=12, H=2) can not fit inside R(W=5, H=4) R(W=12, H=2) can not fit inside R(W=6, H=8) R(W=12, H=2) can not fit inside R(W=4, H=0) R(W=12, H=2) can not fit inside R(W=6, H=8) R(W=12, H=2) can not fit inside R(W=10, H=0)