Passed
Push — master ( 79d4e4...fedc6a )
by Doug
03:25
created

PackedItemList::insert()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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 Countable;
13
use IteratorAggregate;
14
use Traversable;
15
16
use function array_map;
17
use function count;
18
use function usort;
19
20
/**
21
 * List of packed items, ordered by volume.
22
 */
23
class PackedItemList implements Countable, IteratorAggregate
24
{
25
    /**
26
     * @var PackedItem[]
27
     */
28
    private array $list = [];
29
30
    private int $weight = 0;
31
32
    private bool $isSorted = false;
33
34 89
    public function insert(PackedItem $item): void
35
    {
36 89
        $this->list[] = $item;
37 89
        $this->weight += $item->getItem()->getWeight();
38
    }
39
40
    /**
41
     * @return Traversable<PackedItem>
42
     */
43 92
    public function getIterator(): Traversable
44
    {
45 92
        if (!$this->isSorted) {
46 92
            usort($this->list, $this->compare(...));
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected ')' on line 46 at column 49
Loading history...
47 92
            $this->isSorted = true;
48
        }
49
50 92
        return new ArrayIterator($this->list);
51
    }
52
53
    /**
54
     * Number of items in list.
55
     */
56 92
    public function count(): int
57
    {
58 92
        return count($this->list);
59
    }
60
61
    /**
62
     * Get copy of this list as a standard PHP array.
63
     *
64
     * @internal
65
     *
66
     * @return Item[]
67
     */
68 9
    public function asItemArray(): array
69
    {
70 9
        return array_map(fn (PackedItem $packedItem) => $packedItem->getItem(), $this->list);
71
    }
72
73
    /**
74
     * Get total volume of these items.
75
     */
76 92
    public function getVolume(): int
77
    {
78 92
        $volume = 0;
79
80 92
        foreach ($this->list as $item) {
81 89
            $volume += $item->getVolume();
82
        }
83
84 92
        return $volume;
85
    }
86
87
    /**
88
     * Get total weight of these items.
89
     */
90 92
    public function getWeight(): int
91
    {
92 92
        return $this->weight;
93
    }
94
95 77
    private function compare(PackedItem $itemA, PackedItem $itemB): int
96
    {
97 77
        $itemAVolume = $itemA->getItem()->getWidth() * $itemA->getItem()->getLength() * $itemA->getItem()->getDepth();
98 77
        $itemBVolume = $itemB->getItem()->getWidth() * $itemB->getItem()->getLength() * $itemB->getItem()->getDepth();
99
100 77
        return ($itemBVolume <=> $itemAVolume) ?: ($itemB->getItem()->getWeight() <=> $itemA->getItem()->getWeight());
101
    }
102
}
103