box_packer 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzdjZDhlOTBiNmZmYjI3Zjc2ZDA2MTE2YWVlNWJiYWE0NmIwMjExMg==
4
+ MmU3YzNiYTFmYzA1YTM5MzFiYTc0NDA4MzYzODQ4YWQwZGM1OTI5Yg==
5
5
  data.tar.gz: !binary |-
6
- N2E1MDhjOTY1ZmQ5YjQ4M2M0MjUzMmY4ZTE4NzI5ZTNlOWEyYTY0OA==
6
+ NjdhYzg2OGM1ZjRhZDBjNTBiOWVlYzkwNjE5NGFlMDRjZmIwNTIzYw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODMxODdhNTE5OWQ4ZTNkNzFkZGJlYzY2ODJlYzU3OWMyNDQzNTBmNDAzYTlm
10
- MjJkMWZhOGVmMjkyM2MxNzc3ZDJhZGQzODJkNjFmMTVlMDc0ZTVkNjI2YjE1
11
- YzYwMjZhY2FkMGQ0YTZlZDU5Y2ZiYmU3MzVmOGYxNmU2OTRhZGQ=
9
+ ZTNkNmJmZWI4ODI5YzE0MjY2ZTcyZjI2OWJkZWE4NjhjY2VmNDg3MDBkOTI4
10
+ YjQ1MDEwY2UwZDhlYjA1NjI0OWJhODhkNGQ4YmQ4MjNkZDZiZTkzZmVhNmVk
11
+ NzE3MWM0MTA2M2VmYTg0YTk0NzQxYTc2NWFjNmYyNTMzNTkxNDY=
12
12
  data.tar.gz: !binary |-
13
- NmZkNTgzYzA3ZWYyZTI2YjdjMGJjZjhkM2Y0YTYyMmRmYmNkZjI4ZGUwNGE1
14
- YTFmMzhhYjcwZTZjNTBlZDVlMWZmNzliOThlNGM2OTlhN2ZiZjU5MjU4ZWE1
15
- NmMxNTM3NmVhNjIwYzQ4NzkyOWM5ZDczZTBmZWJlZmNmNTBiMjc=
13
+ OThjYjRlOWRhMDQ5OTMyNzNjNDI0M2QxNTRmYzE0NGM4ODYyMTM2YzA2MTVj
14
+ YTE0ZDdlMmM5MGI4MDU0MTRmYWI3Nzc5NjU0YTRiYjllNWRiNTM0NDFiMGFm
15
+ OGZmMTljZmJmZTFhYjA4YTgzMDU1MzQwNDkxODVhNDhlZTY1NzU=
data/README.md CHANGED
@@ -18,6 +18,8 @@ Usage
18
18
  -----
19
19
 
20
20
  ```Ruby
21
+ require "box_packer"
22
+
21
23
  container = BoxPacker::Container.new("MyContainer", [6, 3, 7], 50)
22
24
 
23
25
  container.items << BoxPacker::Item.new("MyItem01", [1, 5, 3], 10)
@@ -1,3 +1,3 @@
1
1
  module BoxPacker
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/box_packer.rb CHANGED
@@ -136,7 +136,7 @@ module BoxPacker
136
136
  end
137
137
 
138
138
  def items_all_light_enough?
139
- @items.all? { |item| item.weight < @weight_limit }
139
+ @items.all? { |item| item.weight <= @weight_limit }
140
140
  end
141
141
 
142
142
  def pack_box(current_items, box_to_pack)
@@ -0,0 +1,171 @@
1
+ require_relative "box_packer"
2
+ require "test/unit"
3
+ require 'benchmark'
4
+
5
+ class TestBoxPacker < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @containers = []
9
+ @containers[0] = BoxPacker::Container.new("A",[10, 1, 1],15)
10
+ @containers[1] = BoxPacker::Container.new("B",[1, 10, 5],50)
11
+ @containers[2] = BoxPacker::Container.new("C",[10, 15, 5],325)
12
+
13
+ @items = []
14
+ @items[0] = BoxPacker::Item.new("a",[1, 1, 1],1)
15
+ @items[1] = BoxPacker::Item.new("b",[3, 1, 1],6)
16
+ @items[2] = BoxPacker::Item.new("c",[5, 5, 1],15)
17
+ @items[3] = BoxPacker::Item.new("d",[5, 5, 5],20)
18
+
19
+ @skip_items_count = false
20
+ end
21
+
22
+ def teardown
23
+ @containers.delete_if{ |container| container.packings.empty? }
24
+ unless @containers.empty?
25
+ assert(@containers[0].packings.map(&:count).reduce(:+) == @containers[0].items.count, "Packed items less than container's list") unless @skip_items_count
26
+ assert(@containers[0].packings.map(&:remaining_weight).all? { |rw| rw >= 0 }, "Packing too heavy")
27
+ end
28
+ end
29
+
30
+ def test_no_items
31
+ assert_nil(@containers[0].pack)
32
+ end
33
+
34
+ def test_items_too_heavy
35
+ @items[0].weight = 16
36
+ @containers[0].items << @items[0]
37
+ assert_nil(@containers[0].pack)
38
+ end
39
+
40
+ def test_items_too_big
41
+ @containers[0].items << @items[2]
42
+ assert_nil(@containers[0].pack)
43
+ end
44
+
45
+ def test_too_many_packings
46
+ @containers[0].packings_limit = 1
47
+ 11.times { @containers[0].items << @items[0] }
48
+ assert_nil(@containers[0].pack)
49
+ @skip_items_count = true
50
+ end
51
+
52
+ def test_1d_one_full_packing
53
+ 7.times { @containers[0].items << @items[0] }
54
+ @containers[0].items << @items[1]
55
+ assert_equal(1, @containers[0].pack)
56
+ assert_equal(0, @containers[0].packings[0].remaining_volume)
57
+ end
58
+
59
+ def test_1d_two_packings_due_to_weight_limit
60
+ 3.times { @containers[0].items << @items[1] }
61
+ assert_equal(2, @containers[0].pack)
62
+ end
63
+
64
+ def test_1d_three_full_packings
65
+ @containers[0].packings_limit = 4
66
+ 3.times { @containers[0].items << @items[0] << @items[1] }
67
+ 18.times { @containers[0].items << @items[0] }
68
+ assert_equal(3, @containers[0].pack)
69
+ end
70
+
71
+ def test_2d_one_full_packing_two_identical_items
72
+ 2.times { @containers[1].items << @items[2] }
73
+ assert_equal(1, @containers[1].pack)
74
+ assert_equal(0, @containers[1].packings[0].remaining_volume)
75
+ end
76
+
77
+ def test_2d_one_full_packing_multiple_items
78
+ 4.times { @containers[1].items << @items[0] }
79
+ 7.times { @containers[1].items << @items[1] }
80
+ @containers[1].items << @items[2]
81
+ check_pack_in_between(@containers[1], 1, 2)
82
+ end
83
+
84
+ def test_2d_three_full_packings
85
+ @containers[1].packings_limit = 5
86
+ 8.times { @containers[1].items << @items[0] }
87
+ 14.times { @containers[1].items << @items[1] }
88
+ 4.times { @containers[1].items << @items[2] }
89
+ check_pack_in_between(@containers[1], 3, 4)
90
+ end
91
+
92
+ def test_3d_one_full_packing_with_identical_items
93
+ 6.times { @containers[2].items << @items[3] }
94
+ assert_equal(1, @containers[2].pack)
95
+ assert_equal(0, @containers[2].packings[0].remaining_volume)
96
+ end
97
+
98
+ def test_3d_one_full_packing_with_multiple_items
99
+ 20.times { @containers[2].items << @items[0] }
100
+ 10.times { @containers[2].items << @items[1] }
101
+ 8.times { @containers[2].items << @items[2] }
102
+ 4.times { @containers[2].items << @items[3] }
103
+ assert_equal(1, @containers[2].pack)
104
+ assert_equal(0, @containers[2].packings[0].remaining_volume)
105
+ end
106
+
107
+ def test_3d_three_full_packings
108
+ @containers[2].packings_limit = 5
109
+ 35.times { @containers[2].items << @items[0] }
110
+ 30.times { @containers[2].items << @items[1] }
111
+ 10.times { @containers[2].items << @items[2] }
112
+ 15.times { @containers[2].items << @items[3] }
113
+ check_pack_in_between(@containers[2], 3, 4)
114
+ end
115
+
116
+ def test_benchmark
117
+ puts "\n\nBenchmarking\n============"
118
+ iterations = 500
119
+ containers = []
120
+
121
+ (1..iterations).each do |i|
122
+ container_dimensions = [1 + rand(100), 1 + rand(50), 1 + rand(10)]
123
+ container_weight_limit = 1 + rand(1000)
124
+ container = BoxPacker::Container.new("c#{i}", container_dimensions, container_weight_limit)
125
+ container.packings_limit = 50
126
+
127
+ (1..(1+rand(40))).each do |j|
128
+ item_dimensions = container_dimensions.map { |c_dimension| 1 + rand(c_dimension) / (1 + rand(5)) }
129
+ item_weight = 1 + rand(container_weight_limit / (1 + rand(10)))
130
+ container.items << BoxPacker::Item.new("i#{j}", item_dimensions, item_weight)
131
+ end
132
+ containers << container
133
+ end
134
+
135
+ Benchmark.bm(15) do |bm|
136
+ bm.report('Approx packings') do
137
+ containers.each{ |container| container.pack }
138
+ end
139
+ bm.report('Volume') do
140
+ containers.each{ |container| container.pack(:sort_by_volume) }
141
+ end
142
+ bm.report('Shuffled') do
143
+ containers.each{ |container| container.pack(:sort_by_shuffle) }
144
+ end
145
+ end
146
+
147
+ puts "\nBenchmark data\n=============="
148
+ puts "iterations: #{iterations}"
149
+ benchmark_stats = Hash.new{0}
150
+ containers.each do |container|
151
+ benchmark_stats[:avg_container_volume] += container.volume
152
+ benchmark_stats[:avg_packings_count] += container.packings.count
153
+ benchmark_stats[:avg_items_count] += container.items.count
154
+ benchmark_stats[:avg_item_volume] += container.items.map(&:volume).reduce(:+) / container.items.count.to_f
155
+ end
156
+ benchmark_stats.each do |k, v|
157
+ benchmark_stats[k] = v / containers.count.to_f
158
+ puts "#{k}: #{benchmark_stats[k]}"
159
+ end
160
+ puts "\n"
161
+ end
162
+
163
+ private
164
+
165
+ def check_pack_in_between(container, lower_bound, upper_bound)
166
+ assert(container.pack.between?(lower_bound, upper_bound), "Did not pack into #{lower_bound} (or #{upper_bound}) packings")
167
+ assert(container.packings.map(&:remaining_volume).reduce(:+) % container.volume == 0 , "Total remaining volume doesn't add up")
168
+ end
169
+
170
+ end
171
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: box_packer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max White
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-22 00:00:00.000000000 Z
11
+ date: 2014-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,6 +53,7 @@ files:
53
53
  - box_packer.gemspec
54
54
  - lib/box_packer.rb
55
55
  - lib/box_packer/version.rb
56
+ - lib/tc_box_packer.rb
56
57
  homepage: ''
57
58
  licenses:
58
59
  - MIT