From 6b9bda12262ab987e14a8a82941f29a0a9300e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Sm=C3=B3=C5=82kowski?= Date: Wed, 24 May 2023 09:36:26 +0200 Subject: [PATCH] Packager method for packing the heaviest items first --- src/Packager.php | 29 +++++++++ tests/TestCases/PackagerTest.php | 108 +++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/src/Packager.php b/src/Packager.php index 91c3bfe..65c7d2f 100644 --- a/src/Packager.php +++ b/src/Packager.php @@ -370,6 +370,35 @@ public function withFirstFit(): self return $this; } + /** + * This method sort items by their weight, packing the heaviest first. + * It could be ascending or descending. + * + * @return self + */ + public function withHeaviestFirst(): self + { + // Sort the bins based on the sort method value + $iterableBins = $this->getIterableBins(); + $iterableBins->uasort(function ($a, $b) { + if ($a->getWeight() === $b->getWeight()) return 0; + return ($a->getWeight() > $b->getWeight()) ? $this->sortMethod : SortType::DESCENDING * $this->sortMethod; + }); + + $this->bins = $iterableBins; + + // Sort the items based on the sort method value + $iterableItems = $this->getIterableItems(); + $iterableItems->uasort(function ($a, $b) { + if ($a->getWeight() === $b->getWeight()) return 0; + return ($a->getWeight() > $b->getWeight()) ? $this->sortMethod : SortType::DESCENDING * $this->sortMethod;; + }); + + $this->items = $iterableItems; + + return $this; + } + /** * The main pack method, this method would try to pack all the items into all the bins * based on the chosen method, currently the available method is the @see withFirstFit(). diff --git a/tests/TestCases/PackagerTest.php b/tests/TestCases/PackagerTest.php index 67ac365..89756aa 100644 --- a/tests/TestCases/PackagerTest.php +++ b/tests/TestCases/PackagerTest.php @@ -372,6 +372,114 @@ public function testPackMethod_Not_All_Items_Fitted_Into_Two_Bins(): void $this->assertCount(1, $resultedBins[$this->binFixture->bin1Id]->getUnfittedItems()); } + /** + * pack() method tested with two bins and seven items. + * The second bin should go first, cause it has bigger volume. + * All items are fitted into just only the second bin. + * + * @return void + */ + public function testPackMethod_HeaviestFirst_All_Items_Fitted_Into_One_Bin(): void + { + $this->packager->addBins([ + new Bin($this->binFixture->bin1Id, $this->binFixture->bin1Length, $this->binFixture->bin1Height, $this->binFixture->bin1Breadth, $this->binFixture->bin1Weight), + new Bin($this->binFixture->bin2Id, $this->binFixture->bin2Length, $this->binFixture->bin2Height, $this->binFixture->bin2Breadth, $this->binFixture->bin2Weight), + ]); + + $this->packager->addItems([ + new Item($this->itemFixture->item1Id, $this->itemFixture->item1Length, $this->itemFixture->item1Height, $this->itemFixture->item1Breadth, $this->itemFixture->item1Weight), + new Item($this->itemFixture->item2Id, $this->itemFixture->item2Length, $this->itemFixture->item2Height, $this->itemFixture->item2Breadth, $this->itemFixture->item2Weight), + new Item($this->itemFixture->item3Id, $this->itemFixture->item3Length, $this->itemFixture->item3Height, $this->itemFixture->item3Breadth, $this->itemFixture->item3Weight), + new Item($this->itemFixture->item4Id, $this->itemFixture->item4Length, $this->itemFixture->item4Height, $this->itemFixture->item4Breadth, $this->itemFixture->item4Weight), + new Item($this->itemFixture->item5Id, $this->itemFixture->item5Length, $this->itemFixture->item5Height, $this->itemFixture->item5Breadth, $this->itemFixture->item5Weight), + new Item($this->itemFixture->item6Id, $this->itemFixture->item6Length, $this->itemFixture->item6Height, $this->itemFixture->item6Breadth, $this->itemFixture->item6Weight), + new Item($this->itemFixture->item7Id, $this->itemFixture->item7Length, $this->itemFixture->item7Height, $this->itemFixture->item7Breadth, $this->itemFixture->item7Weight), + ]); + + $this->packager->withHeaviestFirst()->pack(); + + $resultedBins = $this->packager->getBins(); + + $this->assertCount(7, $resultedBins[$this->binFixture->bin2Id]->getFittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin1Id]->getFittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin2Id]->getUnfittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin1Id]->getUnfittedItems()); + } + + /** + * pack() method tested with two bins and nine items. + * The second bin should go first, cause it has bigger volume. + * All items are fitted into the second bin. + * + * @return void + */ + public function testPackMethod_HeaviestFirst_All_Items_Fitted_Into_Two_Bins(): void + { + $this->packager->addBins([ + new Bin($this->binFixture->bin1Id, $this->binFixture->bin1Length, $this->binFixture->bin1Height, $this->binFixture->bin1Breadth, $this->binFixture->bin1Weight), + new Bin($this->binFixture->bin2Id, $this->binFixture->bin2Length, $this->binFixture->bin2Height, $this->binFixture->bin2Breadth, $this->binFixture->bin2Weight), + ]); + + $this->packager->addItems([ + new Item($this->itemFixture->item1Id, $this->itemFixture->item1Length, $this->itemFixture->item1Height, $this->itemFixture->item1Breadth, $this->itemFixture->item1Weight), + new Item($this->itemFixture->item2Id, $this->itemFixture->item2Length, $this->itemFixture->item2Height, $this->itemFixture->item2Breadth, $this->itemFixture->item2Weight), + new Item($this->itemFixture->item3Id, $this->itemFixture->item3Length, $this->itemFixture->item3Height, $this->itemFixture->item3Breadth, $this->itemFixture->item3Weight), + new Item($this->itemFixture->item4Id, $this->itemFixture->item4Length, $this->itemFixture->item4Height, $this->itemFixture->item4Breadth, $this->itemFixture->item4Weight), + new Item($this->itemFixture->item5Id, $this->itemFixture->item5Length, $this->itemFixture->item5Height, $this->itemFixture->item5Breadth, $this->itemFixture->item5Weight), + new Item($this->itemFixture->item6Id, $this->itemFixture->item6Length, $this->itemFixture->item6Height, $this->itemFixture->item6Breadth, $this->itemFixture->item6Weight), + new Item($this->itemFixture->item7Id, $this->itemFixture->item7Length, $this->itemFixture->item7Height, $this->itemFixture->item7Breadth, $this->itemFixture->item7Weight), + new Item($this->itemFixture->item8Id, $this->itemFixture->item8Length, $this->itemFixture->item8Height, $this->itemFixture->item8Breadth, $this->itemFixture->item8Weight), + new Item($this->itemFixture->item9Id, $this->itemFixture->item9Length, $this->itemFixture->item9Height, $this->itemFixture->item9Breadth, $this->itemFixture->item9Weight), + ]); + + $this->packager->withHeaviestFirst()->pack(); + + $resultedBins = $this->packager->getBins(); + + $this->assertCount(9, $resultedBins[$this->binFixture->bin2Id]->getFittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin1Id]->getFittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin2Id]->getUnfittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin1Id]->getUnfittedItems()); + } + + /** + * pack() method tested with two bins and ten items. + * The second bin should go first, cause it has bigger volume. + * Eight items are fitted into the second bin, and only one is fitted into the first bin, + * since the item 10 is not fitted into any bin. + * + * @return void + */ + public function testPackMethod_HeaviestFirst_Not_All_Items_Fitted_Into_Two_Bins(): void + { + $this->packager->addBins([ + new Bin($this->binFixture->bin1Id, $this->binFixture->bin1Length, $this->binFixture->bin1Height, $this->binFixture->bin1Breadth, $this->binFixture->bin1Weight), + new Bin($this->binFixture->bin2Id, $this->binFixture->bin2Length, $this->binFixture->bin2Height, $this->binFixture->bin2Breadth, $this->binFixture->bin2Weight), + ]); + + $this->packager->addItems([ + new Item($this->itemFixture->item1Id, $this->itemFixture->item1Length, $this->itemFixture->item1Height, $this->itemFixture->item1Breadth, $this->itemFixture->item1Weight), + new Item($this->itemFixture->item2Id, $this->itemFixture->item2Length, $this->itemFixture->item2Height, $this->itemFixture->item2Breadth, $this->itemFixture->item2Weight), + new Item($this->itemFixture->item3Id, $this->itemFixture->item3Length, $this->itemFixture->item3Height, $this->itemFixture->item3Breadth, $this->itemFixture->item3Weight), + new Item($this->itemFixture->item4Id, $this->itemFixture->item4Length, $this->itemFixture->item4Height, $this->itemFixture->item4Breadth, $this->itemFixture->item4Weight), + new Item($this->itemFixture->item5Id, $this->itemFixture->item5Length, $this->itemFixture->item5Height, $this->itemFixture->item5Breadth, $this->itemFixture->item5Weight), + new Item($this->itemFixture->item6Id, $this->itemFixture->item6Length, $this->itemFixture->item6Height, $this->itemFixture->item6Breadth, $this->itemFixture->item6Weight), + new Item($this->itemFixture->item7Id, $this->itemFixture->item7Length, $this->itemFixture->item7Height, $this->itemFixture->item7Breadth, $this->itemFixture->item7Weight), + new Item($this->itemFixture->item8Id, $this->itemFixture->item8Length, $this->itemFixture->item8Height, $this->itemFixture->item8Breadth, $this->itemFixture->item8Weight), + new Item($this->itemFixture->item9Id, $this->itemFixture->item9Length, $this->itemFixture->item9Height, $this->itemFixture->item9Breadth, $this->itemFixture->item9Weight), + new Item($this->itemFixture->item10Id, $this->itemFixture->item10Length, $this->itemFixture->item10Height, $this->itemFixture->item10Breadth, $this->itemFixture->item10Weight), + ]); + + $this->packager->withHeaviestFirst()->pack(); + + $resultedBins = $this->packager->getBins(); + + $this->assertCount(9, $resultedBins[$this->binFixture->bin2Id]->getFittedItems()); + $this->assertCount(0, $resultedBins[$this->binFixture->bin1Id]->getFittedItems()); + $this->assertCount(1, $resultedBins[$this->binFixture->bin2Id]->getUnfittedItems()); + $this->assertCount(1, $resultedBins[$this->binFixture->bin1Id]->getUnfittedItems()); + } + /** * The tear down test environment method. *