package games.strategy.triplea.delegate;
import static games.strategy.triplea.delegate.GameDataTestUtil.bomber;
import static games.strategy.triplea.delegate.GameDataTestUtil.british;
import static games.strategy.triplea.delegate.GameDataTestUtil.fighter;
import static games.strategy.triplea.delegate.GameDataTestUtil.germans;
import static games.strategy.triplea.delegate.GameDataTestUtil.getDelegateBridge;
import static games.strategy.triplea.delegate.GameDataTestUtil.makeGameLowLuck;
import static games.strategy.triplea.delegate.GameDataTestUtil.setSelectAACasualties;
import static games.strategy.triplea.delegate.GameDataTestUtil.territory;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.ITestDelegateBridge;
import games.strategy.engine.data.Unit;
import games.strategy.engine.random.ScriptedRandomSource;
import games.strategy.triplea.TripleAUnit;
import games.strategy.triplea.attachments.UnitAttachment;
import games.strategy.triplea.delegate.dataObjects.CasualtyDetails;
import games.strategy.triplea.player.ITripleAPlayer;
import games.strategy.triplea.xml.TestMapGameData;
import games.strategy.util.Match;
public class BattleCalculatorTest {
private ITestDelegateBridge bridge;
private final ITripleAPlayer dummyPlayer = mock(ITripleAPlayer.class);
@Before
public void setUp() throws Exception {
final GameData data = TestMapGameData.REVISED.getGameData();
bridge = getDelegateBridge(british(data), data);
}
@Test
public void testAACasualtiesLowLuck() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
final DiceRoll roll = new DiceRoll(new int[] {0}, 1, 1, false);
final Collection<Unit> planes = bomber(data).create(5, british(data));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
final ScriptedRandomSource randomSource = new ScriptedRandomSource(new int[] {0, ScriptedRandomSource.ERROR});
bridge.setRandomSource(randomSource);
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 1);
assertEquals(1, randomSource.getTotalRolled());
}
@Test
public void testAACasualtiesLowLuckDifferentMovementLetf() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
final DiceRoll roll = new DiceRoll(new int[] {0}, 1, 1, false);
final List<Unit> planes = bomber(data).create(5, british(data));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
final ScriptedRandomSource randomSource = new ScriptedRandomSource(new int[] {0, ScriptedRandomSource.ERROR});
bridge.setRandomSource(randomSource);
TripleAUnit.get(planes.get(0)).setAlreadyMoved(1);
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 1);
}
@Test
public void testAACasualtiesLowLuckMixed() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
// 6 bombers and 6 fighters
final Collection<Unit> planes = bomber(data).create(6, british(data));
planes.addAll(fighter(data).create(6, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
// don't allow rolling, 6 of each is deterministic
bridge.setRandomSource(new ScriptedRandomSource(new int[] {ScriptedRandomSource.ERROR}));
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 2);
// should be 1 fighter and 1 bomber
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 1);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 1);
}
@Test
public void testAACasualtiesLowLuckMixedMultipleDiceRolled() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
// 5 bombers and 5 fighters
final Collection<Unit> planes = bomber(data).create(5, british(data));
planes.addAll(fighter(data).create(5, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
// should roll once, a hit
final ScriptedRandomSource randomSource = new ScriptedRandomSource(new int[] {0, 1, 1, ScriptedRandomSource.ERROR});
bridge.setRandomSource(randomSource);
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
assertEquals(1, randomSource.getTotalRolled());
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 2);
// two extra rolls to pick which units are hit
assertEquals(3, randomSource.getTotalRolled());
// should be 1 fighter and 1 bomber
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 0);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 2);
}
@Test
public void testAACasualtiesLowLuckMixedWithChooseAACasualties() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, true);
// 6 bombers and 6 fighters
final Collection<Unit> planes = bomber(data).create(6, british(data));
planes.addAll(fighter(data).create(6, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
when(dummyPlayer.selectCasualties(any(), any(), anyInt(), any(), any(), any(), any(), any(), any(), anyBoolean(),
any(),
any(), any(), any(), anyBoolean())).thenAnswer(new Answer<CasualtyDetails>() {
@Override
public CasualtyDetails answer(final InvocationOnMock invocation) throws Throwable {
final Collection<Unit> selectFrom = invocation.getArgument(0);
final int count = invocation.getArgument(2);
final List<Unit> selected = Match.getNMatches(selectFrom, count, Matches.UnitIsStrategicBomber);
return new CasualtyDetails(selected, new ArrayList<>(), false);
}
});
bridge.setRemote(dummyPlayer);
// don't allow rolling, 6 of each is deterministic
bridge.setRandomSource(new ScriptedRandomSource(new int[] {ScriptedRandomSource.ERROR}));
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
final Collection<Unit> casualties =
BattleCalculator.getAACasualties(false, planes, planes, defendingAA, defendingAA, roll, bridge, germans(data),
british(data), null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 2);
// we selected all bombers
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 2);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 0);
}
@Test
public void testAACasualtiesLowLuckMixedWithChooseAACasualtiesRoll() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, true);
// 7 bombers and 7 fighters
final Collection<Unit> planes = bomber(data).create(7, british(data));
planes.addAll(fighter(data).create(7, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
when(dummyPlayer.selectCasualties(any(), any(), anyInt(), any(), any(), any(), any(), any(), any(), anyBoolean(),
any(), any(), any(), any(), anyBoolean())).thenAnswer(new Answer<CasualtyDetails>() {
@Override
public CasualtyDetails answer(final InvocationOnMock invocation) throws Throwable {
final Collection<Unit> selectFrom = invocation.getArgument(0);
final int count = invocation.getArgument(2);
final List<Unit> selected = Match.getNMatches(selectFrom, count, Matches.UnitIsStrategicBomber);
return new CasualtyDetails(selected, new ArrayList<>(), false);
}
});
bridge.setRemote(dummyPlayer);
// only 1 roll, a hit
bridge.setRandomSource(new ScriptedRandomSource(new int[] {0, ScriptedRandomSource.ERROR}));
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
final Collection<Unit> casualties =
BattleCalculator.getAACasualties(false, planes, planes, defendingAA, defendingAA, roll, bridge, germans(data),
british(data), null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 3);
// we selected all bombers
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 3);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 0);
}
@Test
public void testAACasualtiesLowLuckMixedWithRolling() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
// 7 bombers and 7 fighters
// 2 extra units, roll once
final Collection<Unit> planes = bomber(data).create(7, british(data));
planes.addAll(fighter(data).create(7, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
// one roll, a hit
final ScriptedRandomSource randomSource = new ScriptedRandomSource(new int[] {0});
bridge.setRandomSource(randomSource);
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
// make sure we rolled once
assertEquals(1, randomSource.getTotalRolled());
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 3);
// a second roll for choosing which unit
assertEquals(2, randomSource.getTotalRolled());
// should be 2 fighters and 1 bombers
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 1);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 2);
}
@Test
public void testAACasualtiesLowLuckMixedWithRollingMiss() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
// 7 bombers and 7 fighters
// 2 extra units, roll once
final Collection<Unit> planes = bomber(data).create(7, british(data));
planes.addAll(fighter(data).create(7, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
// one roll, a miss
final ScriptedRandomSource randomSource =
new ScriptedRandomSource(new int[] {2, 0, 0, 0, ScriptedRandomSource.ERROR});
bridge.setRandomSource(randomSource);
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
// make sure we rolled once
assertEquals(1, randomSource.getTotalRolled());
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 2);
assertEquals(4, randomSource.getTotalRolled());
// should be 1 fighter and 1 bomber
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 1);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 1);
}
@Test
public void testAACasualtiesLowLuckMixedWithRollingForBombers() {
final GameData data = bridge.getData();
makeGameLowLuck(data);
setSelectAACasualties(data, false);
// 6 bombers, 7 fighters
final Collection<Unit> planes = bomber(data).create(6, british(data));
planes.addAll(fighter(data).create(7, british(data)));
final Collection<Unit> defendingAA = territory("Germany", data).getUnits().getMatches(Matches.UnitIsAAforAnything);
// 1 roll for the extra fighter
final ScriptedRandomSource randomSource = new ScriptedRandomSource(new int[] {0, ScriptedRandomSource.ERROR});
bridge.setRandomSource(randomSource);
final DiceRoll roll =
DiceRoll
.rollAA(
Match.getMatches(planes,
Matches
.unitIsOfTypes(UnitAttachment.get(defendingAA.iterator().next().getType()).getTargetsAA(data))),
defendingAA, bridge, territory("Germany", data), true);
// make sure we rolled once
assertEquals(1, randomSource.getTotalRolled());
final Collection<Unit> casualties = BattleCalculator.getAACasualties(false, planes, planes, defendingAA,
defendingAA, roll, bridge, null, null, null, territory("Germany", data), null, false, null).getKilled();
assertEquals(casualties.size(), 3);
// should be 2 fighters and 1 bombers
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber), 1);
assertEquals(Match.countMatches(casualties, Matches.UnitIsStrategicBomber.invert()), 2);
}
// Radar AA tests removed, because "revised" does not have radar tech.
}