Skip to content

Commit

Permalink
Add a testcase for positionally constraining stacking
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdoug committed Dec 2, 2018
1 parent 2dbe6c8 commit a97a78f
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 9 deletions.
Expand Up @@ -15,7 +15,7 @@
use function count;
use function iterator_to_array;

class TestConstrainedTestItem extends TestItem implements ConstrainedItem
class ConstrainedTestItem extends TestItem implements ConstrainedItem
{
/**
* @var int
Expand Down
Expand Up @@ -15,7 +15,7 @@
use DVDoug\BoxPacker\PositionallyConstrainedItem;
use function iterator_to_array;

class TestPositionallyConstrainedTestItem extends TestItem implements PositionallyConstrainedItem
class PositionallyConstrainedByCountTestItem extends TestItem implements PositionallyConstrainedItem
{
/**
* @var int
Expand Down
62 changes: 62 additions & 0 deletions tests/Test/PositionallyConstrainedNoStackingTestItem.php
@@ -0,0 +1,62 @@
<?php
/**
* Box packing (3D bin packing, knapsack problem).
*
* @author Doug Wright
*/
declare(strict_types=1);

namespace DVDoug\BoxPacker\Test;

use DVDoug\BoxPacker\Box;
use DVDoug\BoxPacker\PackedItem;
use DVDoug\BoxPacker\PackedItemList;
use function count;
use DVDoug\BoxPacker\PositionallyConstrainedItem;
use function iterator_to_array;

class PositionallyConstrainedNoStackingTestItem extends TestItem implements PositionallyConstrainedItem
{
/**
* Hook for user implementation of item-specific constraints, e.g. max <x> batteries per box.
*
* @param Box $box
* @param PackedItemList $alreadyPackedItems
* @param int $proposedX
* @param int $proposedY
* @param int $proposedZ
* @param int $width
* @param int $length
* @param int $depth
* @return bool
*/
public function canBePacked(
Box $box,
PackedItemList $alreadyPackedItems,
int $proposedX,
int $proposedY,
int $proposedZ,
int $width,
int $length,
int $depth
): bool {
$alreadyPackedType = array_filter(
iterator_to_array($alreadyPackedItems, false),
function (PackedItem $item) {
return $item->getItem()->getDescription() === $this->getDescription();
}
);

/** @var PackedItem $alreadyPacked */
foreach ($alreadyPackedType as $alreadyPacked) {
if (
$alreadyPacked->getZ() + $alreadyPacked->getDepth() === $proposedZ &&
$proposedX >= $alreadyPacked->getX() && $proposedX <= ($alreadyPacked->getX() + $alreadyPacked->getWidth()) &&
$proposedY >= $alreadyPacked->getY() && $proposedY <= ($alreadyPacked->getY() + $alreadyPacked->getLength())) {
return false;
}
}

return true;
}
}
38 changes: 31 additions & 7 deletions tests/VolumePackerTest.php
Expand Up @@ -8,10 +8,11 @@

namespace DVDoug\BoxPacker;

use DVDoug\BoxPacker\Test\PositionallyConstrainedNoStackingTestItem;
use DVDoug\BoxPacker\Test\TestBox;
use DVDoug\BoxPacker\Test\TestConstrainedTestItem;
use DVDoug\BoxPacker\Test\ConstrainedTestItem;
use DVDoug\BoxPacker\Test\TestItem;
use DVDoug\BoxPacker\Test\TestPositionallyConstrainedTestItem;
use DVDoug\BoxPacker\Test\PositionallyConstrainedByCountTestItem;
use PHPUnit\Framework\TestCase;

/**
Expand Down Expand Up @@ -78,11 +79,11 @@ public function testLegacyConstraints(): void
self::assertCount(1, $packedBoxes);

// same dimensions but now constrained by type
TestConstrainedTestItem::$limit = 2;
ConstrainedTestItem::$limit = 2;

$packer = new Packer();
$packer->addBox(new TestBox('Box', 10, 10, 10, 0, 10, 10, 10, 0));
$packer->addItem(new TestConstrainedTestItem('Item', 1, 1, 1, 0, false), 8);
$packer->addItem(new ConstrainedTestItem('Item', 1, 1, 1, 0, false), 8);
$packedBoxes = $packer->pack();

self::assertCount(4, $packedBoxes);
Expand All @@ -91,7 +92,7 @@ public function testLegacyConstraints(): void
/**
* Test that constraint handling works correctly.
*/
public function testConstraints(): void
public function testNewConstraintMatchesLegacy(): void
{
// first a regular item
$packer = new Packer();
Expand All @@ -102,16 +103,39 @@ public function testConstraints(): void
self::assertCount(1, $packedBoxes);

// same dimensions but now constrained by type
TestPositionallyConstrainedTestItem::$limit = 2;
PositionallyConstrainedByCountTestItem::$limit = 2;

$packer = new Packer();
$packer->addBox(new TestBox('Box', 10, 10, 10, 0, 10, 10, 10, 0));
$packer->addItem(new TestPositionallyConstrainedTestItem('Item', 1, 1, 1, 0, false), 8);
$packer->addItem(new PositionallyConstrainedByCountTestItem('Item', 1, 1, 1, 0, false), 8);
$packedBoxes = $packer->pack();

self::assertCount(4, $packedBoxes);
}

/**
* Test that constraint handling works correctly.
*/
public function testNewConstraint(): void
{
// first a regular item
$packer = new Packer();
$packer->addBox(new TestBox('Box', 4, 1, 2, 0, 4, 1, 2, 0));
$packer->addItem(new TestItem('Item', 1, 1, 1, 0, false), 8);
$packedBoxes = $packer->pack();

self::assertCount(1, $packedBoxes);

// same dimensions but now constrained to not have stacking

$packer = new Packer();
$packer->addBox(new TestBox('Box', 4, 1, 2, 0, 4, 1, 2, 0));
$packer->addItem(new PositionallyConstrainedNoStackingTestItem('Item', 1, 1, 1, 0, false), 8);
$packedBoxes = $packer->pack();

self::assertCount(2, $packedBoxes);
}

/**
* Test an infinite loop doesn't come back.
*/
Expand Down

0 comments on commit a97a78f

Please sign in to comment.