mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
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:
parent
138788659a
commit
f4572faf8b
5 changed files with 48 additions and 30 deletions
|
|
@ -909,6 +909,7 @@ public class ComputerPlayer6 extends ComputerPlayer {
|
||||||
List<Permanent> blockers = entry.getValue();
|
List<Permanent> blockers = entry.getValue();
|
||||||
if (blockers != null) {
|
if (blockers != null) {
|
||||||
for (Permanent blocker : blockers) {
|
for (Permanent blocker : blockers) {
|
||||||
|
// TODO: buggy or miss on multi blocker requirements?!
|
||||||
player.declareBlocker(player.getId(), blocker.getId(), attackerId, game);
|
player.declareBlocker(player.getId(), blocker.getId(), attackerId, game);
|
||||||
blocked = true;
|
blocked = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,28 +83,17 @@ public final class CombatUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sortByPower(List<Permanent> permanents, final boolean ascending) {
|
public static void sortByPower(List<Permanent> permanents, final boolean ascending) {
|
||||||
Collections.sort(permanents, new Comparator<Permanent>() {
|
permanents.sort(Comparator.comparingInt(p -> p.getPower().getValue()));
|
||||||
@Override
|
if (!ascending) {
|
||||||
public int compare(Permanent o1, Permanent o2) {
|
Collections.reverse(permanents);
|
||||||
if (ascending) {
|
|
||||||
return o1.getPower().getValue() - o2.getPower().getValue();
|
|
||||||
} else {
|
|
||||||
return o2.getPower().getValue() - o1.getPower().getValue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Permanent getWorstCreature(List<Permanent> creatures) {
|
public static Permanent getWorstCreature(List<Permanent> creatures) {
|
||||||
if (creatures.isEmpty()) {
|
if (creatures.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Collections.sort(creatures, new Comparator<Permanent>() {
|
creatures.sort(Comparator.comparingInt(p -> p.getPower().getValue()));
|
||||||
@Override
|
|
||||||
public int compare(Permanent o1, Permanent o2) {
|
|
||||||
return o2.getPower().getValue() - o1.getPower().getValue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return creatures.get(0);
|
return creatures.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
package mage.cards.d;
|
package mage.cards.d;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.DelayedTriggeredAbility;
|
import mage.abilities.DelayedTriggeredAbility;
|
||||||
|
|
@ -16,11 +15,7 @@ import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||||
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
|
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.*;
|
||||||
import mage.constants.ComparisonType;
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.filter.common.FilterPermanentCard;
|
import mage.filter.common.FilterPermanentCard;
|
||||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
|
@ -29,14 +24,18 @@ import mage.game.permanent.Permanent;
|
||||||
import mage.target.common.TargetCardInLibrary;
|
import mage.target.common.TargetCardInLibrary;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author bunchOfDevs
|
* @author bunchOfDevs
|
||||||
*/
|
*/
|
||||||
public final class DefiantVanguard extends CardImpl {
|
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");
|
private static final FilterPermanentCard filter = new FilterPermanentCard("Rebel permanent card with mana value 4 or less");
|
||||||
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(SubType.REBEL.getPredicate());
|
filter.add(SubType.REBEL.getPredicate());
|
||||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5));
|
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5));
|
||||||
|
|
@ -100,8 +99,8 @@ class DefiantVanguardTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
Permanent blocked = game.getPermanent(event.getTargetId());
|
Permanent blocked = game.getPermanent(event.getTargetId());
|
||||||
if (blocker != null
|
if (blocker != null
|
||||||
&& blocked != null) {
|
&& blocked != null) {
|
||||||
game.getState().setValue(blocked.toString(), blocked.getZoneChangeCounter(game)); // in case the attacker changes zone
|
game.getState().setValue(DefiantVanguard.EFFECT_KEY + blocked.getId(), 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 + blocker.getId(), blocker.getZoneChangeCounter(game)); // in case the blocker changes zone
|
||||||
getAllEffects().setTargetPointer(new FixedTarget(blocked.getId()));
|
getAllEffects().setTargetPointer(new FixedTarget(blocked.getId()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -131,13 +130,13 @@ class DefiantVanguardEffect extends OneShotEffect {
|
||||||
Permanent blockedCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
Permanent blockedCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
Permanent defiantVanguard = game.getPermanent(source.getSourceId());
|
Permanent defiantVanguard = game.getPermanent(source.getSourceId());
|
||||||
if (blockedCreature != null) {
|
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);
|
blockedCreature.destroy(source, game, false);
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (defiantVanguard != null) {
|
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);
|
defiantVanguard.destroy(source, game, false);
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
||||||
@Test
|
@Test
|
||||||
public void test_Block_1_small_attacker_vs_2_big_blockers() {
|
public void test_Block_1_small_attacker_vs_2_big_blockers() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
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");
|
attack(1, playerA, "Arbor Elf");
|
||||||
|
|
||||||
|
|
@ -161,6 +162,31 @@ public class BlockSimulationAITest extends CardTestPlayerBaseWithAIHelps {
|
||||||
assertPermanentCount(playerB, "Spectral Bears", 1);
|
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 DeathtouchAbility
|
||||||
// TODO: add tests for FirstStrikeAbility
|
// TODO: add tests for FirstStrikeAbility
|
||||||
// TODO: add tests for DoubleStrikeAbility
|
// TODO: add tests for DoubleStrikeAbility
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import mage.constants.*;
|
||||||
import mage.counters.Counter;
|
import mage.counters.Counter;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.counters.Counters;
|
import mage.counters.Counters;
|
||||||
import mage.filter.*;
|
import mage.filter.FilterOpponent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.GameState;
|
import mage.game.GameState;
|
||||||
import mage.game.ZoneChangeInfo;
|
import mage.game.ZoneChangeInfo;
|
||||||
|
|
@ -210,8 +210,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
+ ", " + getBasicMageObject().getClass().getSimpleName()
|
+ ", " + getBasicMageObject().getClass().getSimpleName()
|
||||||
+ ", " + imageInfo
|
+ ", " + imageInfo
|
||||||
+ ", " + this.getPower() + "/" + this.getToughness()
|
+ ", " + this.getPower() + "/" + this.getToughness()
|
||||||
|
+ (this.getDamage() > 0 ? ", damage " + this.getDamage() : "")
|
||||||
+ (this.isCopy() ? ", copy" : "")
|
+ (this.isCopy() ? ", copy" : "")
|
||||||
+ (this.isTapped() ? ", tapped" : "");
|
+ (this.isTapped() ? ", tapped" : "")
|
||||||
|
+ (this.isAttacking() ? ", attacking" : "")
|
||||||
|
+ (this.getBlocking() > 0 ? ", blocking" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue