AI, combat: fixed that computer blocking an attacker by biggest creature instead optimal;

refactor: fixed that Defiant Vanguard depends on debug data;
This commit is contained in:
Oleg Agafonov 2024-12-25 18:23:43 +04:00
parent 138788659a
commit f4572faf8b
5 changed files with 48 additions and 30 deletions

View file

@ -909,6 +909,7 @@ public class ComputerPlayer6 extends ComputerPlayer {
List<Permanent> blockers = entry.getValue();
if (blockers != null) {
for (Permanent blocker : blockers) {
// TODO: buggy or miss on multi blocker requirements?!
player.declareBlocker(player.getId(), blocker.getId(), attackerId, game);
blocked = true;
}

View file

@ -83,28 +83,17 @@ public final class CombatUtil {
}
public static void sortByPower(List<Permanent> permanents, final boolean ascending) {
Collections.sort(permanents, new Comparator<Permanent>() {
@Override
public int compare(Permanent o1, Permanent o2) {
if (ascending) {
return o1.getPower().getValue() - o2.getPower().getValue();
} else {
return o2.getPower().getValue() - o1.getPower().getValue();
}
}
});
permanents.sort(Comparator.comparingInt(p -> p.getPower().getValue()));
if (!ascending) {
Collections.reverse(permanents);
}
}
public static Permanent getWorstCreature(List<Permanent> creatures) {
if (creatures.isEmpty()) {
return null;
}
Collections.sort(creatures, new Comparator<Permanent>() {
@Override
public int compare(Permanent o1, Permanent o2) {
return o2.getPower().getValue() - o1.getPower().getValue();
}
});
creatures.sort(Comparator.comparingInt(p -> p.getPower().getValue()));
return creatures.get(0);
}

View file

@ -1,7 +1,6 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
@ -16,11 +15,7 @@ import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
@ -29,14 +24,18 @@ import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInLibrary;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author bunchOfDevs
*/
public final class DefiantVanguard extends CardImpl {
protected static final String EFFECT_KEY = "DefiantVanguardEffect_";
private static final FilterPermanentCard filter = new FilterPermanentCard("Rebel permanent card with mana value 4 or less");
static {
filter.add(SubType.REBEL.getPredicate());
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5));
@ -100,8 +99,8 @@ class DefiantVanguardTriggeredAbility extends TriggeredAbilityImpl {
Permanent blocked = game.getPermanent(event.getTargetId());
if (blocker != null
&& blocked != null) {
game.getState().setValue(blocked.toString(), blocked.getZoneChangeCounter(game)); // in case the attacker changes zone
game.getState().setValue(blocker.toString(), blocker.getZoneChangeCounter(game)); // in case the blocker changes zone
game.getState().setValue(DefiantVanguard.EFFECT_KEY + blocked.getId(), blocked.getZoneChangeCounter(game)); // in case the attacker changes zone
game.getState().setValue(DefiantVanguard.EFFECT_KEY + blocker.getId(), blocker.getZoneChangeCounter(game)); // in case the blocker changes zone
getAllEffects().setTargetPointer(new FixedTarget(blocked.getId()));
return true;
}
@ -131,13 +130,13 @@ class DefiantVanguardEffect extends OneShotEffect {
Permanent blockedCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
Permanent defiantVanguard = game.getPermanent(source.getSourceId());
if (blockedCreature != null) {
if (game.getState().getValue(blockedCreature.toString()).equals(blockedCreature.getZoneChangeCounter(game))) { // true if it did not change zones
if (game.getState().getValue(DefiantVanguard.EFFECT_KEY + blockedCreature.getId()).equals(blockedCreature.getZoneChangeCounter(game))) { // true if it did not change zones
blockedCreature.destroy(source, game, false);
result = true;
}
}
if (defiantVanguard != null) {
if (game.getState().getValue(defiantVanguard.toString()).equals(defiantVanguard.getZoneChangeCounter(game))) { // true if it did not change zones
if (game.getState().getValue(DefiantVanguard.EFFECT_KEY + defiantVanguard.getId()).equals(defiantVanguard.getZoneChangeCounter(game))) { // true if it did not change zones
defiantVanguard.destroy(source, game, false);
result = true;
}

View file

@ -32,7 +32,8 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
@Test
public void test_Block_1_small_attacker_vs_2_big_blockers() {
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 2); // 2/2
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
addCard(Zone.BATTLEFIELD, playerB, "Spectral Bears", 1); // 3/3
attack(1, playerA, "Arbor Elf");
@ -161,6 +162,31 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
assertPermanentCount(playerB, "Spectral Bears", 1);
}
@Test
public void test_Block_1_attacker_vs_many_blockers() {
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2
//
addCard(Zone.BATTLEFIELD, playerB, "Arbor Elf", 1); // 1/1
addCard(Zone.BATTLEFIELD, playerB, "Spectral Bears", 1); // 3/3
addCard(Zone.BATTLEFIELD, playerB, "Deadbridge Goliath", 1); // 5/5
addCard(Zone.BATTLEFIELD, playerB, "Colossal Dreadmaw", 1); // 6/6
attack(1, playerA, "Balduvian Bears");
// ai must use smaller blocker and survive (3/3 must block 2/2)
aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB);
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerA, "Balduvian Bears", 1);
assertDamageReceived(playerB, "Spectral Bears", 2);
}
// TODO: add tests with multi blocker requirement effects
// TODO: add tests for DeathtouchAbility
// TODO: add tests for FirstStrikeAbility
// TODO: add tests for DoubleStrikeAbility

View file

@ -21,7 +21,7 @@ import mage.constants.*;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.counters.Counters;
import mage.filter.*;
import mage.filter.FilterOpponent;
import mage.game.Game;
import mage.game.GameState;
import mage.game.ZoneChangeInfo;
@ -210,8 +210,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
+ ", " + getBasicMageObject().getClass().getSimpleName()
+ ", " + imageInfo
+ ", " + this.getPower() + "/" + this.getToughness()
+ (this.getDamage() > 0 ? ", damage " + this.getDamage() : "")
+ (this.isCopy() ? ", copy" : "")
+ (this.isTapped() ? ", tapped" : "");
+ (this.isTapped() ? ", tapped" : "")
+ (this.isAttacking() ? ", attacking" : "")
+ (this.getBlocking() > 0 ? ", blocking" : "");
}
@Override