@VisibleForTesting List<GenericPair<List<IShip>, List<IShip>>> calculatePairing(List<IShip> attackingShips, List<IShip> defendingShips){ List<GenericPair<List<IShip>, List<IShip>>> pairings = new ArrayList<>(); if (attackingShips.size() == defendingShips.size()){ for (int i = 0; i < attackingShips.size(); i++) { addPairing(attackingShips, defendingShips, pairings, i); } return pairings; } // pair off one on one and distribute the rest on the weakest pairing int minSize = Math.min(attackingShips.size(), defendingShips.size()); for (int i = 0; i < minSize; i++) { addPairing(attackingShips, defendingShips, pairings, i); } if (attackingShips.size() < defendingShips.size()) { for (int i = minSize; i < defendingShips.size(); i++) { GenericPair<List<IShip>, List<IShip>> weakestDefendingPair = findWeakest(pairings, false); weakestDefendingPair.getSecond().add(defendingShips.get(i)); } } else { for (int i = minSize; i < attackingShips.size(); i++) { GenericPair<List<IShip>, List<IShip>> weakestDefendingPair = findWeakest(pairings, true); weakestDefendingPair.getFirst().add(attackingShips.get(i)); } } return pairings; } @VisibleForTesting
private int calculateAgility(List<IShip> ships) { int agility = 0; for (IShip ship : ships) { agility += calculateAgility(ship); } return agility; } @VisibleForTesting
int strength = calculateStrength(shipsOnTurn); int agilityOnTurn = calculateAgility(shipsOnTurn); int agilityNotOnTurn = calculateAgility(shipsNotOnTurn); double evasionProbability = calculateEvasionProbability(agilityOnTurn, agilityNotOnTurn); double accuracy = calculateAccuracy(shipsOnTurn); int damage = calculateDamage(strength, accuracy, evasionProbability); int damagePerShip = damage/shipsNotOnTurn.size(); int damageFirstShip = damagePerShip + damage%shipsNotOnTurn.size(); removeFromFleet(ship, ship.getOwner()); redistributeShips(pairings, attackShipTurn, shipsOnTurn); int deathToll = calculateDeathToll(shipsNotOnTurn, damage); int deathTollPerShip = deathToll/shipsNotOnTurn.size(); int deathTollFirstShip = deathTollPerShip + deathToll%shipsNotOnTurn.size(); IShip shipWithMaxSailors = findMaxSailorsOnShip(shipsOnTurn); IShip captureShip = null; for (IShip ship : shipsNotOnTurn) { updateCapturedShip(capturedDefendingShips, capturedAttackingShips, attackShipTurn, shipWithMaxSailors, captureShip, context); redistributeShips(pairings, attackShipTurn, shipsOnTurn); } else if (shipsOnTurn.isEmpty()) { pairingIter.remove(); redistributeShips(pairings, !attackShipTurn, shipsNotOnTurn);
List<IShip> attackingShips = explodeShipList(attackingVessel); List<IShip> defendingShips = explodeShipList(defendingVessel); List<GenericPair<List<IShip>, List<IShip>>> pairings = calculatePairing(attackingShips, defendingShips); List<IShip> sunkenDefendingShips = new ArrayList<>(); List<IShip> sunkenAttackingShips = new ArrayList<>(); runAttackMove(pairings, sunkenDefendingShips, sunkenAttackingShips, capturedDefendingShips, capturedAttackingShips, pairingIter, pairing, attackShipTurn, context); runAttackMove(pairings, sunkenDefendingShips, sunkenAttackingShips, capturedDefendingShips, capturedAttackingShips, pairingIter, pairing, attackShipTurn, context); case STANDARD: if (attackingVessel.getOwner() instanceof ISeaPirate) { updatePirateAttackStatistic(defendingShips, sunkenDefendingShips, capturedDefendingShips, attacker); postMessageStandardFight(attackingShips, defendingShips, sunkenDefendingShips, sunkenAttackingShips, capturedDefendingShips, capturedAttackingShips, attacker, defender); break; case BLOCKADE: postMessageBlockadeFight(attackingShips, defendingShips, sunkenDefendingShips, sunkenAttackingShips, capturedDefendingShips, capturedAttackingShips, attacker, defender); break; default: ArrayList<IShip> defeatedAttackingShips = new ArrayList<>(sunkenAttackingShips); defeatedAttackingShips.addAll(capturedAttackingShips); updateCaptainsStats(attackingShips, defendingShips, defeatedDefendingShips, defeatedAttackingShips); postAttackOutcome(attackingShips, defendingShips, defeatedDefendingShips, defeatedAttackingShips, attackingVessel, defendingVessel);
private void updateCapturedShipInternal(List<IShip> capturedDefendingShips, List<IShip> capturedAttackingShips, boolean attackShipTurn, IShip shipWithMaxSailors, IShip captureShip, SeaFightContext context) { final int numberOfSailors = captureShip.getNumberOfSailors(); int halfTheSailors = numberOfSailors /2; captureShip.setNumberOfSailors(numberOfSailors - halfTheSailors); IShipOwner previousOwner = shipWithMaxSailors.getOwner(); removeFromFleet(shipWithMaxSailors, previousOwner); shipWithMaxSailors.setNumberOfSailors(halfTheSailors); shipWithMaxSailors.setOwner(captureShip.getOwner()); if (context.getType() == ESeaFightType.BLOCKADE && attackShipTurn) { IBlockade blockade = ((BlockadeSeafightContext)context).getBlockade(); blockade.getShipsToAuction().add(captureShip); } else { addToFleet(shipWithMaxSailors, captureShip.getOwner()); } if (attackShipTurn) { // shipWithMaxSailors belongs to attacking fleet capturedAttackingShips.add(shipWithMaxSailors); } else { capturedDefendingShips.add(shipWithMaxSailors); } }
@Subscribe public void handleShipBreaksBlockade(ShipNearingPortEvent event) { ICity city = event.getCity(); for (Entry<ICity, IBlockade> entry : blockadeState.entrySet()) { if (entry.getKey().equals(city)) { IConvoy blocadingConvoy = entry.getValue().getBlockadeConvoy(); INavigableVessel blockadeBreaker = event.getShip(); BlockadeSeafightContext context = new BlockadeSeafightContext(entry.getValue()); IPlayer owner = (IPlayer) blockadeBreaker.getOwner(); owner.updateCrimialDrive(1); seafightService.calculateOutcome(blocadingConvoy, blockadeBreaker, context); entry.getValue().getShipsToAuction().addAll(context.getCapturedShips()); } } } @Subscribe
int attackForce = attackingShip.getNumberOfSailors() + attackingHandWeapon; int defendForce = defendingShip.getNumberOfSailors() + defendingHandWeapon; double propSurvivingAttack = calculatePropSurvivingAttack(attackingShip, defendingShip); if (propSurvivingAttack > 0.8) {
@Subscribe public void handleShipNearingPort(ShipNearingPortEvent event) { ICity city = event.getCity(); INavigableVessel ship = event.getShip(); if (ship.getPirateFlag()) { Optional<ICityHall> optCityHall = cityHalls.findCityHall(city); if (optCityHall.isPresent()) { Optional<IOutriggerContract> optContract = optCityHall.get().getOutriggerContract(); //noinspection OptionalIsPresent if (optContract.isPresent()) { IShip outrigger = optContract.get().getOutrigger(); SeaFightContext context = new SeaFightContext(ESeaFightType.OUTRIGGER); IPlayer owner = (IPlayer) ship.getOwner(); owner.updateCrimialDrive(1); seaFightService.calculateOutcome(outrigger, ship, context); } } else { logger.warn("No CityHall found for city "+city.getName()); } } }
seaFightService.calculateOutcome(vessel, visibleVessel, new SeaFightContext(ESeaFightType.STANDARD)); if (vissibleOwner instanceof IPlayer) {