All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.sahits.game.openpatrician.engine.player.strategy.SupplyHometownAIStrategy Maven / Gradle / Ivy

package ch.sahits.game.openpatrician.engine.player.strategy;


import ch.sahits.game.openpatrician.clientserverinterface.service.ShipService;
import ch.sahits.game.openpatrician.engine.player.SupplyCityMissionData;
import ch.sahits.game.openpatrician.engine.player.tradesteps.AggregatedCheckedBuyTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.AggregatesDumpTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.AggregatesSellTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.BuyWeaponTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.CheckForRepairTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.CheckHireCaptainTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.GuildJoinTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.HireDismissTradeManagerTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.HireSailorsStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.PayBackLoanTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.TakeLoanTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.TransferToOfficeTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.TravelToTradeStep;
import ch.sahits.game.openpatrician.engine.player.tradesteps.UpgradeShipTradeStep;
import ch.sahits.game.openpatrician.model.IAIPlayer;
import ch.sahits.game.openpatrician.model.city.ICity;
import ch.sahits.game.openpatrician.model.event.IShipEntersPortEvent;
import ch.sahits.game.openpatrician.model.player.ICityProductionConsumptionKnowledge;
import ch.sahits.game.openpatrician.model.player.IProductionConsumptionKnowledge;
import ch.sahits.game.openpatrician.model.product.EWare;
import ch.sahits.game.openpatrician.model.product.IWare;
import ch.sahits.game.openpatrician.model.ship.INavigableVessel;
import ch.sahits.game.openpatrician.utilities.annotation.ClassCategory;
import ch.sahits.game.openpatrician.utilities.annotation.EClassCategory;
import ch.sahits.game.openpatrician.utilities.annotation.LazySingleton;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.eventbus.AsyncEventBus;
import javafx.util.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * AI strategy for trading with the aim to supply the players home town.
 */
@LazySingleton
@ClassCategory(EClassCategory.SINGLETON_BEAN)
public class SupplyHometownAIStrategy extends BasePlayerTradeStrategy {
    private final Logger logger = LogManager.getLogger(getClass());

    @Autowired
    @Qualifier("serverClientEventBus")
    private AsyncEventBus clientServerEventBus;
    @Autowired
    private ShipService shipService;
    @Value("${aiplayer.money.low}")
    private int lowMoney = 2000;
    @Autowired
    private ApplicationContext context;

    public SupplyHometownAIStrategy() {
        this.tradeStrategyType = EAITradeStrategyType.SUPPLY_HOMETOWN;
    }

    @PostConstruct
    private void init() {
        clientServerEventBus.register(this);
    }
    @PreDestroy
    private void destroy() {
        clientServerEventBus.unregister(this);
    }


    @Override
    public void initializeTradeCycle(IAIPlayer player, INavigableVessel vessel) {
        ICity hometown = player.getHometown();
        IProductionConsumptionKnowledge knowledge = player.getProductionAndConsumptionKnowledge();
        ICityProductionConsumptionKnowledge knowledgeHomeTown = knowledge.getKnowlege(hometown);
        List> sortedNeeds = getMostNeededWares(knowledgeHomeTown, vessel);
        ArrayList waresOfInterest = findWaresOfInterest(sortedNeeds);
        SupplyCityMissionData missionData = new SupplyCityMissionData();
        missionData.setRequiredWares(waresOfInterest);
        missionData.setTargetCity(hometown);
        player.setTradeMission(vessel, missionData);
        addTradeStepsInHometownToTravelToNextCity(player, vessel);
    }


    @Override
    public void handleShipArrivesInPort(IShipEntersPortEvent event) {
        // no move steps defined
        INavigableVessel vessel = event.getShip();
        if (isMatchingTradeStrategy(vessel)) {
            ICity city = event.getCity();
            Preconditions.checkArgument(city.getCoordinates().equals(vessel.getLocation()), "The vessel " + vessel.getName() + " actually is not in city " + city.getName());
            IAIPlayer player = (IAIPlayer) vessel.getOwner();
            if (city.equals(player.getHometown())) {
                addTradeStepsSellingInHomeTown(player, vessel);
            } else {
                addTradeStepTradingNextTown(player, vessel);
            }
            executeTradeSteps(player, vessel);
        }
    }


    /**
     * Add the tradesteps to buy wares in the hometown and travel to the first stop.
     * @param player for whom to add the trade steps
     * @param vessel for which to add the trade steps
     */
    private void addTradeStepsInHometownToTravelToNextCity(IAIPlayer player, INavigableVessel vessel) {
        ICity hometown = player.getHometown();
        IProductionConsumptionKnowledge knowledge = player.getProductionAndConsumptionKnowledge();
        ICityProductionConsumptionKnowledge knowledgeHomeTown = knowledge.getKnowlege(hometown);
        List> sortedNeeds = getMostNeededWares(knowledgeHomeTown, vessel);
        ArrayList waresOfInterest = findWaresOfInterest(sortedNeeds);
        ICity firstStop = findNextStopForBuying(hometown, knowledge, waresOfInterest, vessel, hometown);
        List deliverWare = getWaresNeedIn(knowledge, knowledgeHomeTown, firstStop);

        PayBackLoanTradeStep payBackLoan = createPaybackLoanStep(player, hometown);
        append(player, vessel, payBackLoan);
        CheckHireCaptainTradeStep hireCaptain = createHireCaptain(vessel, hometown, player);
        append(player, vessel, hireCaptain);
        GuildJoinTradeStep joinTradeStep = createJoinGuildTradeStep(vessel, hometown, player);
        append(player, vessel, joinTradeStep);
        HireDismissTradeManagerTradeStep hireTradeManager = createHireDismissTradeManagerTradeStep(hometown, player);
        append(player, vessel, hireTradeManager);
        TakeLoanTradeStep takeLoanStep = createCheckAndTakeLoanStep(player, hometown);
        append(player, vessel, takeLoanStep);
        BuyWeaponTradeStep buyWeaponsStep = createWeaponBuyTradeStep(vessel, player, hometown);
        append(player, vessel, buyWeaponsStep);

        // define trade steps for the first city, consider what ware can be transported to that city.
        // Buy step in home town for deliverWare
        AggregatedCheckedBuyTradeStep buyStepHometown = createAggregatedCheckedBuyTradeStep(vessel, hometown, deliverWare);
        append(player, vessel, buyStepHometown);

        HireSailorsStep hireSailors = createHireSailorStep(vessel, hometown);
        append(player, vessel, hireSailors);

        // Travel step to next town
        TravelToTradeStep travelTo = createTravelToStep(vessel, firstStop);
        logger.debug("Add travel to step from hometown {}: {}", hometown.getName(), travelTo);
        append(player, vessel, travelTo);
    }

    /**
     * Add the tradesteps in the hometown to sell the wares and check for repairs
     * @param player for whom to add the trade steps
     * @param vessel for which to add the trade steps
     */
    @VisibleForTesting
    void addTradeStepsSellingInHomeTown(IAIPlayer player, INavigableVessel vessel){
        ICity hometown = player.getHometown();
        // Sell wares
        logger.trace("Add sell steps of wares in hometown: {} for {}", hometown.getName(), vessel.getName());
        TransferToOfficeTradeStep transferStep = createTransferToOfficeTradeStep(vessel, hometown);
        append(player, vessel, transferStep);
        List loadedWares = new ArrayList<>(vessel.getLoadedWares());
        AggregatesDumpTradeStep sellStep1 = createAggregatedDumpStep(vessel, hometown, loadedWares);
        append(player, vessel, sellStep1);
        // Check for repair
        UpgradeShipTradeStep upgradeShipStep = createUpgradeShipTradeStep(vessel, player);
        append(player, vessel, upgradeShipStep);
        CheckForRepairTradeStep repairStep = createCheckRepairStep(vessel, hometown);
        append(player, vessel, repairStep);
        AggregatesSellTradeStep sellStep2 = createAggregatedSellStep(vessel, hometown, loadedWares);
        append(player, vessel, sellStep2);
        addTradeStepsInHometownToTravelToNextCity(player, vessel);
    }

    /**
     * Define the trade steps in another town.
     * @param player for whom to add the trade steps
     * @param vessel for which to add the trade steps
     */
    @VisibleForTesting
    void addTradeStepTradingNextTown(IAIPlayer player, INavigableVessel vessel) {
        Optional optCity = shipService.findCity(vessel);
        if (!optCity.isPresent()) {
            logger.debug("The vessel {} is not in any city but {}", vessel.getName(), vessel.getLocation());
        }
        Preconditions.checkArgument(!optCity.get().equals(player.getHometown()), "The city must not be the players hometown");
        ICity city = optCity.get();
        ICity hometown = player.getHometown();
        List waresOfInterest = ((SupplyCityMissionData) player.getTradeMission(vessel)).getRequiredWares();
        IProductionConsumptionKnowledge knowledge = player.getProductionAndConsumptionKnowledge();
        ICityProductionConsumptionKnowledge knowledgeCurrentTown = knowledge.getKnowlege(city);
        List> sortedNeedsHometown = getMostNeededWares(knowledge.getKnowlege(hometown), vessel);
        List deliveringWares = getLoadedWaresToSell(vessel, waresOfInterest);
        logger.trace("Add sell steps of wares in other town: {} for {}", city.getName(), vessel.getName());
        AggregatesSellTradeStep sellStep = createAggregatedSellStep(vessel, city, deliveringWares);
        append(player, vessel, sellStep);

        PayBackLoanTradeStep payBackLoan = createPaybackLoanStep(player, city);
        append(player, vessel, payBackLoan);
        CheckHireCaptainTradeStep hireCaptain = createHireCaptain(vessel, city, player);
        append(player, vessel, hireCaptain);
        GuildJoinTradeStep joinTradeStep = createJoinGuildTradeStep(vessel, city, player);
        append(player, vessel, joinTradeStep);
        HireDismissTradeManagerTradeStep hireTradeManager = createHireDismissTradeManagerTradeStep(city, player);
        append(player, vessel, hireTradeManager);
        TakeLoanTradeStep takeLoanStep = createCheckAndTakeLoanStep(player, city);
        append(player, vessel, takeLoanStep);
        BuyWeaponTradeStep buyWeaponsStep = createWeaponBuyTradeStep(vessel, player, city);
        append(player, vessel, buyWeaponsStep);

        logger.trace("Add buy steps of wares in other town ({}) needed in hometown ({})  for {}", city.getName(), hometown.getName(), vessel.getName());
        AggregatedCheckedBuyTradeStep buyStep = createAggregatedCheckedBuyTradeStep(vessel, city, waresOfInterest);
        append(player, vessel, buyStep);

        if (shouldReturnToHometown(player, vessel)) {
            HireSailorsStep hireSailors = createHireSailorStep(vessel, city);
            append(player, vessel, hireSailors);
            TravelToTradeStep travelTo = createTravelToStep(vessel, hometown);
            logger.debug("Add travel to step from {} back: {}", city.getName(), travelTo);

            append(player, vessel, travelTo);
        } else {
            ArrayList waresOfInterestHometown = findWaresOfInterest(sortedNeedsHometown);
            ICity nextStop = findNextStopForBuying(city, knowledge, waresOfInterestHometown, vessel, hometown); // Find the next city that can provide more goods for the hometown
            List deliverWare = getWaresNeedIn(knowledge, knowledgeCurrentTown, nextStop);
            logger.trace("Add buy steps of wares in other town ({}) needed in next town ({})  for {}", city.getName(), nextStop.getName(), vessel.getName());
            AggregatedCheckedBuyTradeStep buyStepNextStop = createAggregatedCheckedBuyTradeStep(vessel, city, deliverWare);
            append(player, vessel, buyStepNextStop);
            HireSailorsStep hireSailors = createHireSailorStep(vessel, city);
            append(player, vessel, hireSailors);
            TravelToTradeStep travelTo = createTravelToStep(vessel, nextStop);
            StringBuilder neededInHomeTown = new StringBuilder();
            for (IWare ware : waresOfInterest) {
                neededInHomeTown.append(ware.name()).append(" ");
            }
            StringBuilder sellWares = new StringBuilder();
            for (IWare ware : deliverWare) {
                sellWares.append(ware.name()).append(" ");
            }

            logger.debug("Add travel to step from {}: {}, needed in hometown: {}, deliver wares {}", city.getName(), travelTo, neededInHomeTown.toString(), sellWares.toString());
            append(player, vessel, travelTo);
        }
    }

    /**
     * Check weather the vessel should return to the hometown
     * @param player for whom to check the returnal to the hometown
     * @param vessel which should return to the hometown
     * @return true if the vessle should return to the hometown
     */
    @VisibleForTesting
    boolean shouldReturnToHometown(IAIPlayer player, INavigableVessel vessel) {
        if (player.getCompany().getCash() < lowMoney) {
            return true;
        } else {
            List waresOfInterest = ((SupplyCityMissionData) player.getTradeMission(vessel)).getRequiredWares();
            if (vessel.getCapacity() == 0) {
                for (EWare ware : EWare.values()) {
                    if (vessel.getWare(ware).getAmount() > 0 && !waresOfInterest.contains(ware)) {
                        return false;
                    }
                }
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * Retrieve the wares that can be soled in another city than the hometown.
     * @param vessel from which to retrieve the loaded wares
     * @param waresOfInterest list of wares that should be sold in the hometown and nowhere else.
     * @return List of wares on the vessel
     */
    @VisibleForTesting
    List getLoadedWaresToSell(INavigableVessel vessel, List waresOfInterest) {
        List wares =  new ArrayList<>();
        for (IWare ware : vessel.getLoadedWares()) {
            if (!waresOfInterest.contains(ware)) {
                  wares.add(ware);
            }
        }
        return wares;
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy