diff --git a/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java b/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java index 01d01dcf088..05658d0a022 100644 --- a/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java +++ b/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java @@ -29,6 +29,7 @@ package mage.player.ai; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -73,7 +74,10 @@ import mage.cards.Card; import mage.cards.Cards; import mage.cards.decks.Deck; import mage.choices.Choice; +import mage.filter.Filter; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureForCombat; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterLandCard; import mage.filter.common.FilterNonlandCard; import mage.game.Game; @@ -82,11 +86,13 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.players.PlayerImpl; import mage.target.Target; +import mage.target.TargetAmount; import mage.target.TargetCard; import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetDiscard; -import mage.target.common.TargetSacrificePermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreatureOrPlayerAmount; import mage.util.Copier; import mage.util.Logging; import mage.util.TreeNode; @@ -111,6 +117,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { human = false; } + protected ComputerPlayer(UUID id) { + super(id); + } + @Override public boolean chooseMulligan(Game game) { logger.fine("chooseMulligan"); @@ -157,10 +167,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } - if (target instanceof TargetSacrificePermanent) { + if (target instanceof TargetControlledPermanent) { List targets; - targets = threats(playerId, (TargetPermanent) target, game); - Collections.reverse(targets); + targets = threats(playerId, ((TargetPermanent)target).getFilter(), game); + if (!outcome.isGood()) + Collections.reverse(targets); for (Permanent permanent: targets) { if (target.canTarget(permanent.getId(), game)) { target.addTarget(permanent.getId(), game); @@ -171,10 +182,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target instanceof TargetPermanent) { List targets; if (outcome.isGood()) { - targets = threats(playerId, (TargetPermanent) target, game); + targets = threats(playerId, ((TargetPermanent)target).getFilter(), game); } else { - targets = threats(opponentId, (TargetPermanent) target, game); + targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game); } for (Permanent permanent: targets) { if (target.canTarget(permanent.getId(), game)) { @@ -186,6 +197,34 @@ public class ComputerPlayer extends PlayerImpl implements Player { return false; } + @Override + public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Game game) { + logger.fine("chooseTarget: " + outcome.toString() + ":" + target.toString()); + UUID opponentId = game.getOpponents(playerId).iterator().next(); + if (target instanceof TargetCreatureOrPlayerAmount) { + if (game.getPlayer(opponentId).getLife() <= target.getAmountRemaining()) { + target.addTarget(opponentId, target.getAmountRemaining(), game); + return true; + } + List targets; + if (outcome.isGood()) { + targets = threats(playerId, new FilterCreaturePermanent(), game); + } + else { + targets = threats(opponentId, new FilterCreaturePermanent(), game); + } + for (Permanent permanent: targets) { + if (target.canTarget(permanent.getId(), game)) { + if (permanent.getToughness().getValue() <= target.getAmountRemaining()) { + target.addTarget(permanent.getId(), permanent.getToughness().getValue(), game); + return true; + } + } + } + } + return false; + } + @Override public void priority(Game game) { logger.fine("priority"); @@ -194,7 +233,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (game.isMainPhase() && game.getStack().isEmpty()) { playLand(game); } - switch (game.getTurn().getStep()) { + switch (game.getTurn().getStepType()) { case UPKEEP: findPlayables(game); break; @@ -250,7 +289,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } else { //respond to opponent events - switch (game.getTurn().getStep()) { + switch (game.getTurn().getStepType()) { case UPKEEP: findPlayables(game); case DECLARE_ATTACKERS: @@ -260,10 +299,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { playDamage(game.getCombat().getAttackers(), game); } } - this.passed = true; + pass(); } - private void playLand(Game game) { + protected void playLand(Game game) { logger.fine("playLand"); List lands = hand.getCards(new FilterLandCard()); while (lands.size() > 0 && this.landsPlayed < this.landsPerTurn) { @@ -275,13 +314,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } - private void playALand(List lands, Game game) { + protected void playALand(List lands, Game game) { logger.fine("playALand"); //play a land that will allow us to play an unplayable for (Mana mana: unplayable.keySet()) { for (Card card: lands) { for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - if (ability.getNetMana().enough(mana)) { + if (ability.getNetMana(game).enough(mana)) { this.playLand(card, game); lands.remove(card); return; @@ -293,7 +332,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (Mana mana: unplayable.keySet()) { for (Card card: lands) { for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - if (mana.contains(ability.getNetMana())) { + if (mana.contains(ability.getNetMana(game))) { this.playLand(card, game); lands.remove(card); return; @@ -306,7 +345,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { lands.remove(0); } - private void findPlayables(Game game) { + protected void findPlayables(Game game) { playableInstant.clear(); playableNonInstant.clear(); unplayable.clear(); @@ -366,20 +405,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { logger.fine("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() ); } + @Override protected ManaOptions getManaAvailable(Game game) { - logger.fine("getManaAvailable"); - List manaPerms = this.getAvailableManaProducers(game); - - ManaOptions available = new ManaOptions(); - for (Permanent perm: manaPerms) { - available.addMana(perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)); - } - return available; +// logger.fine("getManaAvailable"); + return super.getManaAvailable(game); } @Override public boolean playMana(ManaCost unpaid, Game game) { - logger.fine("playMana"); +// logger.fine("playMana"); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { @@ -394,7 +428,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // pay all colored costs first for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { if (cost instanceof ColoredManaCost) { - if (cost.testPay(ability.getNetMana())) { + if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) return true; } @@ -403,7 +437,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // then pay hybrid for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { if (cost instanceof HybridManaCost) { - if (cost.testPay(ability.getNetMana())) { + if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) return true; } @@ -412,7 +446,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // then pay mono hybrid for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { if (cost instanceof MonoHybridManaCost) { - if (cost.testPay(ability.getNetMana())) { + if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) return true; } @@ -421,7 +455,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // finally pay generic for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { if (cost instanceof GenericManaCost) { - if (cost.testPay(ability.getNetMana())) { + if (cost.testPay(ability.getNetMana(game))) { if (activateAbility(ability, game)) return true; } @@ -431,6 +465,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { return false; } + /** + * + * returns a list of Permanents that produce mana sorted by the number of mana the Permanent produces + * that match the unpaid costs in ascending order + * + * the idea is that we should pay costs first from mana producers that produce only one type of mana + * and save the multi-mana producers for those costs that can't be paid by any other producers + * + * @param unpaid - the amount of unpaid mana costs + * @param game + * @return List + */ private List getSortedProducers(ManaCosts unpaid, Game game) { List unsorted = this.getAvailableManaProducers(game); Map scored = new HashMap(); @@ -438,7 +484,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { int score = 0; for (ManaCost cost: unpaid) { for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - if (cost.testPay(ability.getNetMana())) { + if (cost.testPay(ability.getNetMana(game))) { score++; break; } @@ -500,9 +546,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - public boolean searchCards(Cards cards, TargetCard target, Game game) { - logger.fine("searchCards"); - //TODO: improve ths + public boolean chooseTarget(Cards cards, TargetCard target, Game game) { + logger.fine("chooseTarget"); + //TODO: improve this //return first match for (Card card: cards.getCards(target.getFilter())) { target.addTarget(card.getId(), game); @@ -584,18 +630,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { return min; } + @Override protected List getAvailableManaProducers(Game game) { - logger.fine("getAvailableManaProducers"); - List result = new ArrayList(); - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { - for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - if (ability.canActivate(playerId, game)) { - result.add(permanent); - break; - } - } - } - return result; +// logger.fine("getAvailableManaProducers"); + return super.getAvailableManaProducers(game); } protected Attackers getPotentialAttackers(Game game) { @@ -739,13 +777,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { return worst; } - protected List threats(UUID playerId, TargetPermanent target, Game game) { - List threats = game.getBattlefield().getAllActivePermanents(target.getFilter(), playerId); + protected List threats(UUID playerId, FilterPermanent filter, Game game) { + List threats = game.getBattlefield().getAllActivePermanents(filter, playerId); Collections.sort(threats, new PermanentComparator(game)); return threats; } - private void logState(Game game) { + protected void logState(Game game) { StringBuilder sb = new StringBuilder(); sb.append("computer player hand: "); for (Card card: hand.values()) { @@ -790,5 +828,14 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + unplayable = new TreeMap(); + playableNonInstant = new ArrayList(); + playableInstant = new ArrayList(); + playableAbilities = new ArrayList(); + } + } diff --git a/Mage.Player.AI/src/mage/player/ai/simulators/ActionSimulator.java b/Mage.Player.AI/src/mage/player/ai/simulators/ActionSimulator.java index e4bd1c231d3..97071cccd22 100644 --- a/Mage.Player.AI/src/mage/player/ai/simulators/ActionSimulator.java +++ b/Mage.Player.AI/src/mage/player/ai/simulators/ActionSimulator.java @@ -33,7 +33,6 @@ import java.util.List; import mage.abilities.ActivatedAbility; import mage.cards.Card; import mage.game.Game; -import mage.game.GameState; import mage.game.permanent.Permanent; import mage.player.ai.ComputerPlayer; import mage.player.ai.PermanentEvaluator;