mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 18:50:06 -08:00
...
This commit is contained in:
parent
8dd685e671
commit
c9d6ee4575
2 changed files with 92 additions and 46 deletions
|
|
@ -29,6 +29,7 @@
|
||||||
package mage.player.ai;
|
package mage.player.ai;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -73,7 +74,10 @@ import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.choices.Choice;
|
import mage.choices.Choice;
|
||||||
|
import mage.filter.Filter;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
import mage.filter.common.FilterCreatureForCombat;
|
import mage.filter.common.FilterCreatureForCombat;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.filter.common.FilterLandCard;
|
import mage.filter.common.FilterLandCard;
|
||||||
import mage.filter.common.FilterNonlandCard;
|
import mage.filter.common.FilterNonlandCard;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
|
@ -82,11 +86,13 @@ import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.players.PlayerImpl;
|
import mage.players.PlayerImpl;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
|
import mage.target.TargetAmount;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
import mage.target.TargetPlayer;
|
import mage.target.TargetPlayer;
|
||||||
import mage.target.common.TargetDiscard;
|
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.Copier;
|
||||||
import mage.util.Logging;
|
import mage.util.Logging;
|
||||||
import mage.util.TreeNode;
|
import mage.util.TreeNode;
|
||||||
|
|
@ -111,6 +117,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
human = false;
|
human = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ComputerPlayer(UUID id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean chooseMulligan(Game game) {
|
public boolean chooseMulligan(Game game) {
|
||||||
logger.fine("chooseMulligan");
|
logger.fine("chooseMulligan");
|
||||||
|
|
@ -157,10 +167,11 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (target instanceof TargetSacrificePermanent) {
|
if (target instanceof TargetControlledPermanent) {
|
||||||
List<Permanent> targets;
|
List<Permanent> targets;
|
||||||
targets = threats(playerId, (TargetPermanent) target, game);
|
targets = threats(playerId, ((TargetPermanent)target).getFilter(), game);
|
||||||
Collections.reverse(targets);
|
if (!outcome.isGood())
|
||||||
|
Collections.reverse(targets);
|
||||||
for (Permanent permanent: targets) {
|
for (Permanent permanent: targets) {
|
||||||
if (target.canTarget(permanent.getId(), game)) {
|
if (target.canTarget(permanent.getId(), game)) {
|
||||||
target.addTarget(permanent.getId(), game);
|
target.addTarget(permanent.getId(), game);
|
||||||
|
|
@ -171,10 +182,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
if (target instanceof TargetPermanent) {
|
if (target instanceof TargetPermanent) {
|
||||||
List<Permanent> targets;
|
List<Permanent> targets;
|
||||||
if (outcome.isGood()) {
|
if (outcome.isGood()) {
|
||||||
targets = threats(playerId, (TargetPermanent) target, game);
|
targets = threats(playerId, ((TargetPermanent)target).getFilter(), game);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
targets = threats(opponentId, (TargetPermanent) target, game);
|
targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game);
|
||||||
}
|
}
|
||||||
for (Permanent permanent: targets) {
|
for (Permanent permanent: targets) {
|
||||||
if (target.canTarget(permanent.getId(), game)) {
|
if (target.canTarget(permanent.getId(), game)) {
|
||||||
|
|
@ -186,6 +197,34 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
return false;
|
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<Permanent> 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
|
@Override
|
||||||
public void priority(Game game) {
|
public void priority(Game game) {
|
||||||
logger.fine("priority");
|
logger.fine("priority");
|
||||||
|
|
@ -194,7 +233,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
if (game.isMainPhase() && game.getStack().isEmpty()) {
|
if (game.isMainPhase() && game.getStack().isEmpty()) {
|
||||||
playLand(game);
|
playLand(game);
|
||||||
}
|
}
|
||||||
switch (game.getTurn().getStep()) {
|
switch (game.getTurn().getStepType()) {
|
||||||
case UPKEEP:
|
case UPKEEP:
|
||||||
findPlayables(game);
|
findPlayables(game);
|
||||||
break;
|
break;
|
||||||
|
|
@ -250,7 +289,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//respond to opponent events
|
//respond to opponent events
|
||||||
switch (game.getTurn().getStep()) {
|
switch (game.getTurn().getStepType()) {
|
||||||
case UPKEEP:
|
case UPKEEP:
|
||||||
findPlayables(game);
|
findPlayables(game);
|
||||||
case DECLARE_ATTACKERS:
|
case DECLARE_ATTACKERS:
|
||||||
|
|
@ -260,10 +299,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
playDamage(game.getCombat().getAttackers(), game);
|
playDamage(game.getCombat().getAttackers(), game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.passed = true;
|
pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playLand(Game game) {
|
protected void playLand(Game game) {
|
||||||
logger.fine("playLand");
|
logger.fine("playLand");
|
||||||
List<Card> lands = hand.getCards(new FilterLandCard());
|
List<Card> lands = hand.getCards(new FilterLandCard());
|
||||||
while (lands.size() > 0 && this.landsPlayed < this.landsPerTurn) {
|
while (lands.size() > 0 && this.landsPlayed < this.landsPerTurn) {
|
||||||
|
|
@ -275,13 +314,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playALand(List<Card> lands, Game game) {
|
protected void playALand(List<Card> lands, Game game) {
|
||||||
logger.fine("playALand");
|
logger.fine("playALand");
|
||||||
//play a land that will allow us to play an unplayable
|
//play a land that will allow us to play an unplayable
|
||||||
for (Mana mana: unplayable.keySet()) {
|
for (Mana mana: unplayable.keySet()) {
|
||||||
for (Card card: lands) {
|
for (Card card: lands) {
|
||||||
for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (ability.getNetMana().enough(mana)) {
|
if (ability.getNetMana(game).enough(mana)) {
|
||||||
this.playLand(card, game);
|
this.playLand(card, game);
|
||||||
lands.remove(card);
|
lands.remove(card);
|
||||||
return;
|
return;
|
||||||
|
|
@ -293,7 +332,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
for (Mana mana: unplayable.keySet()) {
|
for (Mana mana: unplayable.keySet()) {
|
||||||
for (Card card: lands) {
|
for (Card card: lands) {
|
||||||
for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (mana.contains(ability.getNetMana())) {
|
if (mana.contains(ability.getNetMana(game))) {
|
||||||
this.playLand(card, game);
|
this.playLand(card, game);
|
||||||
lands.remove(card);
|
lands.remove(card);
|
||||||
return;
|
return;
|
||||||
|
|
@ -306,7 +345,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
lands.remove(0);
|
lands.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findPlayables(Game game) {
|
protected void findPlayables(Game game) {
|
||||||
playableInstant.clear();
|
playableInstant.clear();
|
||||||
playableNonInstant.clear();
|
playableNonInstant.clear();
|
||||||
unplayable.clear();
|
unplayable.clear();
|
||||||
|
|
@ -366,20 +405,15 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
logger.fine("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() );
|
logger.fine("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected ManaOptions getManaAvailable(Game game) {
|
protected ManaOptions getManaAvailable(Game game) {
|
||||||
logger.fine("getManaAvailable");
|
// logger.fine("getManaAvailable");
|
||||||
List<Permanent> manaPerms = this.getAvailableManaProducers(game);
|
return super.getManaAvailable(game);
|
||||||
|
|
||||||
ManaOptions available = new ManaOptions();
|
|
||||||
for (Permanent perm: manaPerms) {
|
|
||||||
available.addMana(perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD));
|
|
||||||
}
|
|
||||||
return available;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playMana(ManaCost unpaid, Game game) {
|
public boolean playMana(ManaCost unpaid, Game game) {
|
||||||
logger.fine("playMana");
|
// logger.fine("playMana");
|
||||||
ManaCost cost;
|
ManaCost cost;
|
||||||
List<Permanent> producers;
|
List<Permanent> producers;
|
||||||
if (unpaid instanceof ManaCosts) {
|
if (unpaid instanceof ManaCosts) {
|
||||||
|
|
@ -394,7 +428,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
// pay all colored costs first
|
// pay all colored costs first
|
||||||
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (cost instanceof ColoredManaCost) {
|
if (cost instanceof ColoredManaCost) {
|
||||||
if (cost.testPay(ability.getNetMana())) {
|
if (cost.testPay(ability.getNetMana(game))) {
|
||||||
if (activateAbility(ability, game))
|
if (activateAbility(ability, game))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +437,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
// then pay hybrid
|
// then pay hybrid
|
||||||
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (cost instanceof HybridManaCost) {
|
if (cost instanceof HybridManaCost) {
|
||||||
if (cost.testPay(ability.getNetMana())) {
|
if (cost.testPay(ability.getNetMana(game))) {
|
||||||
if (activateAbility(ability, game))
|
if (activateAbility(ability, game))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -412,7 +446,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
// then pay mono hybrid
|
// then pay mono hybrid
|
||||||
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (cost instanceof MonoHybridManaCost) {
|
if (cost instanceof MonoHybridManaCost) {
|
||||||
if (cost.testPay(ability.getNetMana())) {
|
if (cost.testPay(ability.getNetMana(game))) {
|
||||||
if (activateAbility(ability, game))
|
if (activateAbility(ability, game))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -421,7 +455,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
// finally pay generic
|
// finally pay generic
|
||||||
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (cost instanceof GenericManaCost) {
|
if (cost instanceof GenericManaCost) {
|
||||||
if (cost.testPay(ability.getNetMana())) {
|
if (cost.testPay(ability.getNetMana(game))) {
|
||||||
if (activateAbility(ability, game))
|
if (activateAbility(ability, game))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -431,6 +465,18 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
return false;
|
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<Permanent>
|
||||||
|
*/
|
||||||
private List<Permanent> getSortedProducers(ManaCosts unpaid, Game game) {
|
private List<Permanent> getSortedProducers(ManaCosts unpaid, Game game) {
|
||||||
List<Permanent> unsorted = this.getAvailableManaProducers(game);
|
List<Permanent> unsorted = this.getAvailableManaProducers(game);
|
||||||
Map<Permanent, Integer> scored = new HashMap<Permanent, Integer>();
|
Map<Permanent, Integer> scored = new HashMap<Permanent, Integer>();
|
||||||
|
|
@ -438,7 +484,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
int score = 0;
|
int score = 0;
|
||||||
for (ManaCost cost: unpaid) {
|
for (ManaCost cost: unpaid) {
|
||||||
for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (cost.testPay(ability.getNetMana())) {
|
if (cost.testPay(ability.getNetMana(game))) {
|
||||||
score++;
|
score++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -500,9 +546,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean searchCards(Cards cards, TargetCard target, Game game) {
|
public boolean chooseTarget(Cards cards, TargetCard target, Game game) {
|
||||||
logger.fine("searchCards");
|
logger.fine("chooseTarget");
|
||||||
//TODO: improve ths
|
//TODO: improve this
|
||||||
//return first match
|
//return first match
|
||||||
for (Card card: cards.getCards(target.getFilter())) {
|
for (Card card: cards.getCards(target.getFilter())) {
|
||||||
target.addTarget(card.getId(), game);
|
target.addTarget(card.getId(), game);
|
||||||
|
|
@ -584,18 +630,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<Permanent> getAvailableManaProducers(Game game) {
|
protected List<Permanent> getAvailableManaProducers(Game game) {
|
||||||
logger.fine("getAvailableManaProducers");
|
// logger.fine("getAvailableManaProducers");
|
||||||
List<Permanent> result = new ArrayList<Permanent>();
|
return super.getAvailableManaProducers(game);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Attackers getPotentialAttackers(Game game) {
|
protected Attackers getPotentialAttackers(Game game) {
|
||||||
|
|
@ -739,13 +777,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
return worst;
|
return worst;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Permanent> threats(UUID playerId, TargetPermanent target, Game game) {
|
protected List<Permanent> threats(UUID playerId, FilterPermanent filter, Game game) {
|
||||||
List<Permanent> threats = game.getBattlefield().getAllActivePermanents(target.getFilter(), playerId);
|
List<Permanent> threats = game.getBattlefield().getAllActivePermanents(filter, playerId);
|
||||||
Collections.sort(threats, new PermanentComparator(game));
|
Collections.sort(threats, new PermanentComparator(game));
|
||||||
return threats;
|
return threats;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logState(Game game) {
|
protected void logState(Game game) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("computer player hand: ");
|
sb.append("computer player hand: ");
|
||||||
for (Card card: hand.values()) {
|
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<Mana, Card>();
|
||||||
|
playableNonInstant = new ArrayList<Card>();
|
||||||
|
playableInstant = new ArrayList<Card>();
|
||||||
|
playableAbilities = new ArrayList<ActivatedAbility>();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ import java.util.List;
|
||||||
import mage.abilities.ActivatedAbility;
|
import mage.abilities.ActivatedAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.GameState;
|
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.player.ai.ComputerPlayer;
|
import mage.player.ai.ComputerPlayer;
|
||||||
import mage.player.ai.PermanentEvaluator;
|
import mage.player.ai.PermanentEvaluator;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue