2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
6
* This program is distributed in the hope that it will be useful,
7
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
* GNU General Public License for more details.
10
* You should have received a copy of the GNU General Public License
11
* along with this program; if not, write to the Free Software
12
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
package games.strategy.triplea.Dynamix_AI;
17
import games.strategy.triplea.Dynamix_AI.Group.UnitGroup;
18
import games.strategy.engine.data.GameData;
19
import games.strategy.engine.data.GameMap;
20
import games.strategy.engine.data.PlayerID;
21
import games.strategy.engine.data.ProductionFrontier;
22
import games.strategy.engine.data.ProductionRule;
23
import games.strategy.engine.data.Resource;
24
import games.strategy.engine.data.Route;
25
import games.strategy.engine.data.Territory;
26
import games.strategy.engine.data.Unit;
27
import games.strategy.engine.data.UnitType;
28
import games.strategy.triplea.Constants;
29
import games.strategy.triplea.Dynamix_AI.CommandCenter.CachedCalculationCenter;
30
import games.strategy.triplea.Dynamix_AI.CommandCenter.FactoryCenter;
31
import games.strategy.triplea.Dynamix_AI.CommandCenter.GlobalCenter;
32
import games.strategy.triplea.Dynamix_AI.CommandCenter.StrategyCenter;
33
import games.strategy.triplea.Dynamix_AI.CommandCenter.TacticalCenter;
34
import games.strategy.triplea.Dynamix_AI.CommandCenter.ThreatInvalidationCenter;
35
import games.strategy.triplea.Dynamix_AI.Group.PurchaseGroup;
36
import games.strategy.triplea.Dynamix_AI.Others.CM_Task;
37
import games.strategy.triplea.Dynamix_AI.Others.CM_TaskType;
38
import games.strategy.triplea.Dynamix_AI.Others.NCM_Call;
39
import games.strategy.triplea.Dynamix_AI.Others.NCM_CallType;
40
import games.strategy.triplea.Dynamix_AI.Others.NCM_Task;
41
import games.strategy.triplea.Dynamix_AI.Others.NCM_TaskType;
42
import games.strategy.triplea.Dynamix_AI.Others.PhaseType;
43
import games.strategy.triplea.Dynamix_AI.Others.StrategyType;
44
import games.strategy.triplea.Dynamix_AI.UI.UI;
45
import games.strategy.triplea.Properties;
46
import games.strategy.triplea.TripleAUnit;
47
import games.strategy.triplea.attatchments.RulesAttachment;
48
import games.strategy.triplea.attatchments.TerritoryAttachment;
49
import games.strategy.triplea.attatchments.UnitAttachment;
50
import games.strategy.triplea.delegate.Matches;
51
import games.strategy.triplea.delegate.MustFightBattle;
52
import games.strategy.triplea.formatter.MyFormatter;
53
import games.strategy.triplea.oddsCalculator.ta.AggregateResults;
54
import games.strategy.triplea.oddsCalculator.ta.BattleResults;
55
import games.strategy.util.CompositeMatchAnd;
56
import games.strategy.util.CompositeMatchOr;
57
import games.strategy.util.IntegerMap;
58
import games.strategy.util.InverseMatch;
59
import games.strategy.util.Match;
60
import java.util.Arrays;
61
import java.util.Collection;
62
import java.util.Collections;
63
import java.util.Comparator;
64
import java.util.HashMap;
65
import java.util.ArrayList;
66
import java.util.HashSet;
67
import java.util.Iterator;
68
import java.util.List;
70
import java.util.Random;
71
import java.util.TreeMap;
72
import java.util.logging.Level;
73
import javax.swing.SwingUtilities;
81
public static float GetAttackScoreOfUnits(Collection<Unit> units)
85
for(Unit unit : units)
87
UnitAttachment ua = UnitAttachment.get(unit.getType());
88
PlayerID owner = unit.getOwner();
90
unitAttack += ua.getAttack(owner);
92
unitAttack = unitAttack * 2.0F;
93
if(ua.getAttackRolls(owner) > 1)
94
unitAttack = unitAttack * (float)ua.getAttackRolls(owner);
101
public static float GetDefenseScoreOfUnits(Collection<Unit> units)
105
for(Unit unit : units)
107
UnitAttachment ua = UnitAttachment.get(unit.getType());
110
PlayerID owner = unit.getOwner();
111
float unitDefense = 1;
112
unitDefense += ua.getDefense(owner);
114
unitDefense = unitDefense * 2.0F;
116
result += unitDefense;
121
public static float GetValueOfUnits(Collection<Unit> units)
125
for(Unit unit : units)
127
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
129
result += GetAttackStrengthOfUnit(unit);
130
result += GetDefenseStrengthOfUnit(unit);
132
result += 3; //Air units can be retreated to safe places, and stuff
137
public static List<Unit> GetUnitsOnMap(GameData data)
139
return GetUnitsMatchingXInTerritoriesMatchingY(data, Match.ALWAYS_MATCH, Match.ALWAYS_MATCH);
141
public static List<Unit> GetUnitsMatchingXOnMap(GameData data, Match<Unit> unitMatch)
143
return GetUnitsMatchingXInTerritoriesMatchingY(data, unitMatch, Match.ALWAYS_MATCH);
145
public static List<Unit> GetUnitsMatchingXInTerritoriesMatchingY(GameData data, Match<Unit> unitMatch, Match<Territory> terMatch)
147
return GetUnitsMatchingXInTerritories(GetTerritoriesMatching(data, terMatch), unitMatch);
149
public static List<Unit> GetUnitsInTerritories(List<Territory> territories)
151
return GetUnitsMatchingXInTerritories(territories, Match.ALWAYS_MATCH);
153
public static List<Unit> GetUnitsMatchingXInTerritories(List<Territory> territories, Match<Unit> unitMatch)
155
List<Unit> result = new ArrayList<Unit>();
156
for(Territory ter : territories)
157
result.addAll(ter.getUnits().getMatches(unitMatch));
160
public static List<Unit> GetUnitsInUGs(List<UnitGroup> ugs)
162
List<Unit> result = new ArrayList<Unit>();
163
for(UnitGroup ug : ugs)
164
result.addAll(ug.GetUnits());
167
public static int GetTUVOfUnit(Unit unit, ProductionFrontier frontier, Resource resource)
170
for (ProductionRule rule : frontier.getRules())
172
if (((UnitType) rule.getResults().keySet().toArray()[0]).getName().equals(unit.getUnitType().getName()))
173
result += (rule.getCosts().getInt(resource) / rule.getResults().keySet().size()); //We divide the cost by how many units we get from the purchase
177
public static int GetTUVOfUnit(Unit unit, Resource resource)
179
if(unit.getOwner().isNull())
180
return GetTUVOfUnit(unit, GlobalCenter.GetMergedAndAveragedProductionFrontier(), resource);
182
return GetTUVOfUnit(unit, unit.getOwner().getProductionFrontier(), resource);
184
public static int GetTUVOfUnits(Collection<Unit> units, ProductionFrontier frontier, Resource resource)
187
for(Unit unit : units)
188
result += GetTUVOfUnit(unit, frontier, resource);
191
public static int GetTUVOfUnits(Collection<Unit> units, Resource resource)
194
for(Unit unit : units)
195
result += GetTUVOfUnit(unit, resource);
198
public static float GetDefenseStrengthOfUnit(Unit unit)
200
return GetDefenseScoreOfUnits(Collections.singleton(unit));
202
public static float GetAttackStrengthOfUnit(Unit unit)
204
return GetAttackScoreOfUnits(Collections.singleton(unit));
207
* Runs simulated battles numerous times and returns an AggregateResults object that lists the percent of times the attacker won, lost, etc.
208
* @param ter - The map territory used to determine the attacking units, the defending units, and the battle site
209
* @param player - The attacking player
210
* @param data - The game data containing the map, units, players, etc.
211
* @param runCount - How many times to simulate the battle. The more it's simulated, the more accurate the results will be
212
* @param toTake - Whether the attacker needs to have a unit left over after the attack to take the territory for a battle simulation to be counted as a win
213
* @return Returns an AggregateResults object that lists the percent of times the attacker won, lost, etc.
215
public static AggregateResults GetBattleResults(Territory ter, PlayerID player, GameData data, int runCount, boolean toTake)
217
List<Unit> attacking = new ArrayList<Unit>();
218
List<Unit> defending = new ArrayList<Unit>();
220
for(Unit unit : ter.getUnits().getUnits())
222
if(unit.getOwner().equals(player))
224
else if(!data.getAllianceTracker().isAllied(player, unit.getOwner()))
228
return GetBattleResults(attacking, defending, ter, data, runCount, toTake);
231
* Used when you have two or more lists of units, etc and you want all the units in one collection.
233
* List<Unit> unitCollection1 = GetNNEnemyUnitsThatCanReach(target);
234
* List<Unit> unitCollection2 = GetNNEnemyUnitsThatCanReach(target2);
235
* List<Unit> allUnits = CombineCollections(unitCollection1, unitCollection2);
237
public static List CombineCollections(Collection ... collections)
239
List result = new ArrayList();
240
for(Collection collection : collections)
242
result.addAll(collection);
247
* Used when you have 1 or more collections with lists of units, etc and you want all the units in all the lists in one collection.
249
* Collection<List<Unit>> unitLists = units_Mapped.values();
250
* List<Unit> allUnits = CombineListsInCollections(unitLists);
252
public static List CombineListsInCollections(Collection ... collections)
254
List result = new ArrayList();
255
for(Collection collection : collections)
257
for (Object list : collection.toArray())
259
result.addAll((Collection)list);
264
public static float ToFloat(int percentage)
266
return percentage / 100.0F;
268
public static List ToList(Collection collection)
270
return new ArrayList(collection);
272
public static List ToList(Object[] array)
274
return Arrays.asList(array);
276
public static Object[] ToArray(Object ... toSmashIntoArray)
278
return toSmashIntoArray;
281
* First, determines if <code>map</code> contains <code>key</code>.
282
* If it does, it retrieves the value(which is expected to be a List) of <code>key</code> in <code>map</code>, adds <code>obj</code> to the list,
283
* and puts the updated list back into <code>map</code> using <code>key</code> as the key.
284
* If it doesn't, it creates a new list, adds <code>obj</code> to the list, and puts the new list into <code>map</code> using <code>key</code> as the key.
286
public static void AddObjToListValueForKeyInMap(HashMap map, Object key, Object obj)
288
AddObjectsToListValueForKeyInMap(map, key, Collections.singletonList(obj));
292
* Same as AddObjToListValueForKeyInMap except that it does adds a list of objects instead of one object.
294
public static void AddObjectsToListValueForKeyInMap(HashMap map, Object key, List objs)
296
if (map.containsKey(key))
298
List<Object> newList = (List<Object>) map.get(key);
299
newList.addAll(objs);
300
map.put(key, newList);
304
List<Object> newList = new ArrayList<Object>();
305
newList.addAll(objs);
306
map.put(key, newList);
311
* Same as AddObjectsToListValueForKeyInMap except that this method assumes the hashmap has HashSet values instead of List values
313
public static void AddObjectsToHashSetValueForKeyInMap(HashMap map, Object key, List objs)
315
if (map.containsKey(key))
317
HashSet<Object> newList = (HashSet<Object>) map.get(key);
318
newList.addAll(objs);
319
map.put(key, newList);
323
HashSet<Object> newList = new HashSet<Object>();
324
newList.addAll(objs);
325
map.put(key, newList);
330
* (GetHitPointsScoreOfUnits)
332
public static int GetHPScoreOfUnits(List<Unit> units)
335
for (Unit unit : units)
338
if (UnitAttachment.get(unit.getType()).isTwoHit())
345
public static int GetAttackStrengthOfUnits(List<Unit> units)
348
for (Unit unit : units)
350
UnitAttachment ua = UnitAttachment.get(unit.getType());
351
result += (ua.getAttack(unit.getOwner()) * (ua.isTwoHit() ? 2 : 1));
355
public static int GetDefenseStrengthOfUnits(List<Unit> units)
358
for (Unit unit : units)
360
UnitAttachment ua = UnitAttachment.get(unit.getType());
361
result += (ua.getDefense(unit.getOwner()) * (ua.isTwoHit() ? 2 : 1));
365
public static boolean CanPlayerPlaceAnywhere(GameData data, PlayerID player)
367
if(Properties.getPlaceInAnyTerritory(data))
369
RulesAttachment ra = (RulesAttachment) player.getAttachment(Constants.RULES_ATTATCHMENT_NAME);
370
if(ra != null && ra.getPlacementAnyTerritory())
376
public static List<PlayerID> GetAliveEnemyPlayers(GameData data, PlayerID player)
378
List<PlayerID> result = new ArrayList<PlayerID>();
379
for (PlayerID enemy : data.getPlayerList().getPlayers())
381
if (!data.getAllianceTracker().isAllied(player, enemy) && TerritoryAttachment.getAllCurrentlyOwnedCapitals(enemy, data).size() > 0)
386
public static List<PlayerID> GetEnemyPlayers(GameData data, PlayerID us)
388
List<PlayerID> result = new ArrayList<PlayerID>();
389
for (PlayerID player : data.getPlayerList().getPlayers())
391
if (!data.getAllianceTracker().isAllied(us, player))
396
public static List<PlayerID> GetAlliedPlayersIncludingUs(GameData data, PlayerID us)
398
List<PlayerID> result = new ArrayList<PlayerID>();
399
for (PlayerID player : data.getPlayerList().getPlayers())
401
if (data.getAllianceTracker().isAllied(us, player))
407
* Used to find the x closest routes between two territories that are of similar length.
408
* This can be used to find the friendly/enemy units in the general area between two countries to determine how many units to send in one direction.
410
public static List<Route> GetXClosestSimiliarLengthLandRoutesBetweenTers(GameData data, int maxNumberOfRoutes, Territory ter1, Territory ter2)
412
List<Route> result = new ArrayList<Route>();
413
List<Territory> allRouteTers = new ArrayList<Territory>();
415
int uniqueRoutesFound = 0;
416
while (uniqueRoutesFound < maxNumberOfRoutes)
418
Route route = data.getMap().getRoute_IgnoreEnd(ter1, ter2, new CompositeMatchAnd<Territory>(Matches.territoryIsNotInList(allRouteTers), Matches.TerritoryIsLand));
421
if (!result.isEmpty() && !(result.get(0).getLength() + 2 >= route.getLength() && result.get(0).getLength() - 2 <= route.getLength())) //If this route is not similar in length to the first route, break loop
426
for (Territory ter : route.getTerritories())
428
if (ter.getName().equals(route.getStart().getName()))
430
if (ter.getName().equals(route.getEnd().getName()))
432
if(!allRouteTers.contains(ter))
433
allRouteTers.add(ter);
442
public static Unit GetRandomUnitForPlayerMatching(PlayerID player, Match<Unit> match)
445
player = PlayerID.NULL_PLAYERID;
447
ProductionFrontier frontier = player.getProductionFrontier();
449
frontier = GlobalCenter.GetMergedAndAveragedProductionFrontier();
450
List<ProductionRule> rules = new ArrayList<ProductionRule>(frontier.getRules());
451
Collections.shuffle(rules);
452
for (ProductionRule rule : rules)
454
Unit unit = ((UnitType) rule.getResults().keySet().toArray()[0]).create(player);
455
if (match.match(unit))
460
public static List<UnitType> GetAllPurchasableUnitTypesForPlayer(PlayerID player, Match<Unit> match)
462
List<UnitType> result = new ArrayList<UnitType>();
465
player = PlayerID.NULL_PLAYERID;
467
ProductionFrontier frontier = player.getProductionFrontier();
469
frontier = GlobalCenter.GetMergedAndAveragedProductionFrontier();
470
List<ProductionRule> rules = new ArrayList<ProductionRule>(frontier.getRules());
471
Collections.shuffle(rules);
472
for (ProductionRule rule : rules)
474
Unit unit = ((UnitType) rule.getResults().keySet().toArray()[0]).create(player);
475
if (match.match(unit))
476
result.add(unit.getUnitType());
481
public static List<Unit> CreateDefendUnitsTillTakeoverChanceIsLessThanX(Collection<Unit> attackers, Collection<Unit> alreadyDefending, GameData data, Territory testTer, float maxChance)
483
PlayerID defender = testTer.getOwner();
484
if(alreadyDefending.size() > 0)
485
defender = alreadyDefending.iterator().next().getOwner();
486
List<Unit> result = new ArrayList<Unit>();
487
AggregateResults lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 50, true);
488
while (lastResults.getAttackerWinPercent() > maxChance)
490
for (UnitType ut : GlobalCenter.AllMapUnitTypes)
492
lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 1, true);
494
result.add(ut.create(defender));
495
if(lastResults.getAttackerWinPercent() <= maxChance)
499
lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 50, true);
500
while (lastResults.getAttackerWinPercent() > maxChance)
502
for (UnitType ut : GlobalCenter.AllMapUnitTypes)
504
lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 5, true);
506
result.add(ut.create(defender));
507
if(lastResults.getAttackerWinPercent() <= maxChance)
513
public static List<Unit> MultiplyDefenderUnitsTillTakeoverChanceIsLessThanX(Collection<Unit> attackers, Collection<Unit> defenders, GameData data, Territory testTer, float maxChance)
515
if (Match.getMatches(defenders, new CompositeMatchAnd<Unit>(Matches.UnitIsNotAA, Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1))).isEmpty())
517
Match<Unit> randUnitMatch;
518
if(testTer.isWater())
519
randUnitMatch = new CompositeMatchAnd<Unit>(DUtils.CompMatchOr(Matches.UnitIsSea, Matches.UnitIsAir));
521
randUnitMatch = new CompositeMatchAnd<Unit>(Matches.UnitIsLand, Matches.UnitIsNotAA, Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1));
522
Unit randUnit = GetRandomUnitForPlayerMatching(testTer.getOwner(), randUnitMatch);
524
return new ArrayList<Unit>();
525
defenders.add(randUnit);
527
PlayerID defender = testTer.getOwner();
528
if(defenders.size() > 0)
529
defender = defenders.iterator().next().getOwner();
530
List<Unit> result = new ArrayList<Unit>();
531
AggregateResults lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 50, true);
532
while (lastResults.getAttackerWinPercent() > maxChance)
534
for (Unit unit : defenders)
536
lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 1, true);
538
result.add(unit.getUnitType().create(defender));
539
if(lastResults.getAttackerWinPercent() <= maxChance)
543
lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 50, true);
544
while (lastResults.getAttackerWinPercent() > maxChance)
546
for (Unit unit : defenders)
548
lastResults = DUtils.GetBattleResults(attackers, result, testTer, data, 5, true);
550
result.add(unit.getUnitType().create(defender));
551
if (lastResults.getAttackerWinPercent() <= maxChance)
559
* this can return null, if either ters is empty or none of the territories match
561
public static Territory GetRandomTerritoryMatchingXInList(Collection<Territory> ters, Match<Territory> match)
563
List<Territory> list = new ArrayList<Territory>();
564
for (Territory ter : ters)
566
if (!match.match(ter))
574
return list.get(new Random().nextInt(list.size()));
576
public static Match CompMatchAnd(Match ... matches)
578
return new CompositeMatchAnd(matches);
580
public static Match CompMatchOr(Match ... matches)
582
return new CompositeMatchOr(matches);
584
public static Match CompMatchAnd(List<Match> matches)
586
return new CompositeMatchAnd(matches);
588
public static Match CompMatchOr(List<Match> matches)
590
return new CompositeMatchOr(matches);
592
public static List<Territory> GetEnemyTersThatCanBeAttackedByUnitsOwnedBy(GameData data, PlayerID player)
594
return GetTersMatchingXThatCanBeAttackedByUnitsMatchingYInTersMatchingZ(data, player, CompMatchAnd(Matches.TerritoryIsPassableAndNotRestricted(player), CompMatchOr(DMatches.territoryIsOwnedByEnemy(data, player), Matches.territoryHasUnitsThatMatch(CompMatchAnd(Matches.unitIsEnemyOf(data, player), Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1))))), DMatches.territoryIsOwnedByEnemy(data, player).invert(), Matches.unitIsOwnedBy(player));
596
public static List<Territory> GetEnemyLandTersThatCanBeAttackedByLandUnitsOwnedBy(GameData data, PlayerID player)
598
return GetTersMatchingXThatCanBeAttackedByUnitsMatchingYInTersMatchingZ(data, player, CompMatchAnd(Matches.TerritoryIsLand, DMatches.territoryIsOwnedByEnemy(data, player)), DMatches.territoryIsOwnedByEnemy(data, player).invert(), Matches.unitIsLandAndOwnedBy(player));
600
public static List<Territory> GetEnemySeaTersThatCanBeAttackedByUnitsOwnedBy(GameData data, PlayerID player)
602
return GetTersMatchingXThatCanBeAttackedByUnitsMatchingYInTersMatchingZ(data, player, CompMatchAnd(Matches.TerritoryIsWater, Matches.territoryHasEnemyUnits(player, data)), DMatches.territoryIsOwnedByEnemy(data, player).invert(), Matches.unitIsOwnedBy(player));
604
public static List<Territory> GetTersMatchingXThatCanBeAttackedByUnitsMatchingYInTersMatchingZ(GameData data, PlayerID player, Match<Territory> terMatch, Match<Territory> attackFromTerMatch, Match<Unit> unitMatch)
606
List<Territory> result = new ArrayList<Territory>();
607
for (Territory ter : data.getMap().getTerritories())
609
if (!terMatch.match(ter))
612
List<Unit> possibleAttackers = DUtils.GetUnitsMatchingXThatCanReach(data, ter, attackFromTerMatch, unitMatch);
614
if (possibleAttackers.size() > 0)
619
public static List<Territory> GetEnemyLandTersThatCanBeAttackedByLandUnitsInList(GameData data, PlayerID player, List<Unit> units, Territory territory)
621
List<Territory> attackLocs = DUtils.GetTersThatUnitsCanReach(data, Match.getMatches(units, Matches.UnitIsLand), territory, player, new CompositeMatchAnd<Territory>(DMatches.territoryIsOwnedByNNEnemy(data, player), Matches.TerritoryIsLand));
623
List<Territory> result = new ArrayList<Territory>();
624
for (Territory ter : attackLocs)
626
if (data.getAllianceTracker().isAllied(ter.getOwner(), player))
630
if(ter.getOwner().isNull())
637
public static List<Territory> GetLandTersThatCanBeReinforcedByUnitsOwnedBy(GameData data, PlayerID player)
639
return GetTersMatchingXThatCanBeReinforcedByUnitsMatchingYInTersMatchingZ(data, player, DMatches.territoryIsOwnedByXOrAlly(data, player), DMatches.territoryIsOwnedByXOrAlly(data, player), Matches.unitIsOwnedBy(player));
641
public static List<Territory> GetLandTersThatCanBeReinforcedByLandUnitsOwnedBy(GameData data, PlayerID player)
643
return GetTersMatchingXThatCanBeReinforcedByUnitsMatchingYInTersMatchingZ(data, player, DMatches.territoryIsOwnedByXOrAlly(data, player), DMatches.territoryIsOwnedByXOrAlly(data, player), Matches.unitIsLandAndOwnedBy(player));
645
public static List<Territory> GetTersMatchingXThatCanBeReinforcedByUnitsMatchingYInTersMatchingZ(GameData data, PlayerID player, Match<Territory> terMatch, Match<Territory> moveFromTerMatch, Match<Unit> unitMatch)
647
List<Territory> result = new ArrayList<Territory>();
648
for (Territory ter : data.getMap().getTerritories())
650
if (!terMatch.match(ter))
653
List<Unit> possibleAttackers = DUtils.GetUnitsMatchingXThatCanReach(data, ter, moveFromTerMatch, unitMatch);
655
if (possibleAttackers.size() > 0)
660
public static int GetProduction_PlusExtra(Territory ter)
664
GameData data = ter.getData();
665
int result = TerritoryAttachment.get(ter).getProduction();
666
if (DMatches.territoryIsCapitalAndOwnedByEnemy(data, GlobalCenter.CurrentPlayer).match(ter))
668
int puGainIfWeConquer = 0;
669
for (PlayerID enemy : data.getPlayerList().getPlayers())
671
List<Territory> enemyCapList = DUtils.GetAllOurCaps_ThatWeOwn(data, enemy);
672
if (enemyCapList.size() == 1 && enemyCapList.get(0).equals(ter)) //If the enemy only has one cap left, and it's the ter we're checking
673
puGainIfWeConquer += enemy.getResources().getQuantity(GlobalCenter.GetPUResource());
675
result += puGainIfWeConquer;
679
public static int GetCheckedUnitProduction(Territory ter)
681
if(ter.getOwner().getRepairFrontier() != null)
682
return TerritoryAttachment.get(ter).getUnitProduction();
684
return TerritoryAttachment.get(ter).getProduction();
686
public static List<Territory> SortTerritoriesByNNEnemyNeighbors_A(List<Territory> list, final GameData data, final PlayerID player)
688
return DSorting.SortListByX(list, new Comparator<Territory>()
690
public int compare(Territory ter1, Territory ter2)
692
int val1 = DUtils.GetTersThatMatchXThatUnitsOnTerCanAttack(data, ter1, DMatches.territoryIsOwnedByNNEnemy(data, player), player).size();
693
int val2 = DUtils.GetTersThatMatchXThatUnitsOnTerCanAttack(data, ter2, DMatches.territoryIsOwnedByNNEnemy(data, player), player).size();
699
public static List<Territory> GetTerritoriesInListThatAreNotInRoute(List<Territory> list, Route exludeRoute)
701
List<Territory> result = new ArrayList<Territory>();
702
for (Territory ter : list)
704
if (!exludeRoute.getTerritories().contains(ter))
709
public static HashMap<Object, Object> ReverseHashMap(HashMap<Object, Object> map, final GameData data, final PlayerID player)
711
HashMap<Object, Object> result = new HashMap<Object, Object>();
712
List<Object> invertedKeys = new ArrayList<Object>();
713
for (Object obj : map.keySet())
714
invertedKeys.add(obj);
715
Collections.reverse(invertedKeys);
716
for (Object obj : invertedKeys)
718
result.put(obj, map.get(obj));
722
public static int GetSlowestMovementUnitInList(Collection<Unit> list)
724
int lowestMovement = Integer.MAX_VALUE;
725
for (Unit unit : list)
727
TripleAUnit tu = TripleAUnit.get(unit);
728
if (tu.getMovementLeft() < lowestMovement)
730
lowestMovement = tu.getMovementLeft();
733
if(lowestMovement == Integer.MAX_VALUE)
735
return lowestMovement;
737
public static int GetFastestMovementUnitInList(Collection<Unit> list)
739
int fastestMovement = Integer.MIN_VALUE;
740
for (Unit unit : list)
742
TripleAUnit tu = TripleAUnit.get(unit);
743
if (tu.getMovementLeft() > fastestMovement)
745
fastestMovement = tu.getMovementLeft();
748
if(fastestMovement == Integer.MIN_VALUE)
750
return fastestMovement;
752
public static Unit GetCheapestUnitInList(Collection<Unit> list)
754
int cheapest = Integer.MAX_VALUE;
755
Unit cheapestUnit = null;
756
for (Unit unit : list)
758
int cost = DUtils.GetTUVOfUnit(unit, GlobalCenter.GetPUResource());
768
* Separates all the units in the list into separate lists and puts them into a hashmap with the key as the movement speed and the value as the list of units with that speed.
769
* @param list - List of units to seperate
770
* @return - a hashmap containing all the units separated by speed.
772
public static HashMap<Integer, List<Unit>> SeperateUnitsInListIntoSeperateMovementLists(List<Unit> list)
774
HashMap<Integer, List<Unit>> result = new HashMap<Integer, List<Unit>>();
775
for (Unit unit : list)
777
TripleAUnit ta = TripleAUnit.get(unit);
778
int movement = ta.getMovementLeft();
779
if (result.containsKey(movement))
781
List<Unit> oldUnits = result.get(movement);
783
result.put(movement, oldUnits);
787
List<Unit> oldUnits = new ArrayList<Unit>();
789
result.put(movement, oldUnits);
794
public static List<Territory> GetXClosestTersInList(GameData data, List<Territory> ters, Territory target, int count)
796
if (ters == null || ters.isEmpty())
797
return new ArrayList<Territory>();
798
return DSorting.SortTerritoriesByLandThenNoCondDistance_A(ters, data, target).subList(0, count);
800
public static Territory GetClosestTerInList(GameData data, List<Territory> ters, Territory target)
802
List<Territory> xClosest = GetXClosestTersInList(data, ters, target, 1);
803
if(xClosest.isEmpty())
805
return xClosest.get(0);
808
///////////////////////////Territory finding methods///////////////////////////
809
public static Territory GetClosestTerMatchingX(GameData data, Territory target, Match<Territory> match)
811
List<Territory> matching = GetTerritoriesWithinXDistanceOfYMatchingZ(data, target, Integer.MAX_VALUE, match);
812
if(matching.isEmpty())
814
return matching.get(0);
816
public static Territory GetClosestTerMatchingXAndHavingRouteMatchingY(GameData data, Territory target, Match<Territory> match, Match<Territory> routeMatch)
818
List<Territory> matching = GetTerritoriesWithinXDistanceOfYMatchingZAndHavingRouteMatchingA(data, target, Integer.MAX_VALUE, match, routeMatch);
819
if(matching.isEmpty())
821
return matching.get(0);
825
* Returns all capitals.
827
public static List<Territory> GetAllCapitals(GameData data)
829
return Match.getMatches(data.getMap().getTerritories(), DMatches.territoryIsCapital);
832
///////////////////////////Our cap methods///////////////////////////
834
* Returns all capitals currently owned by player.
836
public static List<Territory> GetAllCapsOwnedBy(GameData data, PlayerID player)
838
return Match.getMatches(GetAllCapitals(data), DMatches.territoryIsOwnedBy(player));
841
* Returns all capitals originally owned by player.
843
public static List<Territory> GetAllOurCaps(GameData data, PlayerID player)
845
return TerritoryAttachment.getAllCapitals(player, data);
848
* Returns all capitals originally owned by player that we own currently.
850
public static List<Territory> GetAllOurCaps_ThatWeOwn(GameData data, PlayerID player)
852
return Match.getMatches(GetAllOurCaps(data, player), Matches.isTerritoryOwnedBy(player));
855
* Returns the closest capital originally owned by player.
857
public static Territory GetOurClosestCap(GameData data, PlayerID player, Territory ter)
859
return GetClosestTerInList(data, GetAllOurCaps(data, player), ter);
862
* Returns the closest capital originally owned by player that we own currently.
864
public static Territory GetOurClosestCap_ThatWeOwn(GameData data, PlayerID player, Territory ter)
866
return GetClosestTerInList(data, GetAllOurCaps_ThatWeOwn(data, player), ter);
869
///////////////////////////Enemy cap methods///////////////////////////
871
* Returns all capitals currently owned by enemies.
873
public static List<Territory> GetAllCapsOwnedByEnemies(GameData data, PlayerID player)
875
return Match.getMatches(GetAllCapitals(data), Matches.isTerritoryEnemy(player, data));
878
* Returns all capitals originally owned by enemies.
880
public static List<Territory> GetAllEnemyCaps(GameData data, PlayerID player)
882
List<Territory> result = new ArrayList<Territory>();
883
for(PlayerID enemy : data.getPlayerList().getPlayers())
885
if(data.getAllianceTracker().isAllied(enemy, player))
888
result.addAll(GetAllOurCaps(data, enemy));
893
* Returns all capitals originally owned by enemies that the original owner currently owns.
895
public static List<Territory> GetAllEnemyCaps_ThatAreOwnedByOriginalOwner(GameData data, PlayerID player)
897
List<Territory> result = new ArrayList<Territory>();
898
for (PlayerID enemy : data.getPlayerList().getPlayers())
900
if (data.getAllianceTracker().isAllied(enemy, player))
903
result.addAll(GetAllOurCaps_ThatWeOwn(data, enemy));
908
public static List<Territory> GetTerritoriesMatching(GameData data, Match<Territory> match)
910
return Match.getMatches(data.getMap().getTerritories(), match);
912
public static Territory GetUnitLocation(GameData data, Unit unit)
914
for(Territory ter : data.getMap().getTerritories())
916
if(ter.getUnits().getUnits().contains(unit))
922
public static List<Territory> GetUnitLocations(GameData data, List<Unit> units)
924
List<Territory> result = new ArrayList<Territory>();
926
for(Territory ter : data.getMap().getTerritories())
928
for (Unit unit : units)
930
if (ter.getUnits().getUnits().contains(unit))
940
public static boolean CanUnitReachTer(GameData data, Territory ter, Unit unit, Territory target)
942
return CanUnitReachTer(data, ter, unit, target, new ArrayList<Territory>());
944
public static boolean CanUnitReachTer(GameData data, Territory ter, Unit unit, Territory target, List<Territory> passthroughTers)
946
PlayerID player = unit.getOwner();
948
if(GlobalCenter.CurrentPhaseType == PhaseType.Combat_Move)
953
if (DMatches.territoryContainsMultipleAlliances(data).match(ter))
954
return false; //We don't consider units in a battle ter to be able to reach anything
955
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit))
957
if (ThreatInvalidationCenter.get(data, GlobalCenter.CurrentPlayer).IsUnitInvalidatedForTer(unit, target))
965
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit))
967
if (ThreatInvalidationCenter.get(data, GlobalCenter.CurrentPlayer).IsUnitInvalidatedForTer(unit, target))
971
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
972
TripleAUnit ta = TripleAUnit.get(unit);
974
Route noCondRoute = CachedCalculationCenter.GetRoute(data, ter, target);
975
if (noCondRoute == null)
976
return false; //Yikes, must be a map with entirely disconnected ters... :(
977
if (noCondRoute.getLength() > ta.getMovementLeft()) //If the unit can't even get from ter to territory on a condition-less route, we know it can't make it
982
if(DMatches.territoryIsOwnedByXOrAlly(data, player).match(target))
984
Route route = data.getMap().getRoute(ter, target, Matches.TerritoryIsNotImpassable);
987
if(ta.getMovementLeft() >= route.getLength())
993
if (CanAirUnitLandWithXSurvivalChanceIfAttackingFromXToY(data, ter, target, unit, DUtils.ToFloat(DSettings.LoadSettings().AA_survivalChanceOfLandingTerRequiredForPlaneRecruit)))
1001
Route route = DUtils.GetAttackRouteFromXToY_BySea(data, player, ter, target);
1002
if (route != null && ta.getMovementLeft() >= route.getLength())
1016
if(ua.isAA() && GlobalCenter.CurrentPhaseType != GlobalCenter.CurrentPhaseType.Non_Combat_Move)
1017
return false; //AA's can't move unless in ncm phase
1018
Route route = DUtils.GetAttackRouteFromXToY_ByLand_CountZAsPassthroughs(data, player, ter, target, passthroughTers);
1019
if (route != null && ta.getMovementLeft() >= route.getLength())
1025
public static List<Unit> GetUnitsMatching(List<Unit> units, Match<Unit> match)
1027
return Match.getMatches(units, match);
1029
public static List<Territory> GetEnemyTerritoriesWithinXLandDistanceThatHaveEnemyUnitsThatCanAttack(Territory target, GameData data, PlayerID player, int maxJumpDist)
1031
List<Territory> result = new ArrayList<Territory>();
1032
for (Territory ter : data.getMap().getTerritories())
1036
if (data.getAllianceTracker().isAllied(player, ter.getOwner()))
1038
List<Unit> enemyUnits = ter.getUnits().getMatches(Matches.unitIsEnemyOf(data, player));
1039
int dist = DUtils.GetJumpsFromXToY_PassableLand(data, ter, target);
1040
if(dist < 1 || dist > maxJumpDist)
1043
Route noCondRoute = CachedCalculationCenter.GetRoute(data, ter, target);
1044
if (noCondRoute == null)
1045
continue; //Yikes, must be a map with entirely disconnected ters... :(
1046
if (noCondRoute.getLength() > GlobalCenter.FastestUnitMovement) //If the unit can't even get from ter to territory on a condition-less route, we know it can't make it
1049
for (Unit u : enemyUnits)
1051
if(CanUnitReachTer(data, ter, u, target))
1060
public static int GetHighestTerProduction(GameData data)
1063
for (Territory ter : data.getMap().getTerritories())
1067
TerritoryAttachment ta = TerritoryAttachment.get(ter);
1070
if (ta.getProduction() > result)
1071
result = ta.getProduction();
1075
public static float GetValueOfLandTer(Territory target, GameData data, PlayerID player)
1079
Territory ourCap = GetOurClosestCap(data, player, target);
1080
int jumps = DUtils.GetJumpsFromXToY_PassableLand(data, target, ourCap);
1082
//3) If this ter is 1 jump away from our cap, add 90, if 2 jumps away, add 40, if three jumps away, add 10
1090
List<Territory> enemyCaps = DUtils.GetAllEnemyCaps(data, player);
1091
if(enemyCaps.contains(target))
1092
result += 250; //Give enemy caps a large score boost
1094
if(ourCap.getName().equals(target.getName()))
1095
result += 500; //Give our cap a huge score boost
1097
if(target.getUnits().getMatches(Matches.UnitIsFactory).size() > 0)
1098
result += 100; //Give enemy factory ters a boost
1100
result += TerritoryAttachment.get(target).getProduction() * 10;
1101
result += data.getMap().getNeighbors(target, Matches.TerritoryIsLand).size() * 2;
1102
result += data.getMap().getNeighbors(target, DMatches.territoryIsOwnedByNNEnemy(data, player)).size();
1106
public static HashMap<PlayerID, StrategyType> CalculateStrategyAssignments(GameData data, PlayerID player)
1108
HashMap<PlayerID, StrategyType> result = new HashMap<PlayerID, StrategyType>();
1109
if (GlobalCenter.IsFFAGame)
1111
List<Territory> ourTersConnectedToCap = new ArrayList<Territory>();
1112
List<Territory> ourCaps = DUtils.GetAllOurCaps(data, player);
1113
for (Territory cap : ourCaps)
1114
ourTersConnectedToCap.addAll(DUtils.GetTerritoriesWithinXDistanceOfYMatchingZAndHavingRouteMatchingA(data, cap, Integer.MAX_VALUE, DMatches.territoryIsOwnedBy(player), DMatches.territoryIsOwnedBy(player)));
1116
HashSet<PlayerID> enemiesTouchingOurCapConnectedTers = new HashSet<PlayerID>(); //Btw, I use HashSet because it doesn't allow duplicates in a list
1118
for(Territory enemyTer : data.getMap().getTerritories())
1120
if(!DMatches.territoryIsOwnedByNNEnemy(data, player).match(enemyTer))
1121
continue; //If this ter is not an enemy
1122
if(Match.getMatches(data.getMap().getNeighbors(enemyTer), DMatches.territoryIsInList(ourTersConnectedToCap)).isEmpty())
1123
continue; //If none of this ters neighbors are part of our 'ters connected to cap' list, don't count it
1124
if(!DMatches.territoryHasRouteMatchingXToTerritoryMatchingY(data, DMatches.territoryIsOwnedBy(enemyTer.getOwner()), CompMatchAnd(DMatches.territoryIsOwnedBy(enemyTer.getOwner()), DMatches.territoryIsInList(DUtils.GetAllOurCaps(data, enemyTer.getOwner())))).match(enemyTer))
1125
continue; //If this enemy ter does not have a route to it's capital
1127
//We passed all the checks, so we count this enemy as a 'neighbor'
1128
enemiesTouchingOurCapConnectedTers.add(enemyTer.getOwner());
1131
PlayerID weakestEnemyNeighbor = null;
1132
int weakestEnemyTUV = Integer.MAX_VALUE;
1133
for(PlayerID enemy : enemiesTouchingOurCapConnectedTers)
1135
int tuv = GetTUVOfUnits(GetUnitsMatchingXInTerritoriesMatchingY(data, Matches.unitIsOwnedBy(enemy), Matches.TerritoryIsLandOrWater), GlobalCenter.GetPUResource());
1136
if(tuv < weakestEnemyTUV)
1138
weakestEnemyNeighbor = enemy;
1139
weakestEnemyTUV = tuv;
1143
if(weakestEnemyNeighbor != null)
1144
result.put(weakestEnemyNeighbor, StrategyType.Enemy_Offensive); //For now, only go on the offensive on our weakest neighbor
1146
for (PlayerID otherPlayer : data.getPlayerList())
1148
if(otherPlayer == player)
1150
if (data.getAllianceTracker().isAtWar(player, otherPlayer))
1152
if(result.containsKey(otherPlayer)) //If this player already has an assignment
1155
result.put(otherPlayer, StrategyType.Enemy_Defensive);
1157
else //Shouldn't ever happen in FFA's...
1158
result.put(otherPlayer, StrategyType.Ally_OffensiveAssist);
1163
List<Territory> ourTersConnectedToCap = new ArrayList<Territory>();
1164
List<Territory> ourCaps = DUtils.GetAllOurCaps(data, player);
1165
for (Territory cap : ourCaps)
1166
ourTersConnectedToCap.addAll(DUtils.GetTerritoriesWithinXDistanceOfYMatchingZAndHavingRouteMatchingA(data, cap, Integer.MAX_VALUE, DMatches.territoryIsOwnedBy(player), DMatches.territoryIsOwnedBy(player)));
1168
HashSet<PlayerID> enemiesTouchingOurCapConnectedTers = new HashSet<PlayerID>(); //Btw, I use HashSet because it doesn't allow duplicates in a list
1170
for(Territory enemyTer : data.getMap().getTerritories())
1172
if(!DMatches.territoryIsOwnedByNNEnemy(data, player).match(enemyTer))
1173
continue; //If this ter is not an enemy
1174
if(Match.getMatches(data.getMap().getNeighbors(enemyTer), DMatches.territoryIsInList(ourTersConnectedToCap)).isEmpty())
1175
continue; //If none of this ters neighbors are part of our 'ters connected to cap' list, don't count it
1176
if(!DMatches.territoryHasRouteMatchingXToTerritoryMatchingY(data, DMatches.territoryIsOwnedBy(enemyTer.getOwner()), CompMatchAnd(DMatches.territoryIsOwnedBy(enemyTer.getOwner()), DMatches.territoryIsInList(DUtils.GetAllOurCaps(data, enemyTer.getOwner())))).match(enemyTer))
1177
continue; //If this enemy ter does not have a route to it's capital
1179
//We passed all the checks, so we count this enemy as a 'neighbor'
1180
enemiesTouchingOurCapConnectedTers.add(enemyTer.getOwner());
1183
PlayerID weakestEnemyNeighbor = null;
1184
int weakestEnemyTUV = Integer.MAX_VALUE;
1185
for(PlayerID enemy : enemiesTouchingOurCapConnectedTers)
1187
int tuv = GetTUVOfUnits(GetUnitsMatchingXInTerritoriesMatchingY(data, Matches.unitIsOwnedBy(enemy), Matches.TerritoryIsLandOrWater), GlobalCenter.GetPUResource());
1188
if(tuv < weakestEnemyTUV)
1190
weakestEnemyNeighbor = enemy;
1191
weakestEnemyTUV = tuv;
1195
if(weakestEnemyNeighbor != null)
1196
result.put(weakestEnemyNeighbor, StrategyType.Enemy_Offensive); //For now, only go on the offensive on our weakest neighbor
1198
for (PlayerID otherPlayer : data.getPlayerList())
1200
if(otherPlayer == player)
1202
if (data.getAllianceTracker().isAtWar(player, otherPlayer))
1204
if(result.containsKey(otherPlayer)) //If this player already has an assignment
1207
result.put(otherPlayer, StrategyType.Enemy_Defensive);
1209
else //Shouldn't ever happen in FFA's...
1210
result.put(otherPlayer, StrategyType.Ally_OffensiveAssist);
1214
DUtils.Log(Level.FINE, " Calculated strategy assignments: {0}", result);
1217
public static float GetCMTaskPriority_LandGrab(GameData data, PlayerID player, Territory ter)
1219
float priority = 1000000F;
1220
priority += DUtils.GetValueOfLandTer(ter, data, player);
1222
StrategyType strategyType = StrategyCenter.get(data, player).GetCalculatedStrategyAssignments().get(ter.getOwner());
1223
if(strategyType == StrategyType.Enemy_Offensive)
1227
public static float GetCMTaskPriority_Stabalization(GameData data, PlayerID player, Territory ter)
1229
float priority = 100F;
1230
priority += DUtils.GetValueOfLandTer(ter, data, player);
1231
if(TerritoryAttachment.getAllCapitals(player, data).contains(ter))
1236
public static float GetCMTaskPriority_Offensive(GameData data, PlayerID player, Territory ter)
1238
float priority = 0F;
1239
final Territory ourCap = GetOurClosestCap(data, player, ter);
1240
priority += DUtils.GetValueOfLandTer(ter, data, player);
1242
Territory neighborWeAreInThatsClosestToOurCap = null; //Atm, we use this to tell 'where we are attacking from'
1243
int closestToCapDist = Integer.MAX_VALUE;
1244
for (Territory neighbor : data.getMap().getNeighbors(ter, Matches.territoryHasUnitsOwnedBy(player)))
1246
Route routeToCap = data.getMap().getLandRoute(neighbor, ourCap);
1247
if (routeToCap == null)
1250
int dist = routeToCap.getLength();
1251
if (dist < closestToCapDist)
1253
neighborWeAreInThatsClosestToOurCap = neighbor;
1254
closestToCapDist = dist;
1258
if (neighborWeAreInThatsClosestToOurCap != null) //This code block will not run if ter does not have a land path to our cap
1260
Territory closestEnemyCapForOurTer = GetClosestTerInList(data, DUtils.GetAllCapsOwnedByEnemies(data, player), neighborWeAreInThatsClosestToOurCap);
1261
Territory closestEnemyCapForTarget = GetClosestTerInList(data, DUtils.GetAllCapsOwnedByEnemies(data, player), ter);
1263
if (closestEnemyCapForOurTer != null && closestEnemyCapForTarget != null) //If there aren't capitals left to take, skip this part
1265
//2) Is the territory-we-would-move-to closer to the closest enemy capital than the territory-we-are-currently-in? (ie: are we moving towards any enemy capital at all) If so, give 6 points.
1266
if (closestEnemyCapForOurTer.getName().equals(closestEnemyCapForTarget.getName()))
1268
if (DUtils.GetJumpsFromXToY_PassableLand(data, ter, closestEnemyCapForTarget) < DUtils.GetJumpsFromXToY_PassableLand(data, neighborWeAreInThatsClosestToOurCap, closestEnemyCapForTarget))
1275
Territory closestFactToOurTer = DUtils.GetClosestTerMatchingXAndHavingRouteMatchingY(data, neighborWeAreInThatsClosestToOurCap, Matches.territoryHasUnitsThatMatch(new CompositeMatchAnd<Unit>(Matches.UnitIsFactory, Matches.unitIsEnemyOf(data, player))), Matches.TerritoryIsLand);
1276
//3) Are we moving towards the closest enemy factory?
1277
if (DUtils.GetJumpsFromXToY_PassableLand(data, ter, closestFactToOurTer) < DUtils.GetJumpsFromXToY_PassableLand(data, neighborWeAreInThatsClosestToOurCap, closestFactToOurTer))
1279
float productionPercentOfHighest = (float) TerritoryAttachment.get(closestFactToOurTer).getProduction() / (float) GlobalCenter.HighestTerProduction;
1280
priority += productionPercentOfHighest * 5; //If so, add 2 to 5 points, depending on value of factory and territory.
1284
List<Territory> enemyCaps = GetAllCapsOwnedByEnemies(data, player);
1285
if(enemyCaps.contains(ter))
1288
if(ter.getOwner().isNull())
1289
priority = (priority * .75F); //Neutral attacks aren't as important
1291
int enemyNeighbors = data.getMap().getNeighbors(ter, CompMatchAnd(Matches.TerritoryIsLand, DMatches.territoryIsOwnedByEnemy(data, player))).size();
1292
if(ter.getOwner().isNull())
1293
priority = priority / (enemyNeighbors * 2);
1295
int friendlyNeighbors = data.getMap().getNeighbors(ter, CompMatchAnd(Matches.TerritoryIsLand, DMatches.territoryIsOwnedByXOrAlly(data, player))).size();
1296
priority += friendlyNeighbors;
1298
StrategyType strategyType = StrategyCenter.get(data, player).GetCalculatedStrategyAssignments().get(ter.getOwner());
1299
if(strategyType == StrategyType.Enemy_Offensive)
1304
public static float GetCMTaskPriority_Trade(GameData data, PlayerID player, Territory ter)
1306
float priority = 1000F;
1307
priority += DUtils.GetValueOfLandTer(ter, data, player);
1309
StrategyType strategyType = StrategyCenter.get(data, player).GetCalculatedStrategyAssignments().get(ter.getOwner());
1310
if(strategyType == StrategyType.Enemy_Offensive)
1315
//As a note to any developers reading this, these priority deciding methods need a lot more work.
1316
public static float GetNCMTaskPriority_Block(GameData data, PlayerID player, Territory ter)
1318
float priority = 1000F; //TODO
1319
priority += GetValueOfLandTer(ter, data, player);
1322
public static float GetNCMTaskPriority_Frontline(GameData data, PlayerID player, Territory ter)
1324
float priority = 500F; //TODO
1325
priority += GetValueOfLandTer(ter, data, player);
1326
priority += data.getMap().getNeighbors(ter, DMatches.territoryIsOwnedByNNEnemy(data, player)).size() * 5;
1329
public static float GetNCMTaskPriority_Stabalize(GameData data, PlayerID player, Territory ter)
1331
float priority = 750F; //TODO
1332
priority += GetValueOfLandTer(ter, data, player);
1335
public static float GetNCMCallPriority_ForLandGrab(GameData data, PlayerID player, Territory ter)
1337
float priority = 1000F; //TODO
1338
priority += GetValueOfLandTer(ter, data, player);
1341
public static float GetNCMCallPriority_ForDefensiveFront(GameData data, PlayerID player, Territory ter)
1343
float priority = 1000000F;
1344
priority += GetValueOfLandTer(ter, data, player);
1347
public static float GetNCMCallPriority_ForCapitalDefense(GameData data, PlayerID player, Territory ter)
1349
float priority = 0F; //TODO
1350
priority += GetValueOfLandTer(ter, data, player);
1353
public static int GetDistance_ForLandThenNoCondComparison(GameData data, Territory ter1, Territory ter2)
1355
Route route1 = CachedCalculationCenter.GetLandRoute(data, ter1, ter2);
1356
Route route1_nc = CachedCalculationCenter.GetRoute(data, ter1, ter2);
1358
if (route1_nc == null)
1359
return DConstants.Integer_HalfMax; //If there's no route, we want ones with a route to come first
1361
int distance1 = route1_nc.getLength() * 100;
1363
distance1 = route1.getLength();
1368
* Basically, this method uses the battle calculator to sort the units so while adding each unit into the new list, the attack score is the highest possible at each unit add.
1369
* (Atm, this method does not work well...)
1371
public static List<Unit> InterleaveUnits_ForBestAttack(List<Unit> units)
1373
GameData data = units.get(0).getData();
1374
Territory battleTer = (Territory)data.getMap().getTerritories().toArray()[0];
1375
PlayerID player = GlobalCenter.CurrentPlayer;
1377
List<Unit> defendStack = MultiplyDefenderUnitsTillTakeoverChanceIsLessThanX(units, Collections.singletonList(GetRandomUnitForPlayerMatching(battleTer.getOwner(), DMatches.UnitCanDefend)), data, battleTer, .9F);
1379
List<Unit> leftToAdd = new ArrayList<Unit>(units);
1380
ArrayList<Unit> result = new ArrayList<Unit>();
1382
while(result.size() < units.size())
1384
Unit nextToAdd = CalculateUnitThatWillHelpWinAttackOnArmyTheMostPerPU(battleTer, data, player, result, leftToAdd, defendStack, Match.ALWAYS_MATCH, DSettings.LoadSettings().CA_CMNCM_sortsPossibleTaskRecruitsForOptimalAttackDefense);
1386
result.add(nextToAdd);
1387
leftToAdd.remove(nextToAdd);
1392
public static List<Unit> InterleaveUnits_SoWhileSortingYPercentOfUnitsMatchX(List<Unit> units, Match<Unit> match, float percentage)
1394
List<Unit> result = new ArrayList<Unit>();
1395
double xToOthersRatio = 0.5F;
1396
while(result.size() < units.size())
1398
Unit nextToAdd = null;
1399
if (xToOthersRatio < percentage) //If less than Y% of units are matching x, seek x matching unit
1400
nextToAdd = GetFirstUnitMatching(units, CompMatchAnd(match, DMatches.unitIsNotInList(result)), 0);
1401
else if (xToOthersRatio > percentage) //If more than Y% of units are matching x, seek non-x matching unit
1402
nextToAdd = GetFirstUnitMatching(units, CompMatchAnd(match.invert(), DMatches.unitIsNotInList(result)), 0);
1403
if(nextToAdd == null) //If we can no longer keep up this ratio, add leftover units, then break and return
1405
result.addAll(Match.getMatches(units, DMatches.unitIsNotInList(result)));
1409
result.add(nextToAdd);
1411
if (match.match(nextToAdd))
1413
double dif = 1.0F - xToOthersRatio;
1414
xToOthersRatio += (dif / (double)result.size());
1418
double dif = 0.0F - xToOthersRatio; //Yes, I know this is the same as -airToLandRatio...
1419
xToOthersRatio += (dif / (double)result.size());
1424
public static List<Unit> InterleaveUnits_CarriersAndPlanes(List<Unit> units, int planesThatDontNeedToLand)
1426
if (!(Match.someMatch(units, Matches.UnitIsCarrier) && Match.someMatch(units, Matches.UnitCanLandOnCarrier)))
1429
//Clone the current list
1430
ArrayList<Unit> result = new ArrayList<Unit>(units);
1432
Unit seekedCarrier = null;
1433
int indexToPlaceCarrierAt = -1;
1434
int spaceLeftOnSeekedCarrier = -1;
1435
int processedPlaneCount = 0;
1436
List<Unit> filledCarriers = new ArrayList<Unit>();
1437
//Loop through all units, starting from the right, and rearrange units
1438
for (int i = result.size() - 1; i >= 0; i--)
1440
Unit unit = result.get(i);
1441
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
1442
if (ua.getCarrierCost() > 0) //If this is a plane
1444
if(processedPlaneCount < planesThatDontNeedToLand) //If we haven't ignored enough trailing planes
1446
processedPlaneCount++; //Increase number of trailing planes ignored
1447
continue; //And skip any processing
1450
if (seekedCarrier == null) //If this is the first carrier seek
1452
int seekedCarrierIndex = GetIndexOfLastUnitMatching(result, CompMatchAnd(Matches.UnitIsCarrier, DMatches.unitIsNotInList(filledCarriers)), result.size() - 1);
1453
if (seekedCarrierIndex == -1)
1454
break; //No carriers left
1455
seekedCarrier = units.get(seekedCarrierIndex);
1457
indexToPlaceCarrierAt = i + 1; //Tell the code to insert carrier to the right of this plane
1458
spaceLeftOnSeekedCarrier = UnitAttachment.get(seekedCarrier.getUnitType()).getCarrierCapacity();
1460
spaceLeftOnSeekedCarrier -= ua.getCarrierCost();
1461
if(spaceLeftOnSeekedCarrier <= 0) //If the carrier has been filled or overflowed
1463
if(spaceLeftOnSeekedCarrier < 0) //If we over-filled the old carrier
1464
i++; //Move current unit index up one, so we re-process this unit (since it can't fit on the current seeked carrier)
1466
if (result.indexOf(seekedCarrier) < i) //If the seeked carrier is earlier in the list
1468
//Move the carrier up to the planes by: removing carrier, then reinserting it (index decreased cause removal of carrier reduced indexes)
1469
result.remove(seekedCarrier);
1470
result.add(indexToPlaceCarrierAt - 1, seekedCarrier);
1471
i--; //We removed carrier in earlier part of list, so decrease index
1472
filledCarriers.add(seekedCarrier);
1474
//Find the next carrier
1475
seekedCarrier = GetLastUnitMatching(result, CompMatchAnd(Matches.UnitIsCarrier, DMatches.unitIsNotInList(filledCarriers)), result.size() - 1);
1476
if (seekedCarrier == null)
1477
break; //No carriers left
1478
indexToPlaceCarrierAt = i; //Place next carrier right before this plane (which just filled the old carrier that was just moved)
1479
spaceLeftOnSeekedCarrier = UnitAttachment.get(seekedCarrier.getUnitType()).getCarrierCapacity();
1481
else //If it's later in the list
1483
int oldIndex = result.indexOf(seekedCarrier);
1484
int carrierPlaceLocation = indexToPlaceCarrierAt;
1485
//Place carrier where it's supposed to go
1486
result.remove(seekedCarrier);
1487
if (oldIndex < indexToPlaceCarrierAt)
1488
carrierPlaceLocation--;
1489
result.add(carrierPlaceLocation, seekedCarrier);
1490
filledCarriers.add(seekedCarrier);
1492
//Move the planes down to the carrier
1493
List<Unit> planesBetweenHereAndCarrier = new ArrayList<Unit>();
1494
for(int i2 = i;i2 < carrierPlaceLocation;i2++)
1496
Unit unit2 = result.get(i2);
1497
UnitAttachment ua2 = UnitAttachment.get(unit2.getUnitType());
1498
if (ua2.getCarrierCost() > 0)
1499
planesBetweenHereAndCarrier.add(unit2);
1501
planesBetweenHereAndCarrier = InvertList(planesBetweenHereAndCarrier); //Invert list, so they are inserted in the same order
1502
int planeMoveCount = 0;
1503
for (Unit plane : planesBetweenHereAndCarrier)
1505
result.remove(plane);
1506
result.add(carrierPlaceLocation - 1, plane); //Insert each plane right before carrier (index decreased cause removal of carrier reduced indexes)
1510
//Find the next carrier
1511
seekedCarrier = GetLastUnitMatching(result, CompMatchAnd(Matches.UnitIsCarrier, DMatches.unitIsNotInList(filledCarriers)), result.size() - 1);
1512
if (seekedCarrier == null)
1513
break; //No carriers left
1514
indexToPlaceCarrierAt = carrierPlaceLocation - planeMoveCount; //Since we only moved planes up, just reduce next carrier place index by plane move count
1515
spaceLeftOnSeekedCarrier = UnitAttachment.get(seekedCarrier.getUnitType()).getCarrierCapacity();
1523
public static List<Unit> InterleaveUnits_InfantryAndArtillery(List<Unit> units, int infantryPerArtillery, int infantryThatDontNeedArtillery)
1525
if (!(Match.someMatch(units, Matches.UnitIsArtillery) && Match.someMatch(units, Matches.UnitIsArtillerySupportable)))
1528
//Clone the current list
1529
ArrayList<Unit> result = new ArrayList<Unit>(units);
1531
Unit seekedArtillery = null;
1532
int indexToPlaceArtAt = -1;
1533
int spaceLeftOnSeekedArt = -1;
1534
int processedInfantryCount = 0;
1535
List<Unit> filledArts = new ArrayList<Unit>();
1536
//Loop through all units, starting from the right, and rearrange units
1537
for (int i = result.size() - 1; i >= 0; i--)
1539
Unit unit = result.get(i);
1540
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
1541
if (ua.isArtillerySupportable()) //If this is an infantry
1543
if(processedInfantryCount < infantryThatDontNeedArtillery) //If we haven't ignored enough trailing infantry
1545
processedInfantryCount++; //Increase number of trailing infantry ignored
1546
continue; //And skip any processing
1549
if (seekedArtillery == null) //If this is the first artillery seek
1551
int seekedArtIndex = GetIndexOfLastUnitMatching(result, CompMatchAnd(Matches.UnitIsArtillery, DMatches.unitIsNotInList(filledArts)), result.size() - 1);
1552
if (seekedArtIndex == -1)
1553
break; //No artilleries left
1554
seekedArtillery = units.get(seekedArtIndex);
1556
indexToPlaceArtAt = i + 1; //Tell the code to insert artillery to the right of this infantry
1557
spaceLeftOnSeekedArt = infantryPerArtillery;
1559
spaceLeftOnSeekedArt -= 1;
1560
if(spaceLeftOnSeekedArt <= 0) //If the artillery has been filled or overflowed
1562
if(spaceLeftOnSeekedArt < 0) //If we over-filled the old artillery
1563
i++; //Move current unit index up one, so we re-process this unit (since it can't fit on the current seeked artillery)
1565
if (result.indexOf(seekedArtillery) < i) //If the seeked artillery is earlier in the list
1567
//Move the artillery up to the infantry by: removing artillery, then reinserting it (index decreased cause removal of artillery reduced indexes)
1568
result.remove(seekedArtillery);
1569
result.add(indexToPlaceArtAt - 1, seekedArtillery);
1570
i--; //We removed artillery in earlier part of list, so decrease index
1571
filledArts.add(seekedArtillery);
1573
//Find the next artillery
1574
seekedArtillery = GetLastUnitMatching(result, CompMatchAnd(Matches.UnitIsArtillery, DMatches.unitIsNotInList(filledArts)), result.size() - 1);
1575
if (seekedArtillery == null)
1576
break; //No artillery left
1577
indexToPlaceArtAt = i; //Place next artillery right before this infantry (which just filled the old artillery that was just moved)
1578
spaceLeftOnSeekedArt = infantryPerArtillery;
1580
else //If it's later in the list
1582
int oldIndex = result.indexOf(seekedArtillery);
1583
int artPlaceLocation = indexToPlaceArtAt;
1584
//Place artillery where it's supposed to go
1585
result.remove(seekedArtillery);
1586
if (oldIndex < indexToPlaceArtAt)
1588
result.add(artPlaceLocation, seekedArtillery);
1589
filledArts.add(seekedArtillery);
1591
//Move the infantry down to the artillery
1592
List<Unit> infantryBetweenHereAndArtillery = new ArrayList<Unit>();
1593
for(int i2 = i;i2 < artPlaceLocation;i2++)
1595
Unit unit2 = result.get(i2);
1596
UnitAttachment ua2 = UnitAttachment.get(unit2.getUnitType());
1597
if (ua2.isArtillerySupportable())
1598
infantryBetweenHereAndArtillery.add(unit2);
1600
infantryBetweenHereAndArtillery = InvertList(infantryBetweenHereAndArtillery); //Invert list, so they are inserted in the same order
1601
int infantryMoveCount = 0;
1602
for (Unit infantry : infantryBetweenHereAndArtillery)
1604
result.remove(infantry);
1605
result.add(artPlaceLocation - 1, infantry); //Insert each infantry right before artillery (index decreased cause removal of artillery reduced indexes)
1606
infantryMoveCount++;
1609
//Find the next artillery
1610
seekedArtillery = GetLastUnitMatching(result, CompMatchAnd(Matches.UnitIsArtillery, DMatches.unitIsNotInList(filledArts)), result.size() - 1);
1611
if (seekedArtillery == null)
1612
break; //No artillery left
1613
indexToPlaceArtAt = artPlaceLocation - infantryMoveCount; //Since we only moved infantry up, just reduce next artillery place index by infantry move count
1614
spaceLeftOnSeekedArt = infantryPerArtillery;
1622
public static Unit GetLastUnitMatching(List<Unit> units, Match<Unit> match, int endIndex)
1624
int index = GetIndexOfLastUnitMatching(units, match, endIndex);
1627
return units.get(index);
1629
public static int GetIndexOfLastUnitMatching(List<Unit> units, Match<Unit> match, int endIndex)
1631
for (int i = endIndex; i >= 0; i--)
1633
Unit unit = units.get(i);
1634
if (match.match(unit))
1639
public static Unit GetFirstUnitMatching(List<Unit> units, Match<Unit> match, int startIndex)
1641
int index = GetIndexOfFirstUnitMatching(units, match, startIndex);
1644
return units.get(index);
1646
public static int GetIndexOfFirstUnitMatching(List<Unit> units, Match<Unit> match, int startIndex)
1648
for(int i = startIndex;i < units.size(); i++)
1650
Unit unit = units.get(i);
1651
if(match.match(unit))
1656
public static int HowWellIsUnitSuitedToTask(GameData data, CM_Task task, Territory ter, Unit unit)
1658
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit) && ter != task.GetTarget())
1659
return Integer.MIN_VALUE;
1662
Route route = CachedCalculationCenter.GetRoute(data, ter, task.GetTarget());
1664
return Integer.MIN_VALUE;
1665
int dist = route.getLength();
1667
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
1668
TripleAUnit ta = TripleAUnit.get(unit);
1669
int tuv = DUtils.GetTUVOfUnit(unit, GlobalCenter.GetPUResource());
1670
int movementSpeed = ua.getMovement(unit.getOwner());
1671
int movementLeft = ta.getMovementLeft();
1673
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit))
1676
if (task.GetTaskType() == CM_TaskType.Attack_Offensive)
1678
List<Territory> targets = DUtils.GetTersThatUnitsCanReach(data, Collections.singletonList(unit), ter, GlobalCenter.CurrentPlayer, CompMatchAnd(Matches.TerritoryIsLand, DMatches.territoryIsOwnedByNNEnemy(data, GlobalCenter.CurrentPlayer)));
1679
result -= targets.size(); //We want low-attack target units to attack
1681
else if (task.GetTaskType() == CM_TaskType.Attack_Stabilize)
1683
List<Territory> targets = DUtils.GetTersThatUnitsCanReach(data, Collections.singletonList(unit), ter, GlobalCenter.CurrentPlayer, CompMatchAnd(Matches.TerritoryIsLand, DMatches.territoryIsOwnedByNNEnemy(data, GlobalCenter.CurrentPlayer)));
1684
result -= targets.size(); //We want low-attack target units to attack
1686
else if (task.GetTaskType() == CM_TaskType.LandGrab)
1689
return Integer.MIN_VALUE;
1690
//There's currently a flaw... A blitz unit that's already blitzed a ter is considered in it's 'start' territory for the next blitz (for 3 and up speed units)
1691
int movementAfterBlitz = movementLeft - dist;
1692
if(DSettings.LoadSettings().TR_attackLandGrab_onlyGrabLandIfWeCanBlitzIt)
1694
if(!ua.getCanBlitz() || movementAfterBlitz < dist) //If this unit can't blitz, or it can't take ter and get back
1695
return Integer.MIN_VALUE;
1698
result += movementAfterBlitz * 10; //We want ones that can blitz away the most to attack
1699
result -= dist; //If two halftracks match, we want the closer but with less movement one to blitz it
1701
else if(task.GetTaskType() == CM_TaskType.Attack_Trade)
1703
//Unit pairing or interlacing is, or will be, done in the CM_Task class for trade attacks
1707
public static int HowWellIsUnitSuitedToTask(GameData data, NCM_Task task, Territory ter, Unit unit)
1709
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit) && ter != task.GetTarget())
1710
return Integer.MIN_VALUE;
1713
Route route = CachedCalculationCenter.GetRoute(data, ter, task.GetTarget());
1715
return Integer.MIN_VALUE;
1716
int dist = route.getLength();
1718
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
1719
TripleAUnit ta = TripleAUnit.get(unit);
1720
int tuv = DUtils.GetTUVOfUnit(unit, GlobalCenter.GetPUResource());
1721
int movementSpeed = ua.getMovement(unit.getOwner());
1722
int movementLeft = ta.getMovementLeft();
1724
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit))
1727
if(task.GetTaskType().equals(NCM_TaskType.Reinforce_Block))
1730
return Integer.MIN_VALUE;
1731
result -= tuv; //We will lose unit, so send cheapest
1733
else if(task.GetTaskType().equals(NCM_TaskType.Reinforce_FrontLine))
1736
return Integer.MIN_VALUE;
1737
if (movementLeft == 0 && ter != task.GetTarget())
1738
return Integer.MIN_VALUE;
1740
int turnsToGetThere = (int)Math.ceil((double)dist / (double)movementSpeed);
1742
result -= turnsToGetThere; //We want to reinforce as quickly as possible
1744
//If this is an AA, and we're reinforcing a ter with a factory and no AA yet, we boost the score for this AA
1745
if(ua.isAA() && task.GetTarget().getUnits().getMatches(Matches.UnitIsFactory).size() > 0 && task.GetTarget().getUnits().getMatches(Matches.UnitIsAA).isEmpty())
1748
else if (task.GetTaskType().equals(NCM_TaskType.Reinforce_Stabilize))
1751
return Integer.MIN_VALUE;
1752
if (movementLeft == 0 && ter != task.GetTarget())
1753
return Integer.MIN_VALUE;
1755
int turnsToGetThere = (int)Math.ceil((double)dist / (double)movementSpeed);
1757
result -= turnsToGetThere; //We want to reinforce as quickly as possible
1759
//If this is an AA, and we're reinforcing a ter with a factory and no AA yet, we boost the score for this AA
1760
if(ua.isAA() && task.GetTarget().getUnits().getMatches(Matches.UnitIsFactory).size() > 0 && task.GetTarget().getUnits().getMatches(Matches.UnitIsAA).isEmpty())
1765
public static int HowWellIsUnitSuitedToCall(GameData data, NCM_Call call, Territory ter, Unit unit)
1768
Route route = CachedCalculationCenter.GetRoute(data, ter, call.GetTarget());
1770
return Integer.MIN_VALUE;
1771
int dist = route.getLength();
1773
UnitAttachment ua = UnitAttachment.get(unit.getUnitType());
1774
TripleAUnit ta = TripleAUnit.get(unit);
1775
int tuv = DUtils.GetTUVOfUnit(unit, GlobalCenter.GetPUResource());
1776
int movementSpeed = ua.getMovement(unit.getOwner());
1777
int movementLeft = ta.getMovementLeft();
1779
//With calls, we'll consider recruiting a unit even if it is currently frozen (we don't need the unit to be able to attack or defend somewhere this round)
1780
if(TacticalCenter.get(data, GlobalCenter.CurrentPlayer).GetFrozenUnits().contains(unit))
1783
if(call.GetCallType().equals(NCM_CallType.Call_ForDefensiveFront))
1786
return Integer.MIN_VALUE;
1787
//With calls, we'll consider recruiting a unit even if it is currently frozen (we don't need the unit to be able to attack or defend somewhere this round)
1788
//if (movementLeft == 0 && ter != call.GetTarget())
1789
// return Integer.MIN_VALUE;
1791
int turnsToGetThere = (int)Math.ceil((double)dist / (double)movementSpeed);
1793
result -= turnsToGetThere; //We want to call units there as quickly as possible
1795
else if(call.GetCallType().equals(NCM_CallType.Call_ForLandGrab))
1798
return Integer.MIN_VALUE;
1799
//With calls, we'll consider recruiting a unit even if it is currently frozen (we don't need the unit to be able to attack or defend somewhere this round)
1800
//if (movementLeft == 0 && ter != call.GetTarget())
1801
// return Integer.MIN_VALUE;
1803
int turnsToGetThere = (int)Math.ceil((double)dist / (double)movementSpeed);
1805
result -= turnsToGetThere; //We want to call units there as quickly as possible
1807
else if(call.GetCallType().equals(NCM_CallType.Call_ForCapitalDefense))
1810
return Integer.MIN_VALUE;
1811
//With calls, we'll consider recruiting a unit even if it is currently frozen (we don't need the unit to be able to attack or defend somewhere this round)
1812
//if (movementLeft == 0 && ter != call.GetTarget())
1813
// return Integer.MIN_VALUE;
1815
int turnsToGetThere = (int)Math.ceil((double)dist / (double)movementSpeed);
1817
result -= turnsToGetThere; //We want to call units there as quickly as possible
1822
public static HashMap ToHashMap(Collection keys, Collection values)
1824
HashMap result = new HashMap();
1825
Iterator valueIter = values.iterator();
1826
for(Object key : keys)
1827
result.put(key, valueIter.next());
1830
public static IntegerMap ToIntegerMap(HashMap map)
1832
IntegerMap result = new IntegerMap(map.size());
1833
for(Object key : map.keySet())
1834
result.add(key, Integer.parseInt(map.get(key).toString()));
1837
public static TreeMap ToTreeMap_AutoSortingByValues_A(Map map)
1839
TreeMap result = new TreeMap(new ValueComparator_A(map));
1843
public static TreeMap ToTreeMap_AutoSortingByValues_D(Map map)
1845
TreeMap result = new TreeMap(new ValueComparator_D(map));
1849
static class ValueComparator_A implements Comparator
1852
public ValueComparator_A(Map base)
1856
public int compare(Object a, Object b)
1858
if ((Double) base.get(a) < (Double) base.get(b))
1860
else if ((Double) base.get(a) == (Double) base.get(b))
1866
static class ValueComparator_D implements Comparator
1869
public ValueComparator_D(Map base)
1873
public int compare(Object a, Object b)
1875
if ((Double) base.get(a) > (Double) base.get(b))
1877
else if ((Double) base.get(a) == (Double) base.get(b))
1884
* Determines the TUV lost by the attacker and defender based on the average battle outcome contained in the AggregateResults object.
1885
* @param initialAttackers - The list of attackers before any casualties
1886
* @param initialDefenders - The list of defenders before any casualties
1887
* @param results - The AggregateResults object that contains the average battle outcome.
1888
* @return a list of two integers. The first being the attacker's average TUV loss, the second being the defender's average TUV loss.
1890
public static List<Integer> GetTUVChangeOfAttackerAndDefender(List<Unit> initialAttackers, List<Unit> initialDefenders, AggregateResults results)
1892
PlayerID attacker = null;
1893
if(!initialAttackers.isEmpty())
1894
attacker = initialAttackers.get(0).getOwner();
1895
PlayerID defender = null;
1896
if(!initialDefenders.isEmpty())
1897
defender = initialDefenders.get(0).getOwner();
1899
List<Unit> oldAttackerUnits = Match.getMatches(initialAttackers, DMatches.UnitCanAttack);
1900
List<Unit> oldDefenderUnits = Match.getMatches(initialDefenders, DMatches.UnitCanDefend);
1902
List<Unit> newAttackerUnits = Match.getMatches(results.GetAverageAttackingUnitsRemaining(), DMatches.UnitCanAttack);
1903
List<Unit> newDefenderUnits = Match.getMatches(results.GetAverageDefendingUnitsRemaining(), DMatches.UnitCanDefend);
1905
float oldAttackerTUV = DUtils.GetTUVOfUnits(oldAttackerUnits, GlobalCenter.GetPUResource());
1906
float oldDefenderTUV = DUtils.GetTUVOfUnits(oldDefenderUnits, GlobalCenter.GetPUResource());
1908
float newAttackerTUV = DUtils.GetTUVOfUnits(newAttackerUnits, GlobalCenter.GetPUResource());
1909
float newDefenderTUV = DUtils.GetTUVOfUnits(newDefenderUnits, GlobalCenter.GetPUResource());
1911
float attackerTUVGainOrLoss = newAttackerTUV - oldAttackerTUV;
1912
float defenderTUVGainOrLoss = newDefenderTUV - oldDefenderTUV;
1914
List<Integer> result = new ArrayList<Integer>();
1915
result.add((int)attackerTUVGainOrLoss);
1916
result.add((int)defenderTUVGainOrLoss);
1920
* Returns defender's tuv loss minus attacker's TUV loss. TUV losses are contained in the array supplied, where first array int represents tuv loss for attacker, second for defender.
1922
public static int GetTUVSwingForTUVChange(List<Integer> attackerAndDefenderTUVChanges)
1924
return attackerAndDefenderTUVChanges.get(0) - attackerAndDefenderTUVChanges.get(1);
1926
public static float GetSwingForBeforeAndAfterChange(List<Integer> beforeAndAfter)
1928
return beforeAndAfter.get(1) - beforeAndAfter.get(0);
1930
public static float GetSwingForBeforeAndAfterChange_F(List<Float> beforeAndAfter)
1932
return beforeAndAfter.get(1) - beforeAndAfter.get(0);
1934
public static List<Territory> GetTerritoriesWithinXLandJumpsOfTer(GameData data, Territory territory, int maxJumps, Match<Territory> resultTerMatch)
1936
List<Territory> result = new ArrayList<Territory>();
1937
for (Territory ter : data.getMap().getTerritories())
1939
if (DUtils.CanWeGetFromXToY_ByPassableLand(data, ter, territory))
1941
if (DUtils.GetJumpsFromXToY_PassableLand(data, ter, territory) <= maxJumps)
1948
* Returns the chance of destruction of the supplied army if StrongestPlayerNonNullEnemyUnits that can reach army attack.
1950
public static float GetVulnerabilityOfArmy(GameData data, PlayerID player, Territory ter, List<Unit> defendUnits, int calcRuns)
1952
List<Unit> possibleAttackers = DUtils.GetSPNNEnemyUnitsThatCanReach(data, ter, player, Matches.TerritoryIsLand);
1953
possibleAttackers = Match.getMatches(possibleAttackers, new CompositeMatchOr<Unit>(Matches.UnitIsLand, Matches.UnitIsAir));
1954
AggregateResults results = DUtils.GetBattleResults(possibleAttackers, defendUnits, ter, data, calcRuns, true);
1956
float result = (float)results.getAttackerWinPercent();
1960
* Returns the chance of survival of the supplied army if StrongestPlayerNonNullEnemyUnits that can reach army attack.
1962
public static float GetSurvivalChanceOfArmy(GameData data, PlayerID player, Territory ter, Collection<Unit> defendUnits, int calcRuns)
1964
List<Unit> possibleAttackers = DUtils.GetSPNNEnemyUnitsThatCanReach(data, ter, player, Matches.TerritoryIsLand);
1965
possibleAttackers = Match.getMatches(possibleAttackers, new CompositeMatchOr<Unit>(Matches.UnitIsLand, Matches.UnitIsAir));
1966
AggregateResults results = DUtils.GetBattleResults(possibleAttackers, defendUnits, ter, data, calcRuns, true);
1968
float result = (float)results.getDefenderWinPercent();
1971
public static float average(Float ... values)
1974
for(Float val : values)
1976
return total / values.length;
1978
public static List<Territory> GetTerritoriesWithinXDistanceOfY(GameData data, Territory start, int maxDistance)
1980
return GetTerritoriesWithinXDistanceOfYMatchingZ(data, start, maxDistance, Match.ALWAYS_MATCH);
1982
public static List<Territory> GetTerritoriesWithinXDistanceOfYMatchingZ(GameData data, Territory start, int maxDistance, Match<Territory> match)
1984
return GetTerritoriesWithinXDistanceOfYMatchingZAndHavingRouteMatchingA(data, start, maxDistance, match, Match.ALWAYS_MATCH);
1986
public static List<Territory> GetTerritoriesWithinXDistanceOfYMatchingZAndHavingRouteMatchingA(GameData data, Territory start, int maxDistance, Match<Territory> match, Match<Territory> routeMatch)
1988
HashSet<Territory> processed = new HashSet<Territory>();
1989
processed.add(start);
1991
List<Territory> result = new ArrayList<Territory>();
1992
HashSet<Territory> nextSet = new HashSet<Territory>(data.getMap().getNeighbors(start));
1993
if(match.match(start))
1996
while(nextSet.size() > 0 && dist <= maxDistance)
1998
HashSet<Territory> newSet = new HashSet<Territory>();
1999
for(Territory ter : nextSet)
2002
if(routeMatch.match(ter))
2004
List<Territory> neighbors = DUtils.ToList(data.getMap().getNeighbors(ter));
2005
newSet.addAll(neighbors); //Add all this ter's neighbors to the next set for checking
2006
//(don't worry, neighbors already processed or in this current nextSet will be removed)
2008
if (match.match(ter))
2011
newSet.removeAll(processed); //Don't check any that have been processed
2017
public static List<Territory> GetEnemySeaTersThatCanBeAttackedBySeaOrAirUnitsOwnedBy(GameData data, PlayerID player)
2019
List<Territory> result = new ArrayList<Territory>();
2020
for (Territory ter : data.getMap().getTerritories())
2025
List<Unit> possibleAttackers = DUtils.GetUnitsOwnedByPlayerThatCanReach(data, ter, player, Matches.TerritoryIsLand);
2026
possibleAttackers = Match.getMatches(possibleAttackers, new CompositeMatchOr<Unit>(Matches.UnitIsSea, Matches.UnitIsAir));
2028
if(possibleAttackers.size() > 0)
2033
public static List CloneList(Collection list)
2035
return new ArrayList(list);
2037
public static UnitType GetRandomUnitType()
2039
return (UnitType)GlobalCenter.GetMergedAndAveragedProductionFrontier().getRules().get(0).getResults().keySet().iterator().next();
2042
* Runs simulated battles numerous times and returns an AggregateResults object that lists the percent of times the attacker won, lost, etc.
2043
* @param attacking - The units that are attacking in this battle
2044
* @param defending - The units that are defending in this battle
2045
* @param testingTer - The territory this battle will be simulated on. (You might be able to use any territory, I'm unsure)
2046
* @param data - The game data containing the map, units, players, etc.
2047
* @param runCount - How many times to simulate the battle. The more it's simulated, the more accurate the results will be
2048
* @param toTake - Whether the attacker needs to have a unit left over after the attack to take the territory for a battle simulation to be counted as a win
2049
* @return Returns an AggregateResults object that lists the percent of times the attacker won, lost, etc.
2051
public static AggregateResults GetBattleResults(Collection<Unit> attacking, Collection<Unit> defending, Territory testingTer, GameData data, int runCount, boolean toTake)
2053
if (attacking == null || attacking.isEmpty())
2055
if (defending == null || defending.isEmpty())
2057
if (toTake) //If the calculation is to check for takeover and armies are empty, never set as draw, set it as defender win(defender keeps ter)
2058
return CreateDefenderWinsAggregateResults(data, testingTer, defending); //Signal as defender wins
2060
return CreateDrawAggregateResults(data, testingTer); //Signal as draw
2062
return CreateDefenderWinsAggregateResults(data, testingTer, defending);//Signal as defender wins
2064
else if(defending == null || defending.isEmpty())
2066
if(toTake && Match.getNMatches(attacking, 1, Matches.UnitIsLand).isEmpty()) //If we're supposed to take ter, but we don't have any land attacking
2067
return CreateDefenderWinsAggregateResults(data, testingTer, defending); //Signal as defender wins(defender keeps ter)
2068
return CreateAttackerWinsAggregateResults(data, testingTer, attacking); //Signal as attacker wins
2071
PlayerID attacker = attacking.iterator().next().getOwner();
2072
PlayerID defender = defending.iterator().next().getOwner();
2076
if (DSettings.LoadSettings().AllowCalcingDecrease && Dynamix_AI.GetTimeTillNextScheduledActionDisplay() == 0) //Hmmm... Let's try to speed things up to reach the user-specified action length
2077
runCount = (int) DUtils.Limit(runCount * DUtils.ToFloat(DSettings.LoadSettings().CalcingDecreaseToPercentage), 1.0F, Integer.MAX_VALUE);
2079
float attackerUnitsStrength = DUtils.GetAttackScoreOfUnits(attacking);
2080
float defenderUnitsStrength = DUtils.GetDefenseScoreOfUnits(defending);
2082
if (attackerUnitsStrength > defenderUnitsStrength * 2) //If attacker has a huge attack/defense score advantage
2083
runCount = (int) DUtils.Limit(runCount / ((attackerUnitsStrength / defenderUnitsStrength) * 5), 1.0F, Integer.MAX_VALUE); //Then reduce calcing count, as we're pretty sure attacker will win
2084
else if (defenderUnitsStrength > attackerUnitsStrength * 2)
2085
runCount = (int) DUtils.Limit(runCount / ((defenderUnitsStrength / attackerUnitsStrength) * 5), 1.0F, Integer.MAX_VALUE); //Then reduce calcing count, as we're pretty sure defender will win
2087
if(Properties.getLow_Luck(data))
2088
runCount = (int) DUtils.Limit(runCount / 5.0F, 10.0F, Integer.MAX_VALUE); //Reduce calcing count, as we're playing with LL
2091
DOddsCalculator calc = new DOddsCalculator();
2092
calc.setKeepOneAttackingLandUnit(toTake);
2094
AggregateResults results = calc.calculate(data, attacker, defender, testingTer, attacking, defending, new ArrayList<Unit>(), runCount);
2095
if(toTake) //If we're supposed to 'take' ter
2097
//But the attackers averaged without a land unit left (or there are no attackers left after battle)
2098
if(results == null || results.GetAverageAttackingUnitsRemaining() == null || Match.getNMatches(results.GetAverageAttackingUnitsRemaining(), 1, Matches.unitIsLandAndOwnedBy(attacker)).isEmpty())
2099
return CreateDefenderWinsAggregateResults(data, testingTer, defending); //Signal as defender wins
2103
public static AggregateResults CreateAttackerWinsAggregateResults(GameData data, Territory ter, Collection<Unit> attacking)
2105
MustFightBattle battle = new MustFightBattle(ter, PlayerID.NULL_PLAYERID, data, null);
2106
battle.setUnits(new ArrayList<Unit>(), attacking, new ArrayList<Unit>(), PlayerID.NULL_PLAYERID);
2107
BattleResults result = new BattleResults(battle);
2108
AggregateResults dWins = new AggregateResults(1);
2109
dWins.addResult(result);
2112
public static AggregateResults CreateDefenderWinsAggregateResults(GameData data, Territory ter, Collection<Unit> defending)
2114
MustFightBattle battle = new MustFightBattle(ter, PlayerID.NULL_PLAYERID, data, null);
2115
battle.setUnits(defending, new ArrayList<Unit>(), new ArrayList<Unit>(), PlayerID.NULL_PLAYERID);
2116
BattleResults result = new BattleResults(battle);
2117
AggregateResults dWins = new AggregateResults(1);
2118
dWins.addResult(result);
2121
public static AggregateResults CreateDrawAggregateResults(GameData data, Territory ter)
2123
MustFightBattle battle = new MustFightBattle(ter, PlayerID.NULL_PLAYERID, data, null);
2124
battle.setUnits(new ArrayList<Unit>(), new ArrayList<Unit>(), new ArrayList<Unit>(), PlayerID.NULL_PLAYERID);
2125
BattleResults result = new BattleResults(battle);
2126
AggregateResults dWins = new AggregateResults(1);
2127
dWins.addResult(result);
2130
public static List<Unit> getMoveableUnits(List<Unit> units)
2132
List<Unit> values = new ArrayList<Unit>();
2133
Iterator<Unit> iter = units.iterator();
2134
while (iter.hasNext())
2136
Unit unit = iter.next();
2137
if (Matches.unitHasMovementLeft.match(unit))
2142
public static int GetTaskTradeScore(GameData data, Territory target, List<Unit> attackers, List<Unit> defenders, AggregateResults simulatedAttack, List<Unit> responseAttackers, List<Unit> responseDefenders, AggregateResults simulatedResponse)
2144
if(simulatedAttack.getAttackerWinPercent() < .5F)
2145
return DConstants.Integer_HalfMin;
2147
List<Integer> tuvLosses = DUtils.GetTUVChangeOfAttackerAndDefender(attackers, defenders, simulatedAttack);
2148
int tuvSwing = DUtils.GetTUVSwingForTUVChange(tuvLosses);
2149
int responseTUVSwing = 0;
2150
if (simulatedResponse != null) //Will be null if the caller didn't want this method to care about counter-attacks
2152
List<Integer> responseTUVLosses = DUtils.GetTUVChangeOfAttackerAndDefender(responseAttackers, responseDefenders, simulatedResponse);
2153
responseTUVSwing = DUtils.GetTUVSwingForTUVChange(responseTUVLosses);
2155
int terProduction = GetProduction_PlusExtra(target);
2156
if(Match.getMatches(simulatedAttack.GetAverageAttackingUnitsRemaining(), Matches.UnitIsLand).isEmpty()) //If no land units survive, on average
2157
terProduction = 0; //Don't count in ter production
2159
int score = terProduction + tuvSwing;
2160
if(responseTUVSwing > 0) //If it makes sense for the enemy to counter-attack us
2161
score = score - (responseTUVSwing / 2); //Then count our loss in this counter attack against us
2165
public static List<UnitGroup> TrimRecruits_NonMovedOnes(List<UnitGroup> list, int toTrim)
2168
List<UnitGroup> result = new ArrayList<UnitGroup>();
2169
for(int i = list.size() - 1;i >= 0;i--)
2171
UnitGroup ug = list.get(i);
2172
if(ug.GetMovedTo() != null || trimmed >= toTrim)
2179
public static Route TrimRoute_AtFirstTerWithEnemyUnits(Route route, int newRouteJumpCount, PlayerID player, GameData data)
2181
return TrimRoute_AtFirstTerMatchingX(route, newRouteJumpCount, player, data, Matches.territoryHasUnitsThatMatch(new CompositeMatchAnd<Unit>(Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1), Matches.unitIsEnemyOf(data, player))));
2183
public static Route TrimRoute_AtFirstTerMatchingX(Route route, int newRouteJumpCount, PlayerID player, GameData data, Match<Territory> match)
2185
List<Territory> newTers = new ArrayList<Territory>();
2187
for (Territory ter : route.getTerritories())
2190
if (match.match(ter))
2193
if (i > newRouteJumpCount)
2196
return new Route(newTers);
2198
public static Route TrimRoute_AtLastFriendlyTer(Route route, int newRouteJumpCount, PlayerID player, GameData data)
2200
return TrimRoute_BeforeFirstTerMatching(route, newRouteJumpCount, player, data, DMatches.territoryIsOwnedByEnemy(data, player));
2202
public static Route TrimRoute_BeforeFirstTerMatching(Route route, int newRouteJumpCount, PlayerID player, GameData data, Match<Territory> match)
2204
List<Territory> newTers = new ArrayList<Territory>();
2206
for(Territory ter : route.getTerritories())
2208
if(match.match(ter))
2212
if(i > newRouteJumpCount)
2215
if(newTers.size() < 2)
2217
return new Route(newTers);
2219
public static Route TrimRoute_BeforeFirstTerWithEnemyUnits(Route route, int newRouteJumpCount, PlayerID player, GameData data)
2221
return TrimRoute_BeforeFirstTerMatching(route, newRouteJumpCount, player, data, Matches.territoryHasUnitsThatMatch(new CompositeMatchAnd<Unit>(Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1), Matches.unitIsEnemyOf(data, player))));
2223
public static Route TrimRoute_ToLength(Route route, int newRouteJumpCount, PlayerID player, GameData data)
2225
List<Territory> newTers = new ArrayList<Territory>();
2227
for(Territory ter : route.getTerritories())
2231
if(i > newRouteJumpCount)
2234
if(newTers.size() < 2)
2236
return new Route(newTers);
2238
public static int GetJumpsFromXToY_NoCond(GameData data, Territory ter1, Territory ter2)
2240
Route route = CachedCalculationCenter.GetRoute(data, ter1, ter2);
2242
return Integer.MAX_VALUE;
2243
return route.getLength();
2245
public static int GetJumpsFromXToY_AirPassable(GameData data, Territory ter1, Territory ter2)
2247
Route route = CachedCalculationCenter.GetAirPassableRoute(data, ter1, ter2);
2249
return Integer.MAX_VALUE;
2250
return route.getLength();
2253
* Almost always, you'll want to use GetJumpsFromXToY_PassableLand instead of this
2255
public static int GetJumpsFromXToY_Land(GameData data, Territory ter1, Territory ter2)
2257
Route route = CachedCalculationCenter.GetLandRoute(data, ter1, ter2);
2259
return DConstants.Integer_HalfMax;
2260
if(ter1.getName().equals(ter2.getName()) || route.getLength() < 1)
2261
return DConstants.Integer_HalfMax;
2262
return route.getLength();
2264
public static int GetJumpsFromXToY_PassableLand(GameData data, Territory ter1, Territory ter2)
2266
Route route = CachedCalculationCenter.GetPassableLandRoute(data, ter1, ter2);
2268
return DConstants.Integer_HalfMax;
2269
if(ter1.getName().equals(ter2.getName()) || route.getLength() < 1)
2270
return DConstants.Integer_HalfMax;
2271
return route.getLength();
2273
public static int GetJumpsFromXToY_Sea(GameData data, Territory ter1, Territory ter2)
2275
Route route = CachedCalculationCenter.GetSeaRoute(data, ter1, ter2);
2277
return DConstants.Integer_HalfMax;
2278
if(ter1.getName().equals(ter2.getName()) || route.getLength() < 1)
2279
return DConstants.Integer_HalfMax;
2280
return route.getLength();
2283
* Almost always, you'll want to use CanWeGetFromXToY_ByPassableLand instead of this
2285
public static boolean CanWeGetFromXToY_ByLand(GameData data, Territory ter1, Territory ter2)
2287
if(ter1 == null || ter2 == null)
2289
return CachedCalculationCenter.GetLandRoute(data, ter1, ter2) != null;
2291
public static boolean CanWeGetFromXToY_ByPassableLand(GameData data, Territory ter1, Territory ter2)
2293
if(ter1 == null || ter2 == null)
2295
return CachedCalculationCenter.GetPassableLandRoute(data, ter1, ter2) != null;
2297
public static boolean CanWeGetFromXToY_BySea(GameData data, Territory ter1, Territory ter2)
2299
if(ter1 == null || ter2 == null)
2301
return CachedCalculationCenter.GetSeaRoute(data, ter1, ter2) != null;
2303
public static boolean CanWeAttackFromXToY_ByLand(GameData data, PlayerID player, Territory ter1, Territory ter2)
2305
return GetAttackRouteFromXToY_ByLand(data, player, ter1, ter2) != null;
2307
public static Route GetAttackRouteFromXToY_ByLand(GameData data, PlayerID player, Territory ter1, Territory ter2)
2311
if(ter1 == null || ter2 == null)
2313
return data.getMap().getRoute_IgnoreEnd(ter1, ter2, new CompositeMatchAnd<Territory>(Matches.TerritoryIsLand, Matches.TerritoryIsNotImpassable, new InverseMatch<Territory>(Matches.territoryHasUnitsThatMatch(new CompositeMatchAnd<Unit>(Matches.unitIsEnemyOf(data, player), Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1))))));
2315
public static Route GetAttackRouteFromXToY_ByLand_CountZAsPassthroughs(GameData data, PlayerID player, Territory ter1, Territory ter2, List<Territory> passthroughTers)
2319
if(ter1 == null || ter2 == null)
2321
List<Match> matches = new ArrayList<Match>();
2322
matches.add(new CompositeMatchAnd<Territory>(Matches.TerritoryIsLand, Matches.TerritoryIsNotImpassable, new InverseMatch<Territory>(Matches.territoryHasUnitsThatMatch(new CompositeMatchAnd<Unit>(Matches.unitIsEnemyOf(data, player), Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1))))));
2323
for(Territory ter : passthroughTers)
2324
matches.add(Matches.territoryIs(ter));
2325
return data.getMap().getRoute_IgnoreEnd(ter1, ter2, CompMatchOr(matches));
2327
public static Route GetAttackRouteFromXToY_BySea(GameData data, PlayerID player, Territory ter1, Territory ter2)
2331
if(ter1 == null || ter2 == null)
2333
return data.getMap().getRoute_IgnoreEnd(ter1, ter2, new CompositeMatchAnd<Territory>(Matches.TerritoryIsWater, new InverseMatch<Territory>(Matches.territoryHasUnitsThatMatch(new CompositeMatchAnd<Unit>(Matches.unitIsEnemyOf(data, player), Matches.unitHasDefenseThatIsMoreThanOrEqualTo(1))))));
2335
public static Route GetNCMRouteFromXToY_ByLand(GameData data, PlayerID player, Territory ter1, Territory ter2)
2339
if(ter1 == null || ter2 == null)
2341
return data.getMap().getRoute_IgnoreEnd(ter1, ter2, new CompositeMatchAnd<Territory>(Matches.TerritoryIsLand, Matches.TerritoryIsNotImpassable, DMatches.territoryIsOwnedByXOrAlly(data, player)));
2343
public static boolean HasNeighborsThatMatch(GameMap map, Territory ter, Match<Territory> match)
2345
return Match.someMatch(map.getNeighbors(ter), match);
2347
public static int GetTotalProductionOfTerritoriesInList(List<Territory> territories)
2350
for(Territory ter : territories)
2352
TerritoryAttachment ta = TerritoryAttachment.get(ter);
2356
result += ta.getProduction();
2366
* Returns all the units matching X that can reach target.
2368
public static List<Unit> GetUnitsMatchingXThatCanReach(final GameData data, Territory target, Match<Territory> terMatch, Match<Unit> unitMatch)
2370
return GetNUnitsMatchingXThatCanReach(data, target, terMatch, unitMatch, Integer.MAX_VALUE);
2373
* Returns all the units matching X that can reach target, or could reach target if passthroughTers were empty.
2375
public static List<Unit> GetUnitsMatchingXThatCanReach_CountYAsPassthroughs(final GameData data, Territory target, Match<Territory> terMatch, Match<Unit> unitMatch, List<Territory> passthroughTers)
2377
return GetNUnitsMatchingXThatCanReach_CountYAsPassthroughs(data, target, terMatch, unitMatch, passthroughTers, Integer.MAX_VALUE);
2380
* Returns the n first units matching X that can reach target.
2382
public static List<Unit> GetNUnitsMatchingXThatCanReach(final GameData data, Territory target, Match<Territory> terMatch, Match<Unit> unitMatch, int maxResults)
2384
return GetNUnitsMatchingXThatCanReach_CountYAsPassthroughs(data, target, terMatch, unitMatch, new ArrayList<Territory>(), maxResults);
2387
* Returns the n first units matching X that can reach target, or could reach target if passthroughTers were empty.
2389
public static List<Unit> GetNUnitsMatchingXThatCanReach_CountYAsPassthroughs(final GameData data, Territory target, Match<Territory> terMatch, Match<Unit> unitMatch, List<Territory> passthroughTers, int maxResults)
2391
List<Unit> result = new ArrayList<Unit>();
2392
for (Territory ter : data.getMap().getTerritories())
2394
if(!terMatch.match(ter))
2397
List<Unit> matchingUnits = Match.getMatches(ToList(ter.getUnits().getUnits()), unitMatch);
2398
for(Unit unit : matchingUnits)
2400
if(CanUnitReachTer(data, ter, unit, target, passthroughTers))
2403
if(result.size() >= maxResults)
2411
* Returns all the units matching X that can reach target.
2413
public static HashMap<Territory, List<Unit>> GetUnitsMatchingXThatCanReach_Mapped(final GameData data, Territory target, Match<Territory> terMatch, Match<Unit> unitMatch)
2415
return GetUnitsMatchingXThatCanReach_Mapped_CountYAsPassthroughs(data, target, terMatch, unitMatch, new ArrayList<Territory>());
2418
* Returns all the units matching X that can reach target.
2420
public static HashMap<Territory, List<Unit>> GetUnitsMatchingXThatCanReach_Mapped_CountYAsPassthroughs(final GameData data, Territory target, Match<Territory> terMatch, Match<Unit> unitMatch, List<Territory> passthroughTers)
2422
HashMap<Territory, List<Unit>> result = new HashMap<Territory, List<Unit>>();
2423
for (Territory ter : data.getMap().getTerritories())
2425
if(!terMatch.match(ter))
2428
List<Unit> matchingUnits = Match.getMatches(ToList(ter.getUnits().getUnits()), unitMatch);
2429
for(Unit unit : matchingUnits)
2431
if(CanUnitReachTer(data, ter, unit, target, passthroughTers))
2432
AddObjToListValueForKeyInMap(result, ter, unit);
2438
* Returns all the units owned by player that can reach target.
2440
public static List<Unit> GetUnitsOwnedByPlayerThatCanReach(final GameData data, Territory target, final PlayerID playerToCheckFor, Match<Territory> terMatch)
2442
return GetUnitsMatchingXThatCanReach(data, target, terMatch, Matches.unitIsOwnedBy(playerToCheckFor));
2445
* (GetStrongestPlayerNonNullEnemyUnitsThatCanReach_Mapped)
2446
* First, determines all the enemy units that can reach territory.
2447
* Then, it estimates the attack score of the units owned by each player.
2448
* Then, it returns all the units owned by that player that can reach territory, in a ter mapped hashmap.
2450
public static HashMap<Territory, List<Unit>> GetSPNNEnemyUnitsThatCanReach_Mapped(final GameData data, Territory territory, final PlayerID playerToCheckFor, Match<Territory> terSearchMatch)
2452
HashMap<Territory, List<Unit>> result = GetNNEnemyUnitsThatCanReach_Mapped(data, territory, playerToCheckFor, terSearchMatch);
2453
return GetTheUnitsOfTheStrongestPlayerContainedInMap_Mapped(result);
2456
* (GetNonNullEnemyUnitsThatCanReach)
2457
* Returns all the non-null-enemy units that can reach territory.
2459
public static List<Unit> GetNNEnemyUnitsThatCanReach(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch)
2461
return GetNNEnemyUnitsThatCanReach_CountXAsPassthroughs(data, target, player, terMatch, new ArrayList<Territory>());
2464
* (GetNNonNullEnemyUnitsThatCanReach)
2465
* Returns the n first non-null-enemy units that can reach territory.
2467
public static List<Unit> GetNNNEnemyUnitsThatCanReach(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch, int maxResults)
2469
return GetNNNEnemyUnitsThatCanReach_CountXAsPassthroughs(data, target, player, terMatch, new ArrayList<Territory>(), maxResults);
2472
* (GetNonNullEnemyUnitsThatCanReach_Mapped)
2473
* Returns a hashmap that lists the enemy units that can reach <code>territory</code>, where key is the ter with attackers, and value is the list of attackers in that ter.
2475
public static HashMap<Territory, List<Unit>> GetNNEnemyUnitsThatCanReach_Mapped(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch)
2477
return GetUnitsMatchingXThatCanReach_Mapped(data, target, terMatch, DMatches.unitIsNNEnemyOf(data, player));
2480
* (GetNonNullEnemyUnitsThatCanReach_CountXAsPassthroughs)
2481
* Returns all the enemy units that can reach territory, or could reach territory if passthrough ters were empty of enemies.
2483
public static List<Unit> GetNNEnemyUnitsThatCanReach_CountXAsPassthroughs(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch, List<Territory> passthroughTers)
2485
return GetNNNEnemyUnitsThatCanReach_CountXAsPassthroughs(data, target, player, terMatch, passthroughTers, Integer.MAX_VALUE);
2488
* (GetNNonNullEnemyUnitsThatCanReach_CountXAsPassthroughs)
2489
* Returns the n first enemy units that can reach territory, or could reach territory if passthrough ters were empty of enemies.
2491
public static List<Unit> GetNNNEnemyUnitsThatCanReach_CountXAsPassthroughs(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch, List<Territory> passthroughTers, int maxResults)
2493
return GetNUnitsMatchingXThatCanReach_CountYAsPassthroughs(data, target, terMatch, DMatches.unitIsNNEnemyOf(data, player), passthroughTers, maxResults);
2496
* (GetNonNullEnemyLandUnitsThatCanReach)
2497
* Returns all the non-null-enemy land units that can reach territory.
2499
public static List<Unit> GetNNEnemyLUnitsThatCanReach(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch)
2501
return GetNNNEnemyLUnitsThatCanReach(data, target, player, terMatch, Integer.MAX_VALUE);
2504
* (GetNNonNullEnemyLandUnitsThatCanReach)
2505
* Returns the n first non-null-enemy land units that can reach territory.
2507
public static List<Unit> GetNNNEnemyLUnitsThatCanReach(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch, int maxResults)
2509
return GetNUnitsMatchingXThatCanReach(data, target, terMatch, CompMatchAnd(Matches.UnitIsLand, DMatches.unitIsNNEnemyOf(data, player)), maxResults);
2512
* (GetStrongestPlayerUnitsMatchingXThatCanReach)
2513
* First, determines all the units matching X that can reach territory.
2514
* Then, it estimates the attack score of the units owned by each player.
2515
* Then, it returns all the units that can reach territory that are also owned by the player whose units had the highest total score.
2517
public static List<Unit> GetSPUnitsMatchingXThatCanReach(final GameData data, Territory territory, final PlayerID playerToCheckFor, Match<Territory> terSearchMatch, Match<Unit> unitMatch)
2519
List<Unit> result = GetUnitsMatchingXThatCanReach(data, territory, terSearchMatch, unitMatch);
2520
return GetSPUnitsInList(result);
2524
* (GetStrongestPlayerNonNullEnemyUnitsThatCanReach)
2525
* First, determines all the enemy units that can reach territory.
2526
* Then, it estimates the attack score of the units owned by each player.
2527
* Then, it returns all the units that can reach territory that are also owned by the player whose units had the highest total score.
2529
public static List<Unit> GetSPNNEnemyUnitsThatCanReach(final GameData data, Territory territory, final PlayerID playerToCheckFor, Match<Territory> terMatch)
2531
List<Unit> result = GetNNEnemyUnitsThatCanReach(data, territory, playerToCheckFor, terMatch);
2532
return GetSPUnitsInList(result);
2536
* (GetStrongestPlayerNonNullEnemyUnitsThatCanReach_CountXAsPassthroughs)
2537
* First, determines all the enemy units that can reach territory, or could reach territory if passthrough ters were empty of enemies.
2538
* Then, it estimates the attack score of the units owned by each player.
2539
* Then, it returns all the units that can reach territory that are also owned by the player whose units had the highest total score.
2541
public static List<Unit> GetSPNNEnemyUnitsThatCanReach_CountXAsPassthroughs(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch, List<Territory> passthroughTers)
2543
List<Unit> result = GetNNEnemyUnitsThatCanReach_CountXAsPassthroughs(data, target, player, terMatch, passthroughTers);
2544
return GetSPUnitsInList(result);
2548
* (GetStrongestPlayerNonNullEnemyWithLandUnitsThatCanReach)
2549
* First, determines all the enemy units that can reach territory.
2550
* Then, it estimates the attack score of the units owned by each player. (And owns land units in the list)
2551
* Then, it returns all the units that can reach territory that are also owned by the player whose units had the highest total score.
2553
public static List<Unit> GetSPNNEnemyWithLUnitsThatCanReach(final GameData data, Territory target, final PlayerID playerToCheckFor, Match<Territory> terMatch)
2555
List<Unit> result = GetNNEnemyUnitsThatCanReach(data, target, playerToCheckFor, terMatch);
2556
return GetTheUnitsOfTheStrongestPlayerWithLUContainedInList(result);
2560
* (GetStrongestPlayerNonNullEnemyWithLandUnitsThatCanReach_CountXAsPassthrough)
2561
* First, determines all the enemy units that can reach territory, or could reach territory if passthrough ter was empty of enemies.
2562
* Then, it estimates the attack score of the units owned by each player. (And owns land units in the list)
2563
* Then, it returns all the units that can reach territory that are also owned by the player whose units had the highest total score.
2565
public static List<Unit> GetSPNNEnemyWithLUnitsThatCanReach_CountXAsPassthrough(final GameData data, Territory target, final PlayerID player, Match<Territory> terMatch, Territory passthroughTer)
2567
return GetSPNNEnemyWithLUnitsThatCanReach_CountXAsPassthroughs(data, target, player, terMatch, Collections.singletonList(passthroughTer));
2571
* (GetStrongestPlayerNonNullEnemyWithLandUnitsThatCanReach_CountXAsPassthroughs)
2572
* First, determines all the enemy units that can reach territory, or could reach territory if passthrough ters were empty of enemies.
2573
* Then, it estimates the attack score of the units owned by each player. (And owns land units in the list)
2574
* Then, it returns all the units that can reach territory that are also owned by the player whose units had the highest total score.
2576
public static List<Unit> GetSPNNEnemyWithLUnitsThatCanReach_CountXAsPassthroughs(final GameData data, Territory territory, final PlayerID playerToCheckFor, Match<Territory> terSearchMatch, List<Territory> passthroughTers)
2578
List<Unit> result = GetNNEnemyUnitsThatCanReach_CountXAsPassthroughs(data, territory, playerToCheckFor, terSearchMatch, passthroughTers);
2579
return GetTheUnitsOfTheStrongestPlayerWithLUContainedInList(result);
2583
* (GetStrongestPlayerNonNullEnemyBasedOnLUnitsOnlyThatCanReach)
2584
* First, determines all the enemy land units that can reach territory.
2585
* Then, it estimates the attack score of the units owned by each player.
2586
* Then, it returns all the land units that can reach territory that are also owned by the player whose land units had the highest total score.
2588
public static List<Unit> GetSPNNEnemyBasedOnLUnitsOnlyThatCanReach(final GameData data, Territory territory, final PlayerID playerToCheckFor, Match<Territory> terSearchMatch)
2590
List<Unit> result = GetNNEnemyLUnitsThatCanReach(data, territory, playerToCheckFor, terSearchMatch);
2591
return GetTheUnitsOfTheStrongestPlayerWithLUContainedInList(result);
2597
/** (GetStrongestPlayerUnitsInList)
2598
* First, groups the units in the list by their owners.
2599
* Then, it determines the total estimated 'attack score' of each group.
2600
* Then, it returns the group of units that has the highest estimated attack score.
2602
public static List<Unit> GetSPUnitsInList(List<Unit> unitsToSearch)
2604
HashMap<String, List<Unit>> attackersUnits = new HashMap<String, List<Unit>>();
2605
List<Unit> highestAttackerUnits = new ArrayList<Unit>();
2606
for (Unit u : unitsToSearch)
2608
if (!attackersUnits.containsKey(u.getOwner().getName()))
2610
List<Unit> newList = new ArrayList<Unit>();
2612
attackersUnits.put(u.getOwner().getName(), newList);
2616
List<Unit> newList = attackersUnits.get(u.getOwner().getName());
2618
attackersUnits.put(u.getOwner().getName(), newList);
2621
float highestAttackerUStrength = Integer.MIN_VALUE;
2622
for (String key : attackersUnits.keySet())
2624
List<Unit> units = attackersUnits.get(key);
2625
float strength = DUtils.GetAttackScoreOfUnits(units);
2626
if (strength > highestAttackerUStrength)
2628
highestAttackerUStrength = strength;
2629
highestAttackerUnits = units;
2632
return highestAttackerUnits;
2635
* First, determines which player owns most of the units. (And owns land units that are in the list)
2636
* Then, it returns all the units owned by that player.
2638
public static List<Unit> GetTheUnitsOfTheStrongestPlayerWithLUContainedInList(List<Unit> unitsToSearch)
2640
HashMap<String, List<Unit>> attackersUnits = new HashMap<String, List<Unit>>();
2641
List<Unit> highestAttackerUnits = new ArrayList<Unit>();
2642
for (Unit u : unitsToSearch)
2644
if (!attackersUnits.containsKey(u.getOwner().getName()))
2646
List<Unit> newList = new ArrayList<Unit>();
2648
attackersUnits.put(u.getOwner().getName(), newList);
2652
List<Unit> newList = attackersUnits.get(u.getOwner().getName());
2654
attackersUnits.put(u.getOwner().getName(), newList);
2657
float highestAttackerUStrength = Integer.MIN_VALUE;
2658
for (String key : attackersUnits.keySet())
2660
List<Unit> units = attackersUnits.get(key);
2661
boolean foundLand = Match.someMatch(units, Matches.UnitIsLand);
2664
float strength = DUtils.GetAttackScoreOfUnits(units);
2665
if (strength > highestAttackerUStrength)
2667
highestAttackerUStrength = strength;
2668
highestAttackerUnits = units;
2671
return highestAttackerUnits;
2674
* First, determines which player owns most of the units.
2675
* Then, it returns all the units owned by that player.
2677
public static HashMap<Territory, List<Unit>> GetTheUnitsOfTheStrongestPlayerContainedInMap_Mapped(HashMap<Territory, List<Unit>> unitsToSearch)
2679
HashMap<String, List<Unit>> attackersUnits = new HashMap<String, List<Unit>>();
2680
for (Territory ter : unitsToSearch.keySet())
2682
for (Unit unit : unitsToSearch.get(ter))
2684
AddObjToListValueForKeyInMap(attackersUnits, unit.getOwner().getName(), unit);
2688
HashSet<Unit> highestAttackerUnits = new HashSet<Unit>();
2689
float highestAttackerUStrength = Integer.MIN_VALUE;
2690
for (String key : attackersUnits.keySet())
2692
List<Unit> units = attackersUnits.get(key);
2693
float strength = DUtils.GetAttackScoreOfUnits(units);
2694
if (strength > highestAttackerUStrength)
2696
highestAttackerUStrength = strength;
2697
highestAttackerUnits = ToHashSet(units);
2701
HashMap<Territory, List<Unit>> highestAttackerUnits_Mapped = new HashMap<Territory, List<Unit>>();
2702
for(Territory ter : unitsToSearch.keySet())
2704
for(Unit terUnit : unitsToSearch.get(ter))
2706
if(highestAttackerUnits.contains(terUnit))
2707
AddObjToListValueForKeyInMap(highestAttackerUnits_Mapped, ter, terUnit);
2710
return highestAttackerUnits_Mapped;
2712
public static boolean CanAirUnitLandWithXSurvivalChanceIfAttackingFromXToY(GameData data, final Territory from, Territory to, Unit airUnit, float survivalChance)
2714
TripleAUnit ta = TripleAUnit.get(airUnit);
2715
int jumpDist = DUtils.GetJumpsFromXToY_AirPassable(data, from, to);
2716
int movementAfterAttack = ta.getMovementLeft() - jumpDist;
2717
for (Territory ter : data.getMap().getTerritories())
2719
if (!data.getAllianceTracker().isAllied(ter.getOwner(), airUnit.getOwner()))
2721
int dist = DUtils.GetJumpsFromXToY_AirPassable(data, ter, to);
2722
if(dist > movementAfterAttack)
2725
if (survivalChance != 0.0F)
2727
//TODO: If we find all attackers, we cause airplane determining endless loop. Current hack: Only figure in land units that can attack
2728
List<Unit> attackers = GetSPNNEnemyBasedOnLUnitsOnlyThatCanReach(data, ter, airUnit.getOwner(), Matches.TerritoryIsLand);
2729
List<Unit> defenders = ToList(ter.getUnits().getUnits());
2730
if(data.getAllianceTracker().isAtWar(airUnit.getOwner(), GlobalCenter.CurrentPlayer)) //If we're checking if an enemy plane can land
2732
List<Territory> neighbors = DUtils.GetTerritoriesWithinXDistanceOfY(data, ter, 1);
2733
defenders = DUtils.GetUnitsMatchingXInTerritories(neighbors, Matches.unitIsLandAndOwnedBy(airUnit.getOwner()));
2735
defenders.remove(airUnit);
2736
defenders.add(airUnit);
2737
AggregateResults results = DUtils.GetBattleResults(attackers, defenders, ter, data, 1, false); //False, so we don't leave air in our land but going to get killed by enemy air
2738
if(results.getDefenderWinPercent() >= survivalChance)
2739
return true; //We found a place to land
2742
return true; //We found a place to land
2746
public static int CountLandUnits(List<Unit> units)
2749
for (Unit u : units)
2751
UnitAttachment ua = UnitAttachment.get(u.getUnitType());
2752
if (!ua.isSea() && !ua.isAir())
2759
public static HashSet ToHashSet(Collection collection)
2761
HashSet result = new HashSet();
2762
for(Object obj : collection)
2766
public static List InvertList(Collection list)
2768
ArrayList result = new ArrayList(list);
2769
Collections.reverse(result);
2772
public static List ShuffleList(Collection list)
2774
ArrayList result = new ArrayList(list);
2775
Collections.shuffle(result);
2778
public static List GetXPercentOfTheItemsInList(Collection list, float percentageToKeep)
2780
if(percentageToKeep == 1.0F)
2781
return new ArrayList(list);
2782
if(percentageToKeep == 0.0F)
2783
return new ArrayList();
2784
ArrayList result = new ArrayList();
2785
for (Object obj : list)
2787
if(Math.random() < percentageToKeep)
2792
public static List<Unit> GetXPercentOfTheUnitsInList_CreateMoreIfNeeded(Collection<Unit> units, float percentageToResultIn)
2794
if(percentageToResultIn == 1.0F)
2795
return new ArrayList<Unit>(units);
2796
if(percentageToResultIn == 0.0F)
2797
return new ArrayList<Unit>();
2798
ArrayList<Unit> result = new ArrayList<Unit>();
2799
while (percentageToResultIn > 1.0F)
2801
for (Unit unit : units)
2802
result.add(unit.getUnitType().create(unit.getOwner())); //We have to create a new instance of that unit type
2803
percentageToResultIn -= 1.0F;
2805
for (Unit unit : units)
2807
if(Math.random() < percentageToResultIn)
2808
result.add(unit.getUnitType().create(unit.getOwner())); //We have to create a new instance of that unit type
2812
public static List<Unit> RecreateXPercentOfTheUnitsInList_CreateMoreIfNeeded(Collection<Unit> units, float percentageToResultIn)
2814
if(percentageToResultIn == 1.0F)
2815
return new ArrayList<Unit>(units);
2816
if(percentageToResultIn == 0.0F)
2817
return new ArrayList<Unit>();
2818
ArrayList<Unit> result = new ArrayList<Unit>();
2819
while (percentageToResultIn > 1.0F)
2821
for (Unit unit : units)
2822
result.add(unit.getUnitType().create(unit.getOwner())); //We have to create a new instance of that unit type
2823
percentageToResultIn -= 1.0F;
2825
for (Unit unit : units)
2827
if(Math.random() < percentageToResultIn)
2828
result.add(unit.getUnitType().create(unit.getOwner())); //We have to create a new instance of that unit type
2832
public static List<Unit> ToUnitList(Collection<UnitGroup> ugs)
2834
List<Unit> result = new ArrayList<Unit>();
2835
for(UnitGroup ug : ugs)
2836
result.addAll(ug.GetUnits());
2840
* Formats the units in a list of unit groups.
2841
* Before: "infantry owned by Americans, infantry owned by Americans, infantry owned by Americans, armour owned by Americans, fighter owned by Americans"
2842
* After: "3 infantry, armour, and fighter owned by Americans"
2844
public static String UnitGroupList_ToString(Collection<UnitGroup> ugs)
2846
List<Unit> units = ToUnitList(ugs);
2848
return UnitList_ToString(units);
2851
* Formats the list of units provided.
2852
* Before: "infantry owned by Americans, infantry owned by Americans, infantry owned by Americans, armour owned by Americans, fighter owned by Americans"
2853
* After: "3 infantry, armour, and fighter owned by Americans"
2855
public static String UnitList_ToString(Collection<Unit> units)
2857
if (units.isEmpty())
2859
if(units.size() == 1)
2860
return units.iterator().next().toString();
2862
StringBuilder builder = new StringBuilder();
2863
builder.append("[");
2864
HashMap<String, List<Unit>> unitsByOwner = new HashMap<String, List<Unit>>();
2865
for(Unit unit : units)
2866
AddObjToListValueForKeyInMap(unitsByOwner, unit.getOwner().getName(), unit);
2868
for(String owner : unitsByOwner.keySet())
2871
String lastUnitType = null;
2872
int lastUnitTypeCount = 0;
2873
for(Unit unit : unitsByOwner.get(owner))
2875
if(lastUnitType == null) //First unit
2878
lastUnitType = unit.getUnitType().getName();
2879
lastUnitTypeCount = 1;
2881
else if(unit.getUnitType().getName().equals(lastUnitType)) //Part of a group
2882
lastUnitTypeCount++;
2883
else //End of last group, start of next
2885
if(unitGroups != 1) //If this is not the end of the first group
2886
builder.append(", ");
2887
if(lastUnitTypeCount == 1) //If the last group was only one unit
2888
builder.append(lastUnitType);
2890
builder.append(lastUnitTypeCount).append(" ").append(MyFormatter.pluralize(lastUnitType));
2892
lastUnitType = unit.getUnitType().getName();
2893
lastUnitTypeCount = 1;
2898
builder.append(", and ");
2899
if (lastUnitTypeCount == 1)
2900
builder.append(lastUnitType).append(" owned by ").append(owner);
2902
builder.append(lastUnitTypeCount).append(" ").append(MyFormatter.pluralize(lastUnitType)).append(" owned by ").append(owner);
2904
builder.append("]");
2905
return builder.toString();
2907
public static List<Unit> DetermineResponseAttackers(GameData data, PlayerID player, Territory battleTer, AggregateResults results)
2909
List<Unit> responseAttackers = DUtils.GetSPNNEnemyUnitsThatCanReach(data, battleTer, player, Matches.TerritoryIsLand);
2910
responseAttackers.removeAll(battleTer.getUnits().getUnits());
2911
return responseAttackers;
2914
* Returns the units that will be on ter after factory units are placed at end of turn.
2916
public static List<Unit> GetUnitsGoingToBePlacedAtX(GameData data, PlayerID player, Territory ter)
2918
PurchaseGroup terPG = FactoryCenter.get(data, player).TurnTerritoryPurchaseGroups.get(ter);
2919
List<Unit> goingToBePlaced = new ArrayList<Unit>();
2921
goingToBePlaced = terPG.GetSampleUnits();
2923
return goingToBePlaced;
2926
* Returns the chances ter would get taken over if (SPNNEnemyWithLUnits)'s units that can reach ter attack.
2928
public static float GetTerTakeoverChance(GameData data, PlayerID player, Territory ter)
2930
List<Unit> oldCapDefenders = new ArrayList<Unit>(ter.getUnits().getUnits()); //Cap defenders before move
2931
List<Unit> oldCapAttackers = DUtils.GetSPNNEnemyWithLUnitsThatCanReach(data, ter, player, Matches.TerritoryIsLand); //Cap attackers before move
2933
AggregateResults oldResults = DUtils.GetBattleResults(oldCapAttackers, oldCapDefenders, ter, data, 1000, true); //Takeover results before move
2935
return (float)oldResults.getAttackerWinPercent();
2938
* Returns the chances ter would get taken over after factory units were placed at end of turn if (SPNNEnemyWithLUnits)'s units that can reach ter attack.
2940
public static float GetTerTakeoverChanceAtEndOfTurn(GameData data, PlayerID player, Territory ter)
2942
List<Unit> oldTerDefenders = GetTerUnitsAtEndOfTurn(data, player, ter);
2943
List<Unit> oldTerAttackers = DUtils.GetSPNNEnemyWithLUnitsThatCanReach(data, ter, player, Matches.TerritoryIsLand); //Cap attackers before move
2945
AggregateResults oldResults = DUtils.GetBattleResults(oldTerAttackers, oldTerDefenders, ter, data, 1000, true); //Takeover results before move
2947
return (float)oldResults.getAttackerWinPercent();
2950
* Returns the units that will be placed down on ter at the end of the turn.
2952
public static List<Unit> GetTerUnitsGoingToBePlacedAt(GameData data, PlayerID player, Territory ter)
2954
PurchaseGroup terPG = FactoryCenter.get(data, player).TurnTerritoryPurchaseGroups.get(ter);
2955
List<Unit> goingToBePlaced = new ArrayList<Unit>();
2957
goingToBePlaced = terPG.GetSampleUnits();
2959
return goingToBePlaced;
2962
* Returns the units that will be on ter after factory units are placed at end of turn.
2964
public static List<Unit> GetTerUnitsAtEndOfTurn(GameData data, PlayerID player, Territory ter)
2966
List<Unit> goingToBePlaced = GetTerUnitsGoingToBePlacedAt(data, player, ter);
2968
List<Unit> result = new ArrayList<Unit>(ter.getUnits().getUnits()); //Current ter units
2969
result.addAll(goingToBePlaced);
2973
* Returns the chances ter would get taken over after move if (SPNNEnemyWithLUnits)'s units that can reach ter attack.
2974
* List item 1: Takeover chance before move
2975
* List item 2: Takeover chance after move
2976
* List item 3: Average number of attack units left before move
2977
* List item 4: Average number of attack units left after move
2979
public static List<Float> GetTerTakeoverChanceBeforeAndAfterMove(GameData data, PlayerID player, Territory terToCheck, Territory movedTo, List<Unit> unitsToMove, int calcAmount)
2981
return GetTerTakeoverChanceBeforeAndAfterMoves(data, player, terToCheck, Collections.singletonList(movedTo), unitsToMove, calcAmount);
2984
* Returns the chances ter would get taken over after moves if (SPNNEnemyWithLUnits)'s units that can reach ter attack.
2985
* List item 1: Takeover chance before moves
2986
* List item 2: Takeover chance after moves
2987
* List item 3: Average number of attack units left before moves
2988
* List item 4: Average number of attack units left after moves
2990
public static List<Float> GetTerTakeoverChanceBeforeAndAfterMoves(GameData data, PlayerID player, Territory terToCheck, List<Territory> movedToTers, List<Unit> unitsToMove, int calcAmount)
2992
List<Float> result = new ArrayList<Float>();
2994
List<Territory> movedFromTersThatBecomeEmpty = new ArrayList<Territory>();
2995
for(Territory ter : data.getMap().getTerritories())
2999
if(data.getAllianceTracker().isAtWar(ter.getOwner(), player))
3001
if(ter.getUnits().isEmpty())
3003
List<Unit> unitsOnTerBeingMoved = Match.getMatches(ter.getUnits().getUnits(), DMatches.unitIsInList(unitsToMove));
3004
if(unitsOnTerBeingMoved.size() == ter.getUnits().size() && GetUnitsGoingToBePlacedAtX(data, player, ter).isEmpty()) //If all the units on this ter will be gone after this move
3005
movedFromTersThatBecomeEmpty.add(ter);
3008
List<Unit> unitsToMoveThatAreOnTerToCheck = new ArrayList<Unit>(unitsToMove);
3009
unitsToMoveThatAreOnTerToCheck.retainAll(terToCheck.getUnits().getUnits());
3011
PurchaseGroup terPG = FactoryCenter.get(data, player).TurnTerritoryPurchaseGroups.get(terToCheck);
3012
List<Unit> goingToBePlaced = new ArrayList<Unit>();
3014
goingToBePlaced = terPG.GetSampleUnits();
3016
List<Unit> oldTerDefenders = new ArrayList<Unit>(terToCheck.getUnits().getUnits()); //Ter defenders before move
3017
oldTerDefenders.addAll(goingToBePlaced);
3018
List<Unit> oldTerAttackers = DUtils.GetSPNNEnemyWithLUnitsThatCanReach(data, terToCheck, player, Matches.TerritoryIsLand); //Ter attackers before move
3020
AggregateResults oldResults = DUtils.GetBattleResults(oldTerAttackers, oldTerDefenders, terToCheck, data, calcAmount, true); //Takeover results before move
3022
List<Unit> newTerDefenders = new ArrayList<Unit>(oldTerDefenders); //Ter defenders after move
3023
newTerDefenders.removeAll(unitsToMoveThatAreOnTerToCheck);
3024
if(movedToTers.contains(terToCheck))
3026
newTerDefenders.removeAll(unitsToMove); //Don't double add
3027
newTerDefenders.addAll(unitsToMove);
3030
List<Unit> newTerAttackers = DUtils.GetSPNNEnemyWithLUnitsThatCanReach_CountXAsPassthroughs(data, terToCheck, player, CompMatchAnd(Matches.TerritoryIsLand, Matches.territoryIsNotInList(movedToTers)), movedFromTersThatBecomeEmpty); //Ter attackers after move
3032
//Now look through the old attack-from enemy territories, and remove the units from the list of new attackers if the attack route will be blocked after the move
3033
List<Territory> attackFromLocs = DUtils.GetEnemyTerritoriesWithinXLandDistanceThatHaveEnemyUnitsThatCanAttack(terToCheck, data, player, GlobalCenter.FastestUnitMovement);
3034
for (Territory from : attackFromLocs)
3036
Route route = DUtils.GetAttackRouteFromXToY_ByLand(data, from.getOwner(), from, terToCheck);
3039
boolean doTheMovesBlockThisAttack = false;
3040
for(Territory to : movedToTers) //Look through each move
3042
if (route.getTerritories().contains(to) && !route.getEnd().equals(to)) //And check if this attack route is blocked by it
3044
doTheMovesBlockThisAttack = true;
3048
if(doTheMovesBlockThisAttack)
3049
newTerAttackers.removeAll(from.getUnits().getUnits());
3053
AggregateResults newResults = DUtils.GetBattleResults(newTerAttackers, newTerDefenders, terToCheck, data, calcAmount, true); //Takeover results after move
3055
result.add((float)oldResults.getAttackerWinPercent());
3056
result.add((float)newResults.getAttackerWinPercent());
3057
result.add((float)oldResults.getAverageAttackingUnitsLeft());
3058
result.add((float)newResults.getAverageAttackingUnitsLeft());
3063
* Returns the number that is the farthest from 0.
3065
public static float GetMostExtremeNum(List<Float> numbers)
3068
float farthestNumDist = 0F;
3069
for(Float num : numbers)
3071
if (MNN(num) > farthestNumDist)
3073
farthestNumDist = MNN(num);
3080
* (ScaleNumbersTillWithinRange_Positive)
3081
* Scales the numbers provided so the numbers range from 0 to ceiling, whether by scaling up or scaling down.
3082
* (If highest number is below ceiling, numbers are 'stretched' till max number reaches ceiling, if highest number is above, numbers are 'compacted' till max number reaches ceiling)
3084
public static List<Float> ScaleNumbersTillWithinRange_P(float ceiling, float ... numbers)
3086
float mostExtremeNum = GetMostExtremeNum(ToList(ToArray(numbers)));
3088
float numberScaleToRange = mostExtremeNum / ceiling;
3090
List<Float> result = new ArrayList<Float>();
3091
for(Float number : numbers)
3093
result.add(number / numberScaleToRange);
3098
* (Divide_Safe_Limit)
3099
* Performs a divide using 'safe' versions of the quotient and divisor, and returns the value as a 'limited' number. (0.0F-1.0F)
3101
public static float Divide_SL(float quotient, float divisor)
3103
return Limit(Divide_S(quotient, divisor));
3107
* Performs a divide using 'safe' versions of the quotient and divisor and returns the value.
3109
public static float Divide_S(float quotient, float divisor)
3111
quotient = MNZ(quotient);
3112
divisor = MNZ(divisor);
3114
return quotient / divisor;
3117
* @return Returns a limited version of the number. (On or between min and max)
3119
public static float Limit(float value, float min, float max)
3121
return Math.min(Math.max(value, min), max);
3124
* @return Returns a limited version of the number. (On or between 0.0F and 1.0F)
3126
public static float Limit(float value)
3128
return Limit(value, 0.0F, 1.0F);
3132
* @param value - The number to make non-zero
3133
* @return - Returns 0.001F if the number is 0.0F, otherwise returns the number itself
3135
public static float MNZ(float value)
3143
* @param value - The number to make non-negative
3144
* @return - Returns an unsigned version of the number (removes the - sign, if it exists)
3146
public static float MNN(float value)
3153
* Returns the territories that units in list can attack.
3155
public static List<Territory> GetTersThatUnitsCanReach(final GameData data, List<Unit> units, Territory territory, final PlayerID playerToCheckFor, Match<Territory> terSearchMatch)
3157
List<Territory> result = new ArrayList<Territory>();
3158
for (Territory ter : data.getMap().getTerritories())
3160
if(!terSearchMatch.match(ter))
3162
for (Unit u : units)
3164
if(CanUnitReachTer(data, ter, u, territory))
3172
* Returns the territories matching X that the units on territory can attack.
3174
public static List<Territory> GetTersThatMatchXThatUnitsOnTerCanAttack(final GameData data, Territory territory, Match<Territory> terMatch, final PlayerID player)
3176
List<Territory> reachableMatches = new ArrayList<Territory>();
3177
for (Territory ter : data.getMap().getTerritories())
3179
if(!terMatch.match(ter))
3181
for (Unit u : ter.getUnits().getMatches(Matches.unitIsOwnedBy(player)))
3183
if(CanUnitReachTer(data, ter, u, territory))
3185
reachableMatches.add(ter);
3191
return reachableMatches;
3194
* Determines which unit in the list will increase the chance of battle winning the most, if chances before were already 1.0F, bases it off of how many attacking units are saved by adding this unit.
3195
* (More powerful units should destroy enemy units faster, thereby reducing attacker's casualties more)
3196
* (Atm, this method does not work well...)
3198
public static Unit CalculateUnitThatWillHelpWinAttackOnArmyTheMostPerPU(Territory testTer, GameData data, PlayerID player, Collection<Unit> unitsAlreadyAttacking, Collection<Unit> unitsToChooseFrom, Collection<Unit> unitsDefending, Match<Unit> match, int calcRunsPerUnit)
3200
float bestTakeoverScore = Integer.MIN_VALUE;
3201
Unit bestUnit = null;
3202
List<Unit> fakeDefenseUnits = DUtils.CreateDefendUnitsTillTakeoverChanceIsLessThanX(unitsAlreadyAttacking, unitsDefending, data, testTer, .85F); //Increase the number of defenders to give a better unit help calculation
3204
List<Unit> units = new ArrayList<Unit>(unitsAlreadyAttacking);
3205
AggregateResults oldResults = DUtils.GetBattleResults(units, fakeDefenseUnits, testTer, data, calcRunsPerUnit * 2, true);
3206
float oldAttackerWinPercent = (float) oldResults.getAttackerWinPercent();
3207
float oldAttackersLeft = (float) oldResults.getAverageAttackingUnitsLeft();
3208
float oldDefendersLeft = (float) oldResults.getAverageDefendingUnitsLeft();
3209
for (Unit testUnit : unitsToChooseFrom)
3211
UnitType ut = testUnit.getUnitType();
3212
UnitAttachment ua = UnitAttachment.get(ut);
3213
if (ua.isSea() || ua.isAA() || ua.isFactory())
3215
if(!match.match(testUnit))
3217
//if(ua.isAir() && Math.random() <= .50F)
3218
// continue; //50% of the time, ignore air units (so we don't want to buy them)
3220
units.add(testUnit);
3221
AggregateResults results = DUtils.GetBattleResults(units, fakeDefenseUnits, testTer, data, calcRunsPerUnit, true);
3222
float attackerWinPercent = (float) results.getAttackerWinPercent();
3223
float attackersLeft = (float) results.getAverageAttackingUnitsLeft();
3224
float defendersLeft = (float) results.getAverageDefendingUnitsLeft();
3225
float cost = GetTUVOfUnit(testUnit, GlobalCenter.GetPUResource());
3226
float dif = attackerWinPercent - oldAttackerWinPercent;
3227
float dif2 = (attackersLeft - oldAttackersLeft) + (oldDefendersLeft - defendersLeft);
3228
if (dif != 0 && dif > 0)
3230
if (dif / cost > bestTakeoverScore)
3232
bestUnit = testUnit;
3233
bestTakeoverScore = dif / cost;
3238
if (dif2 / cost > bestTakeoverScore)
3240
bestUnit = testUnit;
3241
bestTakeoverScore = dif2 / cost;
3244
units.remove(testUnit);
3248
public static List<UnitGroup> CreateUnitGroupsForUnits(Collection<Unit> units, Territory ter, GameData data)
3250
List<UnitGroup> result = new ArrayList<UnitGroup>();
3251
for (Unit unit : units)
3253
result.add(new UnitGroup(unit, ter, data));
3258
* Meant to duplicate the String.format method I used frequently in Microsoft Visual C#.
3259
* (The String.format method in java doesn't seem to replace {0} with the first argument, {1} with the second, etc.)
3261
public static String Format(String message, Object ... args)
3264
for(Object obj : args)
3266
message = message.replace("{".concat(Integer.toString(count)).concat("}"), "" + obj);
3272
* Adds extra spaces to get logs to lineup correctly. (Adds two spaces to fine, one to finer, none to finest, etc.)
3274
private static String addIndentationCompensation(String message, Level level)
3276
StringBuilder builder = new StringBuilder();
3277
int compensateLength = 6 - level.toString().length();
3278
if(compensateLength == 0)
3280
for(int i = 0; i < compensateLength;i++)
3282
builder.append(" ");
3284
builder.append(message);
3285
return builder.toString();
3288
* Some notes on using the Dynamix logger:
3290
* First, to make the logs easily readable even when there are hundreds of lines, I want every considerable step down in the call stack to mean more log message indentation.
3291
* For example, the base logs in the Dynamix_AI class have no indentation before them, but the base logs in the DoCombatMove class will have two spaces inserted at the start, and the level below that, four spaces.
3292
* In this way, when you're reading the log, you can skip over unimportant areas with speed because of the indentation.
3294
* Second, I generally want the Fine logs to be messages that run less than 10 times each round, including almost all messages in the Dynamix_AI class,
3295
* Finest for messages showing details within a method that, for example, returns a value.
3296
* (So, for example, the NCM_Task method IsTaskWorthwhile() would primarily use finest, as it just returns a boolean, and the logs within it are just for details)
3297
* Finer for just about everything else. (There's also the SERVER, INFO, etc. levels)
3299
* Just keep these things in mind while adding new logging code.
3301
public static void Log(Level level, String message, Object ... args)
3303
//Used to pause AI's temporarily while the user is examining the AI logs
3304
if(GlobalCenter.IsPaused && !SwingUtilities.isEventDispatchThread()) //Never 'sleep' on the UI thread
3305
synchronized(GlobalCenter.IsPaused_Object){while(GlobalCenter.IsPaused)try{GlobalCenter.IsPaused_Object.wait();}catch(InterruptedException ex){}}
3308
message = Format(message, args); //Convert {0}, {1}, etc to the objects supplied for them
3310
//We always log to the AI logger, though it only shows up if the developer has the logger enabled in logging.properties
3311
Dynamix_AI.GetStaticLogger().log(level, addIndentationCompensation(message, level));
3313
if (!DSettings.LoadSettings().EnableAILogging)
3314
return; //Skip displaying to settings window if settings window option is turned off
3315
Level logDepth = DSettings.LoadSettings().AILoggingDepth;
3316
if (logDepth.equals(Level.FINE) && (level.equals(Level.FINER) || level.equals(Level.FINEST)))
3317
return; //If the settings window log depth is a higher level than this messages, skip
3318
if (logDepth.equals(Level.FINER) && level.equals(Level.FINEST))
3321
UI.NotifyAILogMessage(level, message);
3323
public static UnitGroup CreateUnitGroupForUnit(Unit unit, Territory ter, GameData data)
3325
return CreateUnitGroupForUnits(Collections.singleton(unit), ter, data);
3328
* Only use this if you know that all the units have the same movement amount left, otherwise the units with more movement left will not go as far as they could
3330
public static UnitGroup CreateUnitGroupForUnits(Collection<Unit> units, Territory ter, GameData data)
3332
return new UnitGroup(units, ter, data);
3335
* This method is very handy when you want to move a territory's units, you want the units to move to a target as far as possible, and in the largest groups possible.
3336
* (If this method were not used, any units with more movement left in the list would not go as far as they could)
3338
public static List<UnitGroup> CreateSpeedSplitUnitGroupsForUnits(Collection<Unit> units, Territory ter, GameData data)
3340
List<UnitGroup> result = new ArrayList<UnitGroup>();
3341
HashMap<Integer, List<Unit>> splitUnits = DUtils.SeperateUnitsInListIntoSeperateMovementLists(new ArrayList<Unit>(units));
3342
for (Integer speed : splitUnits.keySet())
3344
List<Unit> unitsForSpeed = splitUnits.get(speed);
3345
result.add(new UnitGroup(unitsForSpeed, ter, data));
3349
public static List<Unit> GetEndingCapitalUnits(GameData data, PlayerID player)
3351
Territory ourCapital = TerritoryAttachment.getCapital(player, data);
3353
return GetTerUnitsAtEndOfTurn(data, player, ourCapital);