Snap belt-drag end tile to a building's input edge
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <QPoint>
|
||||
@@ -1421,3 +1423,106 @@ TEST_CASE("BuildingSystem: getProductionStatus classifies production state", "[b
|
||||
REQUIRE(statusOf(bay) == ProductionStatus::Producing); // holding scrap -> green
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// getInputPorts (REQ-BLD-BELT-DRAG snapping, REQ-MAT-INPUT-PORTS)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
QPoint directionDelta(Rotation direction)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case Rotation::North: return QPoint(0, -1);
|
||||
case Rotation::East: return QPoint(1, 0);
|
||||
case Rotation::South: return QPoint(0, 1);
|
||||
case Rotation::West: return QPoint(-1, 0);
|
||||
}
|
||||
return QPoint(0, 0);
|
||||
}
|
||||
|
||||
bool hasInputPort(const std::vector<Port>& ports, QPoint tile, Rotation direction)
|
||||
{
|
||||
for (const Port& port : ports)
|
||||
{
|
||||
if (port.tile == tile && port.direction == direction) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Advances the sim until the given site becomes an operational building, or a
|
||||
// safety cap is reached.
|
||||
void buildToCompletion(BuildingSystem& bs, BeltSystem& belts, BuildingId id,
|
||||
Tick& tick)
|
||||
{
|
||||
for (int i = 0; i < 20000 && bs.findBuilding(id) == nullptr; ++i)
|
||||
{
|
||||
runTicks(bs, belts, 1, tick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("BuildingSystem: getInputPorts on a miner site lists every input edge", "[building]")
|
||||
{
|
||||
PlacementFixture f;
|
||||
// Miner mask ["AA","A>"] East → body (0,0),(1,0),(0,1); output tile (1,1) East.
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
const std::vector<Port> ports = f.bs.getInputPorts(id);
|
||||
|
||||
// Every perimeter edge except the output-port edge at (1,1), each pointing in.
|
||||
REQUIRE(ports.size() == 6);
|
||||
REQUIRE(hasInputPort(ports, QPoint(-1, 0), Rotation::East));
|
||||
REQUIRE(hasInputPort(ports, QPoint(0, -1), Rotation::South));
|
||||
REQUIRE(hasInputPort(ports, QPoint(2, 0), Rotation::West));
|
||||
REQUIRE(hasInputPort(ports, QPoint(1, -1), Rotation::South));
|
||||
REQUIRE(hasInputPort(ports, QPoint(-1, 1), Rotation::East));
|
||||
REQUIRE(hasInputPort(ports, QPoint(0, 2), Rotation::North));
|
||||
|
||||
// The output-port tile is never an input port.
|
||||
REQUIRE_FALSE(hasInputPort(ports, QPoint(1, 1), Rotation::North));
|
||||
REQUIRE_FALSE(hasInputPort(ports, QPoint(1, 1), Rotation::West));
|
||||
}
|
||||
|
||||
TEST_CASE("BuildingSystem: getInputPorts matches between a site and the built building",
|
||||
"[building]")
|
||||
{
|
||||
PlacementFixture f;
|
||||
Tick tick = 0;
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
const std::vector<Port> sitePorts = f.bs.getInputPorts(id);
|
||||
buildToCompletion(f.bs, f.belts, id, tick);
|
||||
REQUIRE(f.bs.findBuilding(id) != nullptr);
|
||||
const std::vector<Port> builtPorts = f.bs.getInputPorts(id);
|
||||
|
||||
// The operational path (stored inputPorts) agrees with the site path (mask-derived).
|
||||
REQUIRE(builtPorts.size() == sitePorts.size());
|
||||
for (const Port& port : sitePorts)
|
||||
{
|
||||
REQUIRE(hasInputPort(builtPorts, port.tile, port.direction));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("BuildingSystem: getInputPorts invariants hold for a rotated site", "[building]")
|
||||
{
|
||||
PlacementFixture f;
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::South, 0).value();
|
||||
const ConstructionSite* site = f.bs.findSite(id);
|
||||
REQUIRE(site != nullptr);
|
||||
|
||||
std::set<std::pair<int, int>> bodySet;
|
||||
for (const QPoint& cell : site->bodyCells) { bodySet.insert({cell.x(), cell.y()}); }
|
||||
|
||||
const std::vector<Port> ports = f.bs.getInputPorts(id);
|
||||
REQUIRE_FALSE(ports.empty());
|
||||
for (const Port& port : ports)
|
||||
{
|
||||
// Each port tile is outside the footprint...
|
||||
REQUIRE(bodySet.count({port.tile.x(), port.tile.y()}) == 0);
|
||||
// ...and its direction points into an adjacent body cell.
|
||||
const QPoint into = port.tile + directionDelta(port.direction);
|
||||
REQUIRE(bodySet.count({into.x(), into.y()}) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user