Completed
Push — issue_187 ( fb1b49...8952f9 )
by Doug
158:46 queued 155:58
created

BoxList   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 52
Duplicated Lines 0 %

Test Coverage

Coverage 94.44%

Importance

Changes 0
Metric Value
eloc 16
c 0
b 0
f 0
dl 0
loc 52
ccs 17
cts 18
cp 0.9444
rs 10
wmc 6

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getIterator() 0 8 2
A insert() 0 3 1
A compare() 0 17 3
1
<?php
2
/**
3
 * Box packing (3D bin packing, knapsack problem).
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace DVDoug\BoxPacker;
10
11
use ArrayIterator;
12
use IteratorAggregate;
13
use Traversable;
14
use function usort;
15
16
/**
17
 * List of boxes available to put items into, ordered by volume.
18
 *
19
 * @author Doug Wright
20
 */
21
class BoxList implements IteratorAggregate
22
{
23
    /**
24
     * List containing boxes.
25
     *
26
     * @var Box[]
27
     */
28
    private $list = [];
29
30
    /**
31
     * Has this list already been sorted?
32
     *
33
     * @var bool
34
     */
35
    private $isSorted = false;
36
37 8
    public function getIterator(): Traversable
38
    {
39 8
        if (!$this->isSorted) {
40 8
            usort($this->list, [$this, 'compare']);
41 8
            $this->isSorted = true;
42
        }
43
44 8
        return new ArrayIterator($this->list);
45
    }
46
47 8
    public function insert(Box $item): void
48
    {
49 8
        $this->list[] = $item;
50 8
    }
51
52
    /**
53
     * @param Box $boxA
54
     * @param Box $boxB
55
     */
56 6
    public function compare($boxA, $boxB): int
57
    {
58 6
        $boxAVolume = $boxA->getInnerWidth() * $boxA->getInnerLength() * $boxA->getInnerDepth();
59 6
        $boxBVolume = $boxB->getInnerWidth() * $boxB->getInnerLength() * $boxB->getInnerDepth();
60
61 6
        $volumeDecider = $boxAVolume <=> $boxBVolume; // try smallest box first
62 6
        $emptyWeightDecider = $boxB->getEmptyWeight() <=> $boxA->getEmptyWeight(); // with smallest empty weight
63
64 6
        if ($volumeDecider !== 0) {
65 6
            return $volumeDecider;
66
        }
67 1
        if ($emptyWeightDecider !== 0) {
68
            return $emptyWeightDecider;
69
        }
70
71
        // maximum weight capacity as fallback decider
72 1
        return ($boxA->getMaxWeight() - $boxA->getEmptyWeight()) <=> ($boxB->getMaxWeight() - $boxB->getEmptyWeight());
73
    }
74
}
75