implement building system

This commit is contained in:
2026-04-19 20:50:42 +02:00
parent c70b5c8f08
commit bf29cc40e3
19 changed files with 1818 additions and 7 deletions

View File

@@ -0,0 +1,184 @@
#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));
}