185 lines
6.5 KiB
C++
185 lines
6.5 KiB
C++
#include "catch.hpp"
|
||
|
||
#include <algorithm>
|
||
#include <vector>
|
||
|
||
#include <QPoint>
|
||
|
||
#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 ["<A>"] — 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({"<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() == 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<std::string> 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<std::string> 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));
|
||
}
|