mirror of
https://github.com/correl/mage.git
synced 2025-04-11 17:00:08 -09:00
...
This commit is contained in:
parent
8dd685e671
commit
c9d6ee4575
2 changed files with 92 additions and 46 deletions
Mage.Player.AI/src/mage/player/ai
|
@ -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<Permanent> 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<Permanent> 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<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
|
||||
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<Card> 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<Card> lands, Game game) {
|
||||
protected void playALand(List<Card> 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<Permanent> 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<Permanent> 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<Permanent>
|
||||
*/
|
||||
private List<Permanent> getSortedProducers(ManaCosts unpaid, Game game) {
|
||||
List<Permanent> unsorted = this.getAvailableManaProducers(game);
|
||||
Map<Permanent, Integer> scored = new HashMap<Permanent, Integer>();
|
||||
|
@ -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<Permanent> getAvailableManaProducers(Game game) {
|
||||
logger.fine("getAvailableManaProducers");
|
||||
List<Permanent> result = new ArrayList<Permanent>();
|
||||
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<Permanent> threats(UUID playerId, TargetPermanent target, Game game) {
|
||||
List<Permanent> threats = game.getBattlefield().getAllActivePermanents(target.getFilter(), playerId);
|
||||
protected List<Permanent> threats(UUID playerId, FilterPermanent filter, Game game) {
|
||||
List<Permanent> 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<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.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;
|
||||
|
|
Loading…
Add table
Reference in a new issue