diff --git a/src/lib/sim/BeltSystem.cpp b/src/lib/sim/BeltSystem.cpp index 8167574..5e74bbe 100644 --- a/src/lib/sim/BeltSystem.cpp +++ b/src/lib/sim/BeltSystem.cpp @@ -119,19 +119,13 @@ std::optional BeltSystem::tryTakeItem(Port port) } BeltTile& bt = it->second; - if (bt.front) + if (bt.front && bt.front->progress >= 1.0) { const Item taken = bt.front->item; bt.front = bt.back; bt.back = std::nullopt; return taken; } - if (bt.back) - { - const Item taken = bt.back->item; - bt.back = std::nullopt; - return taken; - } return std::nullopt; } @@ -149,14 +143,10 @@ std::optional BeltSystem::peekItem(Port port) const } const BeltTile& bt = it->second; - if (bt.front) + if (bt.front && bt.front->progress >= 1.0) { return bt.front->item.type; } - if (bt.back) - { - return bt.back->item.type; - } return std::nullopt; } diff --git a/src/test/BeltSystemTest.cpp b/src/test/BeltSystemTest.cpp index a6befc9..f52eaa5 100644 --- a/src/test/BeltSystemTest.cpp +++ b/src/test/BeltSystemTest.cpp @@ -101,12 +101,13 @@ TEST_CASE("BeltSystem: third tryPutItem on full tile returns false", "[belt]") // tryTakeItem // --------------------------------------------------------------------------- -TEST_CASE("BeltSystem: tryTakeItem returns placed item", "[belt]") +TEST_CASE("BeltSystem: tryTakeItem returns placed item after reaching output edge", "[belt]") { BeltSystem bs(kFastBeltSpeed); const QPoint tile(0, 0); bs.placeBelt(tile, Rotation::East); bs.tryPutItem(eastPort(tile), makeItem("iron_ore")); + bs.tick(); // advance to output edge const std::optional taken = bs.tryTakeItem(eastPort(tile)); @@ -114,7 +115,23 @@ TEST_CASE("BeltSystem: tryTakeItem returns placed item", "[belt]") REQUIRE(taken->type.id == "iron_ore"); } -TEST_CASE("BeltSystem: tryTakeItem with two items returns both in sequence", "[belt]") +TEST_CASE("BeltSystem: tryTakeItem requires item to reach output edge before yielding", "[belt]") +{ + BeltSystem bs(kFastBeltSpeed); + const QPoint tile(0, 0); + bs.placeBelt(tile, Rotation::East); + bs.tryPutItem(eastPort(tile), makeItem("iron_ore")); + + // Item placed but not yet at output edge — must not be available. + REQUIRE_FALSE(bs.tryTakeItem(eastPort(tile)).has_value()); + REQUIRE_FALSE(bs.peekItem(eastPort(tile)).has_value()); + + // After one tick the item has reached progress 1.0 and is available. + bs.tick(); + REQUIRE(bs.tryTakeItem(eastPort(tile)).has_value()); +} + +TEST_CASE("BeltSystem: tryTakeItem with two items returns both after each reaches output edge", "[belt]") { BeltSystem bs(kFastBeltSpeed); const QPoint tile(0, 0); @@ -122,15 +139,16 @@ TEST_CASE("BeltSystem: tryTakeItem with two items returns both in sequence", "[b bs.tryPutItem(eastPort(tile), makeItem("first")); bs.tryPutItem(eastPort(tile), makeItem("second")); - // First take returns front item (first placed, higher progress). + // Front item reaches output edge after one tick. + bs.tick(); const std::optional taken1 = bs.tryTakeItem(eastPort(tile)); REQUIRE(taken1.has_value()); - // Second take returns the remaining item. + // Back item (now promoted to front) needs another tick to reach output edge. + bs.tick(); const std::optional taken2 = bs.tryTakeItem(eastPort(tile)); REQUIRE(taken2.has_value()); - // Tile is now empty. REQUIRE_FALSE(bs.tryTakeItem(eastPort(tile)).has_value()); } @@ -156,7 +174,7 @@ TEST_CASE("BeltSystem: tryTakeItem returns nullopt on direction mismatch", "[bel // tick() — item advancement // --------------------------------------------------------------------------- -TEST_CASE("BeltSystem: one tick moves item from tile A to tile B in a 2-tile chain", "[belt]") +TEST_CASE("BeltSystem: item transfers from tile A to tile B and becomes available after two ticks", "[belt]") { BeltSystem bs(kFastBeltSpeed); const QPoint tileA(0, 0); @@ -165,9 +183,9 @@ TEST_CASE("BeltSystem: one tick moves item from tile A to tile B in a 2-tile cha bs.placeBelt(tileB, Rotation::East); bs.tryPutItem(eastPort(tileA), makeItem("iron_ore")); - bs.tick(); + bs.tick(); // item reaches output edge of A, moves to B at progress 0 + bs.tick(); // item reaches output edge of B - // Item should have moved to tileB. REQUIRE_FALSE(bs.tryTakeItem(eastPort(tileA)).has_value()); const std::optional inB = bs.tryTakeItem(eastPort(tileB)); REQUIRE(inB.has_value()); @@ -187,7 +205,7 @@ TEST_CASE("BeltSystem: item stays at progress 1.0 when next tile is absent", "[b REQUIRE(bs.tryTakeItem(eastPort(tileA)).has_value()); } -TEST_CASE("BeltSystem: item traverses 3-tile chain in 2 ticks", "[belt]") +TEST_CASE("BeltSystem: item traverses 3-tile chain in 3 ticks (one per tile)", "[belt]") { BeltSystem bs(kFastBeltSpeed); const QPoint tileA(0, 0); @@ -198,8 +216,9 @@ TEST_CASE("BeltSystem: item traverses 3-tile chain in 2 ticks", "[belt]") bs.placeBelt(tileC, Rotation::East); bs.tryPutItem(eastPort(tileA), makeItem("iron_ore")); - bs.tick(); // A -> B - bs.tick(); // B -> C + bs.tick(); // A output edge → moves to B at progress 0 + bs.tick(); // B output edge → moves to C at progress 0 + bs.tick(); // C output edge → available for pickup REQUIRE_FALSE(bs.tryTakeItem(eastPort(tileA)).has_value()); REQUIRE_FALSE(bs.tryTakeItem(eastPort(tileB)).has_value());