#include "catch.hpp" #include #include #include #include "Port.h" #include "Rotation.h" #include "SurfaceMask.h" // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- static bool hasBodyCell(const ParsedSurfaceMask& mask, int x, int y) { const QPoint pt(x, y); return std::find(mask.bodyCells.begin(), mask.bodyCells.end(), pt) != mask.bodyCells.end(); } static bool hasOutputPort(const ParsedSurfaceMask& mask, int x, int y, Rotation dir) { for (const Port& port : mask.outputPorts) { if (port.tile == QPoint(x, y) && port.direction == dir) { return true; } } return false; } static bool hasShipDockCell(const ParsedSurfaceMask& mask, int x, int y) { const QPoint pt(x, y); return std::find(mask.shipDockCells.begin(), mask.shipDockCells.end(), pt) != mask.shipDockCells.end(); } // --------------------------------------------------------------------------- // Belt ["A>"] — 1×1 body, East output // --------------------------------------------------------------------------- TEST_CASE("SurfaceMask: belt East — 1 body cell, port at (1,0) East", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"A>"}, Rotation::East); REQUIRE(mask.footprint.width() == 1); REQUIRE(mask.footprint.height() == 1); REQUIRE(mask.bodyCells.size() == 1); REQUIRE(hasBodyCell(mask, 0, 0)); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, 1, 0, Rotation::East)); } TEST_CASE("SurfaceMask: belt South — body at (0,0), port at (0,1) South", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"A>"}, Rotation::South); REQUIRE(mask.bodyCells.size() == 1); REQUIRE(hasBodyCell(mask, 0, 0)); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, 0, 1, Rotation::South)); } TEST_CASE("SurfaceMask: belt West — body at (0,0), port at (-1,0) West", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"A>"}, Rotation::West); REQUIRE(mask.bodyCells.size() == 1); REQUIRE(hasBodyCell(mask, 0, 0)); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, -1, 0, Rotation::West)); } TEST_CASE("SurfaceMask: belt North — body at (0,0), port at (0,-1) North", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"A>"}, Rotation::North); REQUIRE(mask.bodyCells.size() == 1); REQUIRE(hasBodyCell(mask, 0, 0)); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, 0, -1, Rotation::North)); } // --------------------------------------------------------------------------- // Miner ["AA", "A>"] — 3 body cells, East output // --------------------------------------------------------------------------- TEST_CASE("SurfaceMask: miner East — 3 body cells, port at (1,1) East, footprint 2×2", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"AA", "A>"}, Rotation::East); REQUIRE(mask.footprint.width() == 2); REQUIRE(mask.footprint.height() == 2); REQUIRE(mask.bodyCells.size() == 3); REQUIRE(hasBodyCell(mask, 0, 0)); REQUIRE(hasBodyCell(mask, 1, 0)); REQUIRE(hasBodyCell(mask, 0, 1)); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, 1, 1, Rotation::East)); } TEST_CASE("SurfaceMask: miner South — port faces South", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"AA", "A>"}, Rotation::South); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(mask.outputPorts[0].direction == Rotation::South); } TEST_CASE("SurfaceMask: miner West — port faces West", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"AA", "A>"}, Rotation::West); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(mask.outputPorts[0].direction == Rotation::West); } TEST_CASE("SurfaceMask: miner North — port faces North", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({"AA", "A>"}, Rotation::North); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(mask.outputPorts[0].direction == Rotation::North); } // --------------------------------------------------------------------------- // Splitter [""] — 1 body cell, West + East outputs // --------------------------------------------------------------------------- TEST_CASE("SurfaceMask: splitter East — 1 body cell, ports at (-1,0) West and (1,0) East", "[surface_mask]") { const ParsedSurfaceMask mask = parseSurfaceMask({""}, Rotation::East); REQUIRE(mask.footprint.width() == 1); REQUIRE(mask.footprint.height() == 1); REQUIRE(mask.bodyCells.size() == 1); REQUIRE(hasBodyCell(mask, 0, 0)); REQUIRE(mask.outputPorts.size() == 2); REQUIRE(hasOutputPort(mask, -1, 0, Rotation::West)); REQUIRE(hasOutputPort(mask, 1, 0, Rotation::East)); } // --------------------------------------------------------------------------- // Shipyard ["AAAS>", "AAAS "] — 6 A + 2 S body cells, 1 port // --------------------------------------------------------------------------- TEST_CASE("SurfaceMask: shipyard East — 6 A bodyCells, 2 S shipDockCells, port at (4,0) East", "[surface_mask]") { const std::vector rows = {"AAAS>", "AAAS "}; const ParsedSurfaceMask mask = parseSurfaceMask(rows, Rotation::East); REQUIRE(mask.footprint.width() == 4); REQUIRE(mask.footprint.height() == 2); REQUIRE(mask.bodyCells.size() == 8); // 6 A + 2 S REQUIRE(mask.shipDockCells.size() == 2); REQUIRE(hasShipDockCell(mask, 3, 0)); REQUIRE(hasShipDockCell(mask, 3, 1)); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, 4, 0, Rotation::East)); } // --------------------------------------------------------------------------- // Assembler ["AAA ", "AAA>", "AAA "] — 9 body cells, East output // --------------------------------------------------------------------------- TEST_CASE("SurfaceMask: assembler East — 9 body cells, port at (3,1) East, footprint 3×3", "[surface_mask]") { const std::vector rows = {"AAA ", "AAA>", "AAA "}; const ParsedSurfaceMask mask = parseSurfaceMask(rows, Rotation::East); REQUIRE(mask.footprint.width() == 3); REQUIRE(mask.footprint.height() == 3); REQUIRE(mask.bodyCells.size() == 9); REQUIRE(mask.outputPorts.size() == 1); REQUIRE(hasOutputPort(mask, 3, 1, Rotation::East)); }