/**
 * @brief Testet das Ausführen einer Bauoperation, die nicht komplett ausgeführt werden kann, weil das
 * Baumaterial nicht reicht.
 *
 * Baue 5 Rumbrennereien, wobei die Resourcen nur für 3 reichen
 */
TEST_F(BuildOperationTest, partialBuildOutOfResources) {
    const MapObjectType* distillery = configMgr->getMapObjectType("distillery");

    // Testaufbau
    player->coins = 2000;
    colony->getGoods(configMgr->getGood("tools")).inventory = 11;
    colony->getGoods(configMgr->getGood("wood")).inventory = 20;
    colony->getGoods(configMgr->getGood("bricks")).inventory = 30;

    BuildOperation buildOperation(context, *player);
    buildOperation.requestBuildWhenNothingInTheWay({39, 34}, distillery, Direction::SOUTH);
    buildOperation.requestBuildWhenNothingInTheWay({39, 37}, distillery, Direction::SOUTH);
    buildOperation.requestBuildWhenNothingInTheWay({39, 39}, distillery, Direction::SOUTH);
    buildOperation.requestBuildWhenNothingInTheWay({37, 37}, distillery, Direction::SOUTH);
    buildOperation.requestBuildWhenNothingInTheWay({37, 39}, distillery, Direction::SOUTH);
    buildOperation.doBuild();

    // Testauswertung: Resourcen korrekt abgezogen
    ASSERT_EQ(1400, player->coins);
    ASSERT_EQ(2, colony->getGoods(configMgr->getGood("tools")).inventory);
    ASSERT_EQ(14, colony->getGoods(configMgr->getGood("wood")).inventory);
    ASSERT_EQ(15, colony->getGoods(configMgr->getGood("bricks")).inventory);

    // Testauswertung: Gebäude in die Map übernommen
    assertCorrectBuild({39, 34}, distillery, Direction::SOUTH, 2, 2);
    assertCorrectBuild({39, 37}, distillery, Direction::SOUTH, 2, 2);
    assertCorrectBuild({39, 39}, distillery, Direction::SOUTH, 2, 2);
    ASSERT_TRUE(game->getMap()->getMapObjectFixedAt({37, 37}) == nullptr);
    ASSERT_TRUE(game->getMap()->getMapObjectFixedAt({37, 39}) == nullptr);
}
/**
 * @brief Spezialtest "halbe Kreuzung"
 *
 * Wir bauen einen Feldweg von (46, 31) nach (46, 33).
 * Allerdings reicht das Geld nur für eine Kachel.
 *
 * Wir erwarten, dass beim Bau nur ein T-Stück entsteht, obwohl eine Kreuzung gezogen wurde.
 */
TEST_F(BuildOperationTest, partialCrossroads) {
    const Map* map = game->getMap();
    const MapObjectType* farmRoad = configMgr->getMapObjectType("farm-road");

    // Testaufbau
    player->coins = 5;

    BuildOperation buildOperation(context, *player);
    for (int y = 31; y <= 33; y++) {
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(46, y), farmRoad, Direction::SOUTH);
    }
    buildOperation.doBuild();

    // Testauswertung
    ASSERT_EQ(0, player->coins);

    assertCorrectBuild({46, 31}, farmRoad, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_SOUTH,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 31}))->streetConnections);

    assertCorrectBuild({46, 32}, farmRoad, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_WEST,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 32}))->streetConnections);

    ASSERT_TRUE(map->getMapObjectFixedAt({46, 33}) == nullptr);
}
/**
 * @brief Testet das Ausführen einer einfachen Bauoperation.
 */
TEST_F(BuildOperationTest, regularBuild) {
    const MapObjectType* marketplace = configMgr->getMapObjectType("marketplace");

    // Testaufbau
    player->coins = 5000;
    colony->getGoods(configMgr->getGood("tools")).inventory = 20;
    colony->getGoods(configMgr->getGood("wood")).inventory = 40;
    colony->getGoods(configMgr->getGood("bricks")).inventory = 30;

    BuildOperation buildOperation(context, *player);
    buildOperation.requestBuildWhenNothingInTheWay(MapCoords(45, 33), marketplace, Direction::SOUTH);
    buildOperation.requestBuildWhenNothingInTheWay(MapCoords(37, 33), marketplace, Direction::NORTH);
    buildOperation.requestBuildWhenNothingInTheWay(MapCoords(38, 37), marketplace, Direction::WEST);
    buildOperation.doBuild();

    // Testauswertung: Resourcen korrekt abgezogen
    ASSERT_EQ(4400, player->coins);
    ASSERT_EQ(8, colony->getGoods(configMgr->getGood("tools")).inventory);
    ASSERT_EQ(10, colony->getGoods(configMgr->getGood("wood")).inventory);
    ASSERT_EQ(30, colony->getGoods(configMgr->getGood("bricks")).inventory);

    // Testauswertung: Gebäude in die Map übernommen
    assertCorrectBuild({45, 33}, marketplace, Direction::SOUTH, 4, 3);
    assertCorrectBuild({37, 33}, marketplace, Direction::NORTH, 4, 3);
    assertCorrectBuild({38, 37}, marketplace, Direction::WEST, 3, 4);
}
/**
 * @brief Testet das Ausführen einer Bauoperation, die Straßen überbaut bzw. anpasst
 *
 * Ziehe Straßenzug von (46, 31) nach (46, 36).
 * 4 Kacheln kommen neu dazu, 2 werden überbaut (wovon nur eine was kostet).
 */
TEST_F(BuildOperationTest, overbuildAndAdeptStreet) {
    const Map* map = game->getMap();

    const MapObjectType* farmRoad = configMgr->getMapObjectType("farm-road");
    const MapObjectType* cobbledStreet = configMgr->getMapObjectType("cobbled-street");

    // Testaufbau
    player->coins = 1000;
    colony->getGoods(configMgr->getGood("tools")).inventory = 10;
    colony->getGoods(configMgr->getGood("wood")).inventory = 20;
    colony->getGoods(configMgr->getGood("bricks")).inventory = 25;

    BuildOperation buildOperation(context, *player);
    for (int y = 31; y <= 36; y++) {
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(46, y), cobbledStreet, Direction::SOUTH);
    }

    unsigned long mapObjectsCountBefore = game->getMap()->getMapObjects().size();
    buildOperation.doBuild();
    unsigned long mapObjectsCountAfter = game->getMap()->getMapObjects().size();

    // Testauswertung: Sicherstellen, dass die Anzahl der Map-Objekte stimmt.
    // Nicht, dass es zwei Map-Objekte auf derselben Koordinate gibt
    ASSERT_EQ(mapObjectsCountBefore + 4, mapObjectsCountAfter);

    // Testauswertung: Resourcen korrekt abgezogen (nur 5 der 6 Kacheln kosten was)
    ASSERT_EQ(975, player->coins);
    ASSERT_EQ(10, colony->getGoods(configMgr->getGood("tools")).inventory);
    ASSERT_EQ(20, colony->getGoods(configMgr->getGood("wood")).inventory);
    ASSERT_EQ(20, colony->getGoods(configMgr->getGood("bricks")).inventory);

    // Testauswertung: Straßen in die Map übernommen bzw. angepasst
    assertCorrectBuild({46, 31}, cobbledStreet, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_SOUTH,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 31}))->streetConnections);

    assertCorrectBuild({46, 32}, cobbledStreet, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_EAST |
              StreetConnections::BIT_MASK_SOUTH | StreetConnections::BIT_MASK_WEST,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 32}))->streetConnections);

    for (int y = 33; y <= 35; y++) {
        assertCorrectBuild({ 46, y }, cobbledStreet, Direction::SOUTH, 1, 1);
        ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_SOUTH,
                  dynamic_cast<const Street*>(map->getMapObjectFixedAt({ 46, y }))->streetConnections);
    }

    assertCorrectBuild({46, 36}, cobbledStreet, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_NORTH | StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_WEST,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({46, 36}))->streetConnections);

    assertCorrectBuild({45, 32}, farmRoad, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_WEST,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({45, 32}))->streetConnections);

    assertCorrectBuild({47, 32}, farmRoad, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_WEST,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({47, 32}))->streetConnections);
}
/**
 * @brief Überprüft, ob korrekt erkannt wird, wenn was im Weg is
 */
TEST_F(BuildOperationTest, somethingInTheWay) {
    const MapObjectType* tavern = configMgr->getMapObjectType("tavern");

    {
        // Wirtshaus normal einsetzen: genug Platz
        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuild(MapCoords(45, 33), tavern, Direction::SOUTH);
        const BuildOperationResult& result = buildOperation.getResult();
        ASSERT_EQ(BuildOperationResult::OK, result.result);
        ASSERT_EQ(6, result.size());
        ASSERT_EQ(true, result.at(MapCoords(46, 35))->buildAllowed);
    }

    {
        // Wirtshaus gedreht einsetzen: genug Platz
        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuild(MapCoords(45, 33), tavern, Direction::WEST);
        const BuildOperationResult& result = buildOperation.getResult();
        ASSERT_EQ(BuildOperationResult::OK, result.result);
        ASSERT_EQ(6, result.size());
        ASSERT_EQ(true, result.at(MapCoords(47, 34))->buildAllowed);
    }

    {
        // Wirtshaus normal einsetzen: ein Feldweg im Weg
        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuild(MapCoords(39, 34), tavern, Direction::NORTH);
        const BuildOperationResult& result = buildOperation.getResult();
        ASSERT_EQ(BuildOperationResult::NOT_OK, result.result);
        ASSERT_EQ(6, result.size());
        ASSERT_EQ(false, result.at(MapCoords(40, 35))->buildAllowed);
    }

    {
        // Wirtshaus gedreht einsetzen: ein Feldweg im Weg
        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuild(MapCoords(38, 36), tavern, Direction::EAST);
        const BuildOperationResult& result = buildOperation.getResult();
        ASSERT_EQ(BuildOperationResult::NOT_OK, result.result);
        ASSERT_EQ(6, result.size());
        ASSERT_EQ(false, result.at(MapCoords(40, 37))->buildAllowed);
    }
}
/**
 * @brief Überprüft, ob die Baukosten korrekt berücksichtigt werden
 */
TEST_F(BuildOperationTest, buildingCosts) {
    const MapObjectType* toolsmiths = configMgr->getMapObjectType("toolsmiths");
    Colony* colony = game->getColony({ 43, 34 });

    {
        player->coins = 500;
        colony->getGoods(configMgr->getGood("tools")).inventory = 6;
        colony->getGoods(configMgr->getGood("wood")).inventory = 30;
        colony->getGoods(configMgr->getGood("bricks")).inventory = 20;

        BuildOperation buildOperation(context, *player);
        const MapCoords mc1 = { 45, 34 };
        const MapCoords mc2 = { 47, 34 };
        const MapCoords mc3 = { 39, 37 };

        // Erste Werkzeugschmiede setzen: Alle Rohstoffe reichen
        buildOperation.requestBuildWhenNothingInTheWay(mc1, toolsmiths, Direction::SOUTH);
        ASSERT_EQ(true, buildOperation.getResult().at(mc1)->resourcesEnoughToBuildThis);

        // Zweite Werkzeugschmiede hinzufügen: Rohstoffe reichen immer noch. Werkzeuge reichen exakt
        buildOperation.requestBuildWhenNothingInTheWay(mc2, toolsmiths, Direction::SOUTH);
        ASSERT_EQ(true, buildOperation.getResult().at(mc1)->resourcesEnoughToBuildThis);
        ASSERT_EQ(true, buildOperation.getResult().at(mc2)->resourcesEnoughToBuildThis);

        // Dritte Werkzeugschmiede hinzufügen: Werkzeuge reichen nicht mehr
        buildOperation.requestBuildWhenNothingInTheWay(mc3, toolsmiths, Direction::SOUTH);
        ASSERT_EQ(true, buildOperation.getResult().at(mc1)->resourcesEnoughToBuildThis);
        ASSERT_EQ(true, buildOperation.getResult().at(mc2)->resourcesEnoughToBuildThis);
        ASSERT_EQ(false, buildOperation.getResult().at(mc3)->resourcesEnoughToBuildThis);
    }

    {
        // Geld reicht nicht
        player->coins = 100;
        colony->getGoods(configMgr->getGood("tools")).inventory = 3;
        colony->getGoods(configMgr->getGood("wood")).inventory = 2;
        colony->getGoods(configMgr->getGood("bricks")).inventory = 5;

        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuildWhenNothingInTheWay({38, 40}, toolsmiths, Direction::SOUTH);
        ASSERT_EQ(false, buildOperation.getResult().at({38, 40})->resourcesEnoughToBuildThis);
    }
}
/**
 * @brief Fügt einen Abreißauftrag der Queue hinzu und prüft, ob alle betroffenen Kacheln als "zu entfernen"
 * markiert werden
 */
TEST_F(BuildOperationTest, demolishMapObject) {
    BuildOperation buildOperation(context, *player);
    buildOperation.requestDemolish(*context.game->getMap()->getMapObjectFixedAt({48, 40}));

    BuildOperationResult result = buildOperation.getResult();
    ASSERT_EQ(BuildOperationResult::OK, result.result);
    ASSERT_EQ(4, result.size());
    ASSERT_EQ(true, result.at(MapCoords(48, 40))->deleteMapObjectThere);
    ASSERT_EQ(true, result.at(MapCoords(49, 40))->deleteMapObjectThere);
    ASSERT_EQ(true, result.at(MapCoords(48, 41))->deleteMapObjectThere);
    ASSERT_EQ(true, result.at(MapCoords(49, 41))->deleteMapObjectThere);
}
/**
 * @brief Überprüft, dass wir auch mit einer leeren Buildqueue zurechtkommen.
 */
TEST_F(BuildOperationTest, emptyBuildQueue) {
    const MapObjectType* pioneersHouse1 = configMgr->getMapObjectType("pioneers-house1");

    BuildOperation buildOperation(context, *player);
    buildOperation.requestBuildWhenNothingInTheWay({47, 39}, pioneersHouse1, Direction::NORTH); // da is belegt

    buildOperation.updateBuildMaterials(); // rebuildResult() triggern

    ASSERT_TRUE(buildOperation.getMapObjectsToBuild().empty());
    ASSERT_TRUE(buildOperation.getResult().empty());
    ASSERT_EQ(BuildOperationResult::OK, buildOperation.getResult().result);
}
Example #9
0
listItem* buildOperationList(){
	unsigned int i_lineNumber = 1;
	void	*currentOperation;
	listItem *currListOperation = (listItem*) malloc(sizeof(listItem));
	listItem *startOfList = currListOperation;
	char s[1024];

	memset(currListOperation, 0, sizeof(listItem));
	memset(s, 0, 1024);

	while(fgets(s, 1024, g_fdDataFile) != NULL) {
		char	*s_operation, *s_argument;
		int i = 0;
		char *last, *tok[6];
		unsigned int i_fileDescriptor = 0;

		s[ strlen(s) - 1 ] = '\0';

		tok[0] = strtok(s, ",");
		while (tok[++i] = strtok(NULL, ","));

		s_operation = tok[0];
		i_fileDescriptor = atoi( tok[1] );
		s_argument = tok[2];

		currentOperation = buildOperation(s_operation,
					i_fileDescriptor,
					s_argument,
					i_lineNumber);

		if (currentOperation != NULL) {
			listItem	*t = (listItem*) malloc(sizeof(listItem));
			(*t).item = NULL;
			(*t).next = NULL;

			(*currListOperation).item = currentOperation;

			(*currListOperation).next = t;
			(*t).prev = currListOperation;
			currListOperation = t;
		}
		else {
			printf("[WARNING] Unrecognized operation line %d [%s]\n", i_lineNumber, (s == NULL ? "null" : s) );
		}

		i_lineNumber ++;
		memset(s, 0, 1024);
	}
	fclose(g_fdDataFile);
	return startOfList;
}
/**
 * @brief Überprüft, ob Überlappungen beim Hinzufügen von Bauaufträgen korrekt erkannt werden.
 */
TEST_F(BuildOperationTest, overlappingRequestBuild) {
    const MapObjectType* marketplace = configMgr->getMapObjectType("marketplace");

    {
        // Ersten Marktplatz setzen
        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(45, 33), marketplace, Direction::SOUTH);
        ASSERT_EQ(12, buildOperation.getResult().size());

        // Weiteren Marktplatz überlappen -> es darf sich nix tun
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(48, 32), marketplace, Direction::WEST);
        ASSERT_EQ(12, buildOperation.getResult().size());

        // Weiteren Marktplatz überlappen über Bauqueue und bestehendes Objekt  -> es darf sich auch nix tun
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(43, 31), marketplace, Direction::WEST);
        ASSERT_EQ(12, buildOperation.getResult().size());

        // Weiteren Marktplatz korrekt hinzufügen
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(49, 33), marketplace, Direction::EAST);
        ASSERT_EQ(24, buildOperation.getResult().size());
    }

    {
        const MapCoords mapCoords(47, 39);

        // Mit requestBuildWhenNothingInTheWay darf ich auf der Karte nicht überlappen
        BuildOperation buildOperation(context, *player);
        buildOperation.requestBuildWhenNothingInTheWay(mapCoords, marketplace, Direction::SOUTH);
        ASSERT_EQ(0, buildOperation.getResult().size());

        // Mit requestBuild schon
        buildOperation.requestBuild(mapCoords, marketplace, Direction::SOUTH);
        ASSERT_EQ(12, buildOperation.getResult().size());
    }

}
/**
 * @brief Test, der Straßenanpassung testet, wenn die Resourcen nicht mehr reichen.
 * Beim Bau dürfen nur Ersetzungen vorgenommen werden, die angrenzen an Straßen, wofür die Resourcen reichen.
 *
 * Wir bauen einen Feldweg von (43, 44) nach (47, 44).
 * Allerdings reicht das Geld nur für zwei Kacheln.
 */
TEST_F(BuildOperationTest, adeptStreetsOutOfResources) {
    const Map* map = game->getMap();
    const MapObjectType* farmRoad = configMgr->getMapObjectType("farm-road");
    const MapObjectType* cobbledStreet = configMgr->getMapObjectType("cobbled-street");

    // Testaufbau
    player->coins = 10;

    BuildOperation buildOperation(context, *player);
    for (int x = 43; x <= 47; x++) {
        buildOperation.requestBuildWhenNothingInTheWay(MapCoords(x, 44), farmRoad, Direction::SOUTH);
    }
    buildOperation.doBuild();

    // Testauswertung

    // Resourcen korrekt nur für 2 Kacheln abgezogen
    ASSERT_EQ(0, player->coins);

    // Bau korrekt
    assertCorrectBuild({43, 44}, farmRoad, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_EAST | StreetConnections::BIT_MASK_SOUTH,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({43, 44}))->streetConnections);

    assertCorrectBuild({44, 44}, farmRoad, Direction::SOUTH, 1, 1);

    for (int x = 45; x <= 47; x++) {
        ASSERT_TRUE(game->getMap()->getMapObjectFixedAt({x, 44}) == nullptr);
    }

    // partielle Anpassung an (44, 44): nur West! Für die Ost-Verbindung reichen die Resourcen nicht
    ASSERT_EQ(StreetConnections::BIT_MASK_WEST,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({44, 44}))->streetConnections);

    // Anpassung an (43, 45)
    assertCorrectBuild({43, 45}, cobbledStreet, Direction::SOUTH, 1, 1);
    ASSERT_EQ(StreetConnections::BIT_MASK_NORTH,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({43, 45}))->streetConnections);

    // Keine Anpassungen an (45, 45), (47, 45), (47, 43), da die Resourcen nicht reichen
    ASSERT_EQ(0, dynamic_cast<const Street*>(map->getMapObjectFixedAt({45, 45}))->streetConnections);
    ASSERT_EQ(0, dynamic_cast<const Street*>(map->getMapObjectFixedAt({47, 45}))->streetConnections);
    ASSERT_EQ(StreetConnections::BIT_MASK_NORTH,
              dynamic_cast<const Street*>(map->getMapObjectFixedAt({47, 43}))->streetConnections);
}
/**
 * @brief Überprüft, dass beim Bau von Häusern sich bereits bestehende Häuser nicht ändern, wenn wir
 * ein weiteres hinzufügen.
 */
TEST_F(BuildOperationTest, addingOneMoreHouse) {
    // Testaufbau

    const MapObjectType* pioneersHouse1 = configMgr->getMapObjectType("pioneers-house1");
    const std::forward_list<MapCoords> mapCoordsToBuildThere = {
        {38, 32}, {38, 34}, {38, 36}, {38, 38}, {38, 40}, {38, 42},
        {36, 33}, {36, 35}, {36, 37}, {36, 39},
        {45, 33}, {47, 34}, {49, 33}, {51, 35}, {51, 37}, {52, 39}, {54, 39}
    };

    Colony* colony = game->getColony({ 43, 34 });
    colony->getGoods(configMgr->getGood("wood")).inventory = 65;

    // Testdurchführung: Baue viele Häuser, baue danach ein weiteres. Es dürfen sich bestehende nicht ändern.

    BuildOperation buildOperation(context, *player);
    for (const MapCoords& mapCoords : mapCoordsToBuildThere) {
        buildOperation.requestBuildWhenNothingInTheWay(mapCoords, pioneersHouse1, Direction::SOUTH);
    };
    BuildOperationResult resultBefore = buildOperation.getResult();

    const MapCoords mapCoordsToBuildAfter = {43, 29};
    buildOperation.requestBuildWhenNothingInTheWay(mapCoordsToBuildAfter, pioneersHouse1, Direction::SOUTH);
    BuildOperationResult resultAfter = buildOperation.getResult();

    // Testauswertung

    ASSERT_EQ(68, resultBefore.size());
    ASSERT_EQ(72, resultAfter.size());

    for (const MapCoords& mapCoords : mapCoordsToBuildThere) {
        const MapObjectType* mapObjectTypeBefore =
            resultBefore.at(mapCoords)->mapObjectToReplaceWith->getMapObjectType();
        const MapObjectType* mapObjectTypeAfter =
            resultAfter.at(mapCoords)->mapObjectToReplaceWith->getMapObjectType();

        ASSERT_EQ(mapObjectTypeBefore, mapObjectTypeAfter) << "mapCoords = " << ::testing::PrintToString(mapCoords);
    }

    ASSERT_TRUE(resultAfter.at(mapCoordsToBuildAfter)->mapObjectToReplaceWith != nullptr);
}
/**
 * @brief Überprüft, ob man die Objekte in der richtigen Reihenfolge wieder aus der Liste kriegt
 */
TEST_F(BuildOperationTest, orderOfInsertion) {
    const MapObjectType* pioneersHouse1 = configMgr->getMapObjectType("pioneers-house1");

    BuildOperation buildOperation(context, *player);

    buildOperation.requestBuild({36, 37}, pioneersHouse1, Direction::EAST);
    buildOperation.requestBuild({39, 40}, pioneersHouse1, Direction::EAST);
    buildOperation.requestBuild({36, 39}, pioneersHouse1, Direction::EAST);
    buildOperation.requestBuild({39, 34}, pioneersHouse1, Direction::EAST);

    const std::list<MapObjectToBuild>& mapObjectsToBuild = buildOperation.getMapObjectsToBuild();
    auto iter = mapObjectsToBuild.cbegin();

    ASSERT_EQ(MapCoords(36, 37), iter->mapCoords);
    iter++;
    ASSERT_EQ(MapCoords(39, 40), iter->mapCoords);
    iter++;
    ASSERT_EQ(MapCoords(36, 39), iter->mapCoords);
    iter++;
    ASSERT_EQ(MapCoords(39, 34), iter->mapCoords);
    iter++;
    ASSERT_TRUE(iter == mapObjectsToBuild.cend());
}
/**
 * @brief Überprüft, dass Häuser beim Enqueue in die BuildOperation zufällig gewählt werden.
 * Wir bauen 2x dasselbe und wollen ein anderes Ergebnis haben.
 */
TEST_F(BuildOperationTest, randomizeWhenBuildingHouses) {
    // Testaufbau

    const unsigned char HOUSE_TYPES_COUNT = 5;
    const MapObjectType* pioneersHouses[HOUSE_TYPES_COUNT] = {
        configMgr->getMapObjectType("pioneers-house1"),
        configMgr->getMapObjectType("pioneers-house2"),
        configMgr->getMapObjectType("pioneers-house3"),
        configMgr->getMapObjectType("pioneers-house4"),
        configMgr->getMapObjectType("pioneers-house5")
    };

    const std::forward_list<MapCoords> mapCoordsToBuildThere = {
        {38, 32}, {38, 34}, {38, 36}, {38, 38}, {38, 40}, {38, 42},
        {36, 33}, {36, 35}, {36, 37}, {36, 39},
        {45, 33}, {47, 34}, {49, 33}, {51, 35}, {51, 37}, {52, 39}, {54, 39}
    };

    Colony* colony = game->getColony({ 43, 34 });
    colony->getGoods(configMgr->getGood("wood")).inventory = 60;

    // Testdurchführung: Baue zweimal dasselbe und vergleiche das Ergebnis

    auto doOneBuild = [&]() {
        BuildOperation buildOperation(context, *player);
        for (const MapCoords& mapCoords : mapCoordsToBuildThere) {
            buildOperation.requestBuildWhenNothingInTheWay(mapCoords, pioneersHouses[0], Direction::SOUTH);
        }
        return buildOperation.getResult();
    };

    BuildOperationResult result1 = doOneBuild();
    BuildOperationResult result2 = doOneBuild();

    // Testauswertung

    ASSERT_EQ(68, result1.size()); // Beide Ergebnis müssen 17 Häuser haben
    ASSERT_EQ(68, result2.size());

    unsigned int differences = 0;
    unsigned int pioneersHouse1CountInResult1 = 0;
    unsigned int pioneersHouse1CountInResult2 = 0;
    for (const MapCoords& mapCoords : mapCoordsToBuildThere) {
        const MapObjectType* mapObjectType1 = result1.at(mapCoords)->mapObjectToReplaceWith->getMapObjectType();
        const MapObjectType* mapObjectType2 = result2.at(mapCoords)->mapObjectToReplaceWith->getMapObjectType();

        if (mapObjectType1 != mapObjectType2) {
            differences++;
        }
        if (mapObjectType1 == pioneersHouses[0]) {
            pioneersHouse1CountInResult1++;
        }
        if (mapObjectType2 == pioneersHouses[0]) {
            pioneersHouse1CountInResult2++;
        }
    }

    ASSERT_NE(pioneersHouse1CountInResult1, 17); // Die Häuser dürfen nicht alle pioneersHouse1 sein
    ASSERT_NE(pioneersHouse1CountInResult2, 17);

    ASSERT_GT(differences, 0); // Die Häuser dürfen nicht alle identisch sein
}