mirror of
https://github.com/correl/mage.git
synced 2025-04-06 17:00:12 -09:00
Changed AI X costs handling according human handling. Fixed AI handling of modal spells. Changed some AI setting. Changes to AI lgging.
This commit is contained in:
parent
987bfb588f
commit
9450074b70
11 changed files with 287 additions and 222 deletions
Mage.Server.Plugins
Mage.Player.AI.MA/src/mage/player/ai
Mage.Player.AI/src/main/java/mage/player/ai
Mage.Player.Human/src/mage/player/human
Mage.Tests/src/test/java/org/mage/test/player
Mage/src/mage
|
@ -35,11 +35,8 @@ import mage.Constants.PhaseStep;
|
||||||
import mage.Constants.RangeOfInfluence;
|
import mage.Constants.RangeOfInfluence;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.ActivatedAbility;
|
import mage.abilities.ActivatedAbility;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.common.PassAbility;
|
import mage.abilities.common.PassAbility;
|
||||||
import mage.abilities.costs.mana.GenericManaCost;
|
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
|
||||||
import mage.abilities.costs.mana.VariableManaCost;
|
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.SearchEffect;
|
import mage.abilities.effects.SearchEffect;
|
||||||
import mage.abilities.keyword.*;
|
import mage.abilities.keyword.*;
|
||||||
|
@ -63,6 +60,7 @@ import mage.player.ai.util.CombatUtil;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
|
import mage.target.Targets;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,7 +85,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
protected Set<String> actionCache;
|
protected Set<String> actionCache;
|
||||||
private static final List<TreeOptimizer> optimizers = new ArrayList<TreeOptimizer>();
|
private static final List<TreeOptimizer> optimizers = new ArrayList<TreeOptimizer>();
|
||||||
|
|
||||||
private int lastTurnOutput = 0;
|
protected int lastLoggedTurn = 0;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
optimizers.add(new LevelUpOptimizer());
|
optimizers.add(new LevelUpOptimizer());
|
||||||
|
@ -97,7 +95,11 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
|
|
||||||
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
public ComputerPlayer6(String name, RangeOfInfluence range, int skill) {
|
||||||
super(name, range);
|
super(name, range);
|
||||||
maxDepth = skill * 2;
|
if (skill < 4) {
|
||||||
|
maxDepth = 4;
|
||||||
|
} else {
|
||||||
|
maxDepth = skill;
|
||||||
|
}
|
||||||
maxThink = skill * 3;
|
maxThink = skill * 3;
|
||||||
maxNodes = Config2.maxNodes;
|
maxNodes = Config2.maxNodes;
|
||||||
getSuggestedActions();
|
getSuggestedActions();
|
||||||
|
@ -136,10 +138,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
case POSTCOMBAT_MAIN:
|
case POSTCOMBAT_MAIN:
|
||||||
if (game.getActivePlayerId().equals(playerId)) {
|
if (game.getActivePlayerId().equals(playerId)) {
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
printOutState(game, playerId);
|
printOutState(game);
|
||||||
for (UUID opponentId : game.getOpponents(playerId)) {
|
|
||||||
printOutState(game, opponentId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (actions.size() == 0) {
|
if (actions.size() == 0) {
|
||||||
calculateActions(game);
|
calculateActions(game);
|
||||||
|
@ -182,14 +181,23 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void printOutState(Game game) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
printOutState(game, playerId);
|
||||||
|
for (UUID opponentId : game.getOpponents(playerId)) {
|
||||||
|
printOutState(game, opponentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void printOutState(Game game, UUID playerId) {
|
protected void printOutState(Game game, UUID playerId) {
|
||||||
if (lastTurnOutput != game.getTurnNum()) {
|
if (lastLoggedTurn != game.getTurnNum()) {
|
||||||
lastTurnOutput = game.getTurnNum();
|
lastLoggedTurn = game.getTurnNum();
|
||||||
logger.info(new StringBuilder("------------------------ ").append("Turn: ").append(game.getTurnNum()).append(" --------------------------------------------------------------").toString());
|
logger.info(new StringBuilder("------------------------ ").append("Turn: ").append(game.getTurnNum()).append("] --------------------------------------------------------------").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player = game.getPlayer(playerId);
|
Player player = game.getPlayer(playerId);
|
||||||
logger.info(new StringBuilder("[").append(game.getPlayer(playerId).getName()).append("] ").append(game.getTurn().getStepType().name()).append(", life=").append(player.getLife()).toString());
|
logger.info(new StringBuilder("[").append(game.getPlayer(playerId).getName()).append("], life = ").append(player.getLife()).toString());
|
||||||
StringBuilder sb = new StringBuilder("-> Hand: [");
|
StringBuilder sb = new StringBuilder("-> Hand: [");
|
||||||
for (Card card : player.getHand().getCards(game)) {
|
for (Card card : player.getHand().getCards(game)) {
|
||||||
sb.append(card.getName()).append(";");
|
sb.append(card.getName()).append(";");
|
||||||
|
@ -219,7 +227,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
boolean usedStack = false;
|
boolean usedStack = false;
|
||||||
while (actions.peek() != null) {
|
while (actions.peek() != null) {
|
||||||
Ability ability = actions.poll();
|
Ability ability = actions.poll();
|
||||||
logger.info(new StringBuilder("Act -------------> [").append(game.getPlayer(playerId).getName()).append("] Action: ").append(ability.toString()).toString());
|
logger.info(new StringBuilder("===> Act [").append(game.getPlayer(playerId).getName()).append("] Action: ").append(ability.toString()).toString());
|
||||||
if (ability.getTargets().size() > 0) {
|
if (ability.getTargets().size() > 0) {
|
||||||
for (Target target : ability.getTargets()) {
|
for (Target target : ability.getTargets()) {
|
||||||
for (UUID id : target.getTargets()) {
|
for (UUID id : target.getTargets()) {
|
||||||
|
@ -240,9 +248,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Card card = game.getCard(ability.getSourceId());
|
Card card = game.getCard(ability.getSourceId());
|
||||||
String action = it.next();
|
String action = it.next();
|
||||||
logger.info("action=" + action + ";card=" + card);
|
logger.info("Suggested action=" + action + ";card=" + card);
|
||||||
if (action.equals(card.getName())) {
|
if (action.equals(card.getName())) {
|
||||||
logger.info("removed from suggested=" + action);
|
logger.info("-> removed from suggested=" + action);
|
||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +295,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
test = root;
|
test = root;
|
||||||
root = root.children.get(0);
|
root = root.children.get(0);
|
||||||
}
|
}
|
||||||
logger.debug("simlating -- game value:" + game.getState().getValue(true) + " test value:" + test.gameValue);
|
logger.trace("Sim getNextAction -- game value:" + game.getState().getValue(true) + " test value:" + test.gameValue);
|
||||||
if (!suggested.isEmpty()) {
|
if (!suggested.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +326,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int minimaxAB(SimulationNode2 node, int depth, int alpha, int beta) {
|
protected int minimaxAB(SimulationNode2 node, int depth, int alpha, int beta) {
|
||||||
logger.info("Simulating minimaxAB -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " node-score: " + (node != null ? node.getScore() : "null"));
|
logger.trace("Sim minimaxAB ["+depth+"] -- a: " + alpha + " b: " + beta + " <" + (node != null ? node.getScore() : "null")+">");
|
||||||
UUID currentPlayerId = node.getGame().getPlayerList().get();
|
UUID currentPlayerId = node.getGame().getPlayerList().get();
|
||||||
SimulationNode2 bestChild = null;
|
SimulationNode2 bestChild = null;
|
||||||
for (SimulationNode2 child : node.getChildren()) {
|
for (SimulationNode2 child : node.getChildren()) {
|
||||||
|
@ -400,7 +408,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
SimulationNode2 newNode = new SimulationNode2(node, sim, depth, ability.getControllerId());
|
SimulationNode2 newNode = new SimulationNode2(node, sim, depth, ability.getControllerId());
|
||||||
node.children.add(newNode);
|
node.children.add(newNode);
|
||||||
newNode.getTargets().add(targetId);
|
newNode.getTargets().add(targetId);
|
||||||
logger.debug("simulating search -- node#: " + SimulationNode2.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName());
|
logger.trace("Sim search -- node#: " + SimulationNode2.getCount() + " for player: " + sim.getPlayer(ability.getControllerId()).getName());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -532,24 +540,55 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
sim.getPlayerList().getNext();
|
sim.getPlayerList().getNext();
|
||||||
}
|
}
|
||||||
SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId());
|
SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId());
|
||||||
|
logger.trace(new StringBuilder("Sim Prio [").append(depth).append("]#").append(counter).append(" -- newNode (").append(action.toString()).append(") ").append(newNode.hashCode()).append(" parent node ").append(node.hashCode()));
|
||||||
// int testVal = GameStateEvaluator2.evaluate(currentPlayer.getId(), sim);
|
// int testVal = GameStateEvaluator2.evaluate(currentPlayer.getId(), sim);
|
||||||
|
|
||||||
sim.checkStateAndTriggered();
|
sim.checkStateAndTriggered();
|
||||||
int val = addActions(newNode, depth - 1, alpha, beta);
|
int val = addActions(newNode, depth - 1, alpha, beta);
|
||||||
|
|
||||||
if (logger.isInfoEnabled() && depth == maxDepth) {
|
if (logger.isInfoEnabled() && depth == maxDepth) {
|
||||||
StringBuilder sb = new StringBuilder("Sim Prio [").append(depth).append("] #").append(counter).append(" -- val = ").append(val).append(" (").append(action).append(")");
|
StringBuilder sb = new StringBuilder("Sim Prio [").append(depth).append("] #").append(counter)
|
||||||
|
.append(" <").append(val).append("> (").append(action)
|
||||||
|
.append(action.isModal() ? " Mode = "+action.getModes().getMode().toString():"")
|
||||||
|
.append(listTargets(game, action.getTargets())).append(")")
|
||||||
|
.append(logger.isTraceEnabled()?" #" +newNode.hashCode():"");
|
||||||
SimulationNode2 logNode = newNode;
|
SimulationNode2 logNode = newNode;
|
||||||
while (logNode.getChildren() != null && logNode.getChildren().size()>0) {
|
while (logNode.getChildren() != null && logNode.getChildren().size()>0) {
|
||||||
logNode = logNode.getChildren().get(0);
|
logNode = logNode.getChildren().get(0);
|
||||||
if (logNode.getAbilities() != null && logNode.getAbilities().size()>0) {
|
if (logNode.getAbilities() != null && logNode.getAbilities().size()>0) {
|
||||||
sb.append(" --> ").append(logNode.getAbilities().get(0).toString());
|
sb.append(" -> [").append(logNode.getDepth()).append("]").append(logNode.getAbilities().toString()).append("<").append(logNode.getScore()).append(">");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info(sb.toString());
|
logger.info(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentPlayer.getId().equals(playerId)) {
|
if (currentPlayer.getId().equals(playerId)) {
|
||||||
|
if (val > alpha) {
|
||||||
|
alpha = val;
|
||||||
|
bestNode = newNode;
|
||||||
|
bestNode.setScore(val);
|
||||||
|
if (newNode.getChildren().size() > 0) {
|
||||||
|
bestNode.setCombat(newNode.getChildren().get(0).getCombat());
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if (node.getTargets().size() > 0) targets =
|
||||||
|
* node.getTargets(); if (node.getChoices().size() > 0)
|
||||||
|
* choices = node.getChoices();
|
||||||
|
*/
|
||||||
|
if (depth == maxDepth) {
|
||||||
|
logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- Saved best node yet <").append(bestNode.getScore()).append("> ").append(bestNode.getAbilities().toString()).toString());
|
||||||
|
node.children.clear();
|
||||||
|
node.children.add(bestNode);
|
||||||
|
node.setScore(bestNode.getScore());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to check other actions
|
||||||
|
if (val == GameStateEvaluator2.WIN_GAME_SCORE) {
|
||||||
|
logger.debug("Sim Prio -- win - break");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (val < beta) {
|
if (val < beta) {
|
||||||
beta = val;
|
beta = val;
|
||||||
bestNode = newNode;
|
bestNode = newNode;
|
||||||
|
@ -564,32 +603,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
logger.debug("Sim Prio -- lose - break");
|
logger.debug("Sim Prio -- lose - break");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (val > alpha) {
|
|
||||||
alpha = val;
|
|
||||||
bestNode = newNode;
|
|
||||||
bestNode.setScore(val);
|
|
||||||
if (newNode.getChildren().size() > 0) {
|
|
||||||
bestNode.setCombat(newNode.getChildren().get(0).getCombat());
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* if (node.getTargets().size() > 0) targets =
|
|
||||||
* node.getTargets(); if (node.getChoices().size() > 0)
|
|
||||||
* choices = node.getChoices();
|
|
||||||
*/
|
|
||||||
if (depth == maxDepth) {
|
|
||||||
logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- Saved best node yet with score: ").append(bestNode.getScore()).append(" abilities: ").append(bestNode.getAbilities().toString()).toString());
|
|
||||||
node.children.clear();
|
|
||||||
node.children.add(bestNode);
|
|
||||||
node.setScore(bestNode.getScore());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no need to check other actions
|
|
||||||
if (val == GameStateEvaluator2.WIN_GAME_SCORE) {
|
|
||||||
logger.debug("Sim Prio -- win - break");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (alpha >= beta) {
|
if (alpha >= beta) {
|
||||||
//logger.info("Sim Prio -- pruning");
|
//logger.info("Sim Prio -- pruning");
|
||||||
|
@ -600,16 +613,16 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end for allActions
|
} // end of for (allActions)
|
||||||
if (depth == maxDepth) {
|
if (depth == maxDepth) {
|
||||||
logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- End for Max Depth").toString());
|
logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- End for Max Depth -- Nodes calculated: ").append(SimulationNode2.nodeCount));
|
||||||
}
|
}
|
||||||
if (bestNode != null) {
|
if (bestNode != null) {
|
||||||
node.children.clear();
|
node.children.clear();
|
||||||
node.children.add(bestNode);
|
node.children.add(bestNode);
|
||||||
node.setScore(bestNode.getScore());
|
node.setScore(bestNode.getScore());
|
||||||
if (logger.isTraceEnabled() && !bestNode.getAbilities().toString().equals("[Pass]") ) {
|
if (logger.isTraceEnabled() && !bestNode.getAbilities().toString().equals("[Pass]") ) {
|
||||||
logger.trace(new StringBuilder("Sim Prio [").append(depth).append("] -- Set after (depth=").append(depth).append(") Score: ").append(bestNode.getScore()).append(" abilities: ").append(bestNode.getAbilities().toString()).toString());
|
logger.trace(new StringBuilder("Sim Prio [").append(depth).append("] -- Set after (depth=").append(depth).append(") <").append(bestNode.getScore()).append("> ").append(bestNode.getAbilities().toString()).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,21 +746,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game) {
|
|
||||||
//SimulatedPlayer.simulateVariableCosts method adds a generic mana cost for each option
|
|
||||||
for (ManaCost manaCost : costs) {
|
|
||||||
if (manaCost instanceof GenericManaCost) {
|
|
||||||
cost.setPayment(manaCost.getPayment());
|
|
||||||
logger.debug("using X = " + cost.getPayment().count());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
game.informPlayers(getName() + " payed " + cost.getPayment().count() + " for " + cost.getText());
|
|
||||||
cost.setPaid();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playNext(Game game, UUID activePlayerId, SimulationNode2 node) {
|
public void playNext(Game game, UUID activePlayerId, SimulationNode2 node) {
|
||||||
boolean skip = false;
|
boolean skip = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -1288,7 +1286,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
Game sim = game.copy();
|
Game sim = game.copy();
|
||||||
for (Player copyPlayer : sim.getState().getPlayers().values()) {
|
for (Player copyPlayer : sim.getState().getPlayers().values()) {
|
||||||
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId()).copy();
|
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId()).copy();
|
||||||
|
if (!suggested.isEmpty()) {
|
||||||
logger.debug(origPlayer.getName() + " suggested: " + suggested);
|
logger.debug(origPlayer.getName() + " suggested: " + suggested);
|
||||||
|
}
|
||||||
SimulatedPlayer2 newPlayer = new SimulatedPlayer2(copyPlayer.getId(), copyPlayer.getId().equals(playerId), suggested);
|
SimulatedPlayer2 newPlayer = new SimulatedPlayer2(copyPlayer.getId(), copyPlayer.getId().equals(playerId), suggested);
|
||||||
newPlayer.restore(origPlayer);
|
newPlayer.restore(origPlayer);
|
||||||
sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer);
|
sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer);
|
||||||
|
@ -1297,7 +1297,8 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkForRepeatedAction(Game sim, SimulationNode2 node, Ability action, UUID playerId) {
|
private boolean checkForRepeatedAction(Game sim, SimulationNode2 node, Ability action, UUID playerId) {
|
||||||
if (action instanceof PassAbility) {
|
// pass or casting two times a spell multiple times on hand is ok
|
||||||
|
if (action instanceof PassAbility || action instanceof SpellAbility) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int newVal = GameStateEvaluator2.evaluate(playerId, sim);
|
int newVal = GameStateEvaluator2.evaluate(playerId, sim);
|
||||||
|
@ -1352,4 +1353,18 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
|
||||||
suggested.add(action.substring(5, action.length()));
|
suggested.add(action.substring(5, action.length()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String listTargets(Game game, Targets targets) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (targets != null) {
|
||||||
|
for (Target target: targets) {
|
||||||
|
sb.append("[").append(target.getTargetedName(game)).append("]");
|
||||||
|
}
|
||||||
|
if (sb.length()>0) {
|
||||||
|
sb.insert(0," targeting ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,12 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean priority(Game game) {
|
public boolean priority(Game game) {
|
||||||
|
if (lastLoggedTurn != game.getTurnNum()) {
|
||||||
|
lastLoggedTurn = game.getTurnNum();
|
||||||
|
logger.info(new StringBuilder("------------------------ ").append("Turn: ").append(game.getTurnNum()).append(" [").append(game.getPlayer(game.getActivePlayerId()).getName()).append("----------------------------------------------------").toString());
|
||||||
|
}
|
||||||
logState(game);
|
logState(game);
|
||||||
logger.debug("Game State: Turn-" + game.getTurnNum() + " Step-" + game.getTurn().getStepType() + " ActivePlayer-" + game.getPlayer(game.getActivePlayerId()).getName() + " PriorityPlayer-" + name);
|
logger.debug("Priority -- Step: " + (game.getTurn().getStepType() + " ").substring(0,25) + " ActivePlayer-" + game.getPlayer(game.getActivePlayerId()).getName() + " PriorityPlayer-" + name);
|
||||||
game.getState().setPriorityPlayerId(playerId);
|
game.getState().setPriorityPlayerId(playerId);
|
||||||
game.firePriorityEvent(playerId);
|
game.firePriorityEvent(playerId);
|
||||||
switch (game.getTurn().getStepType()) {
|
switch (game.getTurn().getStepType()) {
|
||||||
|
@ -77,8 +81,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
return false;
|
return false;
|
||||||
case PRECOMBAT_MAIN:
|
case PRECOMBAT_MAIN:
|
||||||
if (game.getActivePlayerId().equals(playerId)) {
|
if (game.getActivePlayerId().equals(playerId)) {
|
||||||
printOutState(game, playerId);
|
printOutState(game);
|
||||||
printOutState(game, game.getOpponents(playerId).iterator().next());
|
|
||||||
if (actions.size() == 0) {
|
if (actions.size() == 0) {
|
||||||
calculatePreCombatActions(game);
|
calculatePreCombatActions(game);
|
||||||
}
|
}
|
||||||
|
@ -94,8 +97,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
return false;
|
return false;
|
||||||
case DECLARE_ATTACKERS:
|
case DECLARE_ATTACKERS:
|
||||||
if (!game.getActivePlayerId().equals(playerId)) {
|
if (!game.getActivePlayerId().equals(playerId)) {
|
||||||
printOutState(game, playerId);
|
printOutState(game);
|
||||||
printOutState(game, game.getOpponents(playerId).iterator().next());
|
|
||||||
if (actions.size() == 0) {
|
if (actions.size() == 0) {
|
||||||
calculatePreCombatActions(game);
|
calculatePreCombatActions(game);
|
||||||
}
|
}
|
||||||
|
@ -113,19 +115,18 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
pass();
|
pass();
|
||||||
return false;
|
return false;
|
||||||
case POSTCOMBAT_MAIN:
|
case POSTCOMBAT_MAIN:
|
||||||
if (game.getActivePlayerId().equals(playerId)) {
|
// if (game.getActivePlayerId().equals(playerId)) {
|
||||||
printOutState(game, playerId);
|
printOutState(game);
|
||||||
printOutState(game, game.getOpponents(playerId).iterator().next());
|
|
||||||
if (actions.size() == 0) {
|
if (actions.size() == 0) {
|
||||||
calculatePostCombatActions(game);
|
calculatePostCombatActions(game);
|
||||||
}
|
}
|
||||||
act(game);
|
act(game);
|
||||||
return true;
|
return true;
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
pass();
|
// pass();
|
||||||
}
|
// }
|
||||||
return false;
|
// return false;
|
||||||
case END_TURN:
|
case END_TURN:
|
||||||
case CLEANUP:
|
case CLEANUP:
|
||||||
actionCache.clear();
|
actionCache.clear();
|
||||||
|
@ -172,13 +173,12 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
if (root.children.size() > 0) {
|
if (root.children.size() > 0) {
|
||||||
root = root.children.get(0);
|
root = root.children.get(0);
|
||||||
int bestScore = root.getScore();
|
int bestScore = root.getScore();
|
||||||
//if (bestScore > currentScore || allowBadMoves) {
|
if (bestScore > currentScore || allowBadMoves) {
|
||||||
actions = new LinkedList<Ability>(root.abilities);
|
actions = new LinkedList<Ability>(root.abilities);
|
||||||
combat = root.combat;
|
combat = root.combat;
|
||||||
logger.debug("final score: " + bestScore);
|
} else {
|
||||||
//} else {
|
logger.debug("[" + game.getPlayer(playerId).getName() + "] no better score current: " + currentScore + " bestScore: " + bestScore );
|
||||||
//System.out.println("[" + game.getPlayer(playerId).getName() + "][post] Action: not better score");
|
}
|
||||||
//}
|
|
||||||
} else {
|
} else {
|
||||||
logger.debug("[" + game.getPlayer(playerId).getName() + "][post] Action: skip");
|
logger.debug("[" + game.getPlayer(playerId).getName() + "][post] Action: skip");
|
||||||
}
|
}
|
||||||
|
@ -198,21 +198,30 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
logger.debug("interrupted");
|
logger.debug("interrupted");
|
||||||
return GameStateEvaluator2.evaluate(playerId, game);
|
return GameStateEvaluator2.evaluate(playerId, game);
|
||||||
}
|
}
|
||||||
|
// Condition to stop deeper simulation
|
||||||
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) {
|
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) {
|
||||||
val = GameStateEvaluator2.evaluate(playerId, game);
|
val = GameStateEvaluator2.evaluate(playerId, game);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
StringBuilder sb = new StringBuilder("Add Action [").append(depth).append("] -- reached end state val = ").append(val);
|
StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append(">");
|
||||||
SimulationNode2 logNode = node;
|
SimulationNode2 logNode = node;
|
||||||
StringBuilder sb2 = new StringBuilder(" --> ").append(node.getAbilities().get(0).toString());
|
do {
|
||||||
while(logNode.getParent() != null) {
|
sb.append(new StringBuilder(" <- ["+logNode.getDepth()+"]" + (logNode.getAbilities() != null ? logNode.getAbilities().toString():"[empty]")));
|
||||||
logNode = logNode.getParent();
|
logNode = logNode.getParent();
|
||||||
sb2.insert(0,"["+node.getDepth()+"] s:" + logNode.score).insert(0," (0/"+node.getAbilities().size()+" " + node.getAbilities().get(0).toString()).insert(0, ") --> ");
|
} while((logNode.getParent() != null));
|
||||||
|
logger.trace(sb);
|
||||||
}
|
}
|
||||||
logger.debug(sb.append(sb2));
|
} else if (node.getChildren().size() > 0) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
StringBuilder sb = new StringBuilder("Add Action [").append(depth)
|
||||||
|
.append("] -- something added children ")
|
||||||
|
.append(node.getAbilities() != null ? node.getAbilities().toString():"null")
|
||||||
|
.append(" added children: ").append(node.getChildren().size()).append(" (");
|
||||||
|
for (SimulationNode2 logNode: node.getChildren()) {
|
||||||
|
sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString():"null").append(", ");
|
||||||
}
|
}
|
||||||
|
sb.append(")");
|
||||||
|
logger.debug(sb);
|
||||||
}
|
}
|
||||||
else if (node.getChildren().size() > 0) {
|
|
||||||
logger.debug("Add Action -- something added children:" + node.getChildren().size());
|
|
||||||
val = minimaxAB(node, depth-1, alpha, beta);
|
val = minimaxAB(node, depth-1, alpha, beta);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -263,14 +272,25 @@ public class ComputerPlayer7 extends ComputerPlayer6 implements Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node.getChildren().size() > 0) {
|
else if (node.getChildren().size() > 0) {
|
||||||
logger.debug("Add Action -- trigger added children:" + node.getChildren().size());
|
if (logger.isDebugEnabled()) {
|
||||||
|
StringBuilder sb = new StringBuilder("Add Action [").append(depth)
|
||||||
|
.append("] -- trigger ")
|
||||||
|
.append(node.getAbilities() != null ? node.getAbilities().toString():"null")
|
||||||
|
.append(" added children: ").append(node.getChildren().size()).append(" (");
|
||||||
|
for (SimulationNode2 logNode: node.getChildren()) {
|
||||||
|
sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString():"null").append(", ");
|
||||||
|
}
|
||||||
|
sb.append(")");
|
||||||
|
logger.debug(sb);
|
||||||
|
}
|
||||||
|
|
||||||
val = minimaxAB(node, depth, alpha, beta);
|
val = minimaxAB(node, depth, alpha, beta);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val = simulatePriority(node, game, depth, alpha, beta);
|
val = simulatePriority(node, game, depth, alpha, beta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
node.setScore(val); // test
|
||||||
logger.trace("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
logger.trace("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class Config2 {
|
||||||
p.load(new FileInputStream(propertiesFile));
|
p.load(new FileInputStream(propertiesFile));
|
||||||
} else {
|
} else {
|
||||||
// p.setProperty("maxDepth", "10");
|
// p.setProperty("maxDepth", "10");
|
||||||
p.setProperty("maxNodes", "5000");
|
p.setProperty("maxNodes", "50000");
|
||||||
p.setProperty("evaluatorLifeFactor", "2");
|
p.setProperty("evaluatorLifeFactor", "2");
|
||||||
p.setProperty("evaluatorPermanentFactor", "1");
|
p.setProperty("evaluatorPermanentFactor", "1");
|
||||||
p.setProperty("evaluatorCreatureFactor", "1");
|
p.setProperty("evaluatorCreatureFactor", "1");
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
package mage.player.ai;
|
package mage.player.ai;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.TriggeredAbility;
|
import mage.abilities.TriggeredAbility;
|
||||||
import mage.abilities.common.PassAbility;
|
import mage.abilities.common.PassAbility;
|
||||||
|
@ -47,8 +50,6 @@ import mage.players.Player;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -123,23 +124,13 @@ public class SimulatedPlayer2 extends ComputerPlayer<SimulatedPlayer2> {
|
||||||
options = filterOptions(game, options, ability, suggested);
|
options = filterOptions(game, options, ability, suggested);
|
||||||
options = optimizeOptions(game, options, ability);
|
options = optimizeOptions(game, options, ability);
|
||||||
if (options.isEmpty()) {
|
if (options.isEmpty()) {
|
||||||
if (ability.getManaCosts().getVariableCosts().size() > 0) {
|
|
||||||
simulateVariableCosts(ability, game);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
allActions.add(ability);
|
allActions.add(ability);
|
||||||
}
|
|
||||||
// simulateAction(game, previousActions, ability);
|
// simulateAction(game, previousActions, ability);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// ExecutorService simulationExecutor = Executors.newFixedThreadPool(4);
|
// ExecutorService simulationExecutor = Executors.newFixedThreadPool(4);
|
||||||
for (Ability option: options) {
|
for (Ability option: options) {
|
||||||
if (ability.getManaCosts().getVariableCosts().size() > 0) {
|
|
||||||
simulateVariableCosts(option, game);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
allActions.add(option);
|
allActions.add(option);
|
||||||
}
|
|
||||||
// SimulationWorker worker = new SimulationWorker(game, this, previousActions, option);
|
// SimulationWorker worker = new SimulationWorker(game, this, previousActions, option);
|
||||||
// simulationExecutor.submit(worker);
|
// simulationExecutor.submit(worker);
|
||||||
}
|
}
|
||||||
|
@ -149,6 +140,53 @@ public class SimulatedPlayer2 extends ComputerPlayer<SimulatedPlayer2> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addVariableXOptions(List<Ability> options, Ability ability, int targetNum, Game game) {
|
||||||
|
// calculate the mana that can be used for the x part
|
||||||
|
int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost();
|
||||||
|
|
||||||
|
Card card = game.getCard(ability.getSourceId());
|
||||||
|
if (card != null && numAvailable > 0) {
|
||||||
|
// check if variable mana costs is included and get the multiplier
|
||||||
|
VariableManaCost variableManaCost = null;
|
||||||
|
for (ManaCost cost: ability.getManaCostsToPay()) {
|
||||||
|
if (cost instanceof VariableManaCost && !cost.isPaid()) {
|
||||||
|
variableManaCost = (VariableManaCost) cost;
|
||||||
|
break; // only one VariableManCost per spell (or is it possible to have more?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (variableManaCost != null) {
|
||||||
|
int multiplier = variableManaCost.getMultiplier();
|
||||||
|
|
||||||
|
for (int mana = 0; mana <= numAvailable; mana++) {
|
||||||
|
if (mana % multiplier == 0) { // use only values dependant from muliplier
|
||||||
|
int xAmount = mana / multiplier;
|
||||||
|
Ability newAbility = ability.copy();
|
||||||
|
VariableManaCost varCost = null;
|
||||||
|
for (ManaCost cost: newAbility.getManaCostsToPay()) {
|
||||||
|
if (cost instanceof VariableManaCost && !cost.isPaid()) {
|
||||||
|
varCost = (VariableManaCost) cost;
|
||||||
|
break; // only one VariableManCost per spell (or is it possible to have more?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add the specific value for x
|
||||||
|
newAbility.getManaCostsToPay().add(new ManaCostsImpl(new StringBuilder("{").append(xAmount).append("}").toString()));
|
||||||
|
newAbility.getManaCostsToPay().setX(xAmount);
|
||||||
|
varCost.setPaid();
|
||||||
|
card.adjustTargets(newAbility, game);
|
||||||
|
// add the different possible target option for the specific X value
|
||||||
|
if (newAbility.getTargets().getUnchosen().size() > 0) {
|
||||||
|
addTargetOptions(options, newAbility, targetNum, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// protected void simulateAction(Game game, SimulatedAction previousActions, Ability action) {
|
// protected void simulateAction(Game game, SimulatedAction previousActions, Ability action) {
|
||||||
// List<Ability> actions = new ArrayList<Ability>(previousActions.getAbilities());
|
// List<Ability> actions = new ArrayList<Ability>(previousActions.getAbilities());
|
||||||
// actions.add(action);
|
// actions.add(action);
|
||||||
|
@ -160,6 +198,14 @@ public class SimulatedPlayer2 extends ComputerPlayer<SimulatedPlayer2> {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if suggested abilities exist, return only those from playables
|
||||||
|
*
|
||||||
|
* @param game
|
||||||
|
* @param playables
|
||||||
|
* @param suggested
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
protected List<Ability> filterAbilities(Game game, List<Ability> playables, List<String> suggested) {
|
protected List<Ability> filterAbilities(Game game, List<Ability> playables, List<String> suggested) {
|
||||||
if (playables.isEmpty()) {
|
if (playables.isEmpty()) {
|
||||||
return playables;
|
return playables;
|
||||||
|
@ -258,31 +304,6 @@ public class SimulatedPlayer2 extends ComputerPlayer<SimulatedPlayer2> {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
//add a generic mana cost for each amount possible
|
|
||||||
protected void simulateVariableCosts(Ability ability, Game game) {
|
|
||||||
int numAvailable = getAvailableManaProducers(game).size();
|
|
||||||
// Start with X = {1}
|
|
||||||
for (int i = 1; i < numAvailable; i++) {
|
|
||||||
Ability newAbility = ability.copy();
|
|
||||||
newAbility.getManaCostsToPay().add(new GenericManaCost(i));
|
|
||||||
allActions.add(newAbility);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game) {
|
|
||||||
//simulateVariableCosts method adds a generic mana cost for each option
|
|
||||||
for (ManaCost manaCost: costs) {
|
|
||||||
if (manaCost instanceof GenericManaCost) {
|
|
||||||
cost.setPayment(manaCost.getPayment());
|
|
||||||
logger.debug("simulating -- X = " + cost.getPayment().count());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cost.setPaid();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Combat> addAttackers(Game game) {
|
public List<Combat> addAttackers(Game game) {
|
||||||
Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
|
Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
|
||||||
//useful only for two player games - will only attack first opponent
|
//useful only for two player games - will only attack first opponent
|
||||||
|
@ -401,4 +422,6 @@ public class SimulatedPlayer2 extends ComputerPlayer<SimulatedPlayer2> {
|
||||||
//should never get here
|
//should never get here
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1043,23 +1043,14 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game) {
|
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||||
log.debug("playXMana");
|
log.debug("announceXMana");
|
||||||
//put everything into X
|
//TODO: improve this
|
||||||
for (Permanent perm: this.getAvailableManaProducers(game)) {
|
int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost();
|
||||||
for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) {
|
if (numAvailable < 0) {
|
||||||
activateAbility(ability, game);
|
numAvailable = 0;
|
||||||
}
|
}
|
||||||
}
|
return numAvailable;
|
||||||
|
|
||||||
// don't allow X=0
|
|
||||||
if (getManaPool().count() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
game.informPlayers(getName() + " payed " + cost.getPayment().count() + " for " + cost.getText());
|
|
||||||
cost.setPaid();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1262,13 +1253,17 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
|
||||||
@Override
|
@Override
|
||||||
public Mode chooseMode(Modes modes, Ability source, Game game) {
|
public Mode chooseMode(Modes modes, Ability source, Game game) {
|
||||||
log.debug("chooseMode");
|
log.debug("chooseMode");
|
||||||
|
if (modes.getMode() != null) {
|
||||||
|
// mode was already set by the AI
|
||||||
|
return modes.getMode();
|
||||||
|
}
|
||||||
//TODO: improve this;
|
//TODO: improve this;
|
||||||
return modes.values().iterator().next();
|
return modes.values().iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game) {
|
public TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game) {
|
||||||
log.debug("chooseTriggeredAbility");
|
log.debug("chooseTriggeredAbility: " + abilities.toString());
|
||||||
//TODO: improve this
|
//TODO: improve this
|
||||||
if (abilities.size() > 0) {
|
if (abilities.size() > 0) {
|
||||||
return abilities.get(0);
|
return abilities.get(0);
|
||||||
|
|
|
@ -472,20 +472,20 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the amount of mana the player want to spent for a x spell
|
||||||
|
* @param min
|
||||||
|
* @param max
|
||||||
|
* @param message
|
||||||
|
* @param game
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game) {
|
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||||
updateGameStatePriority("playXMana", game);
|
updateGameStatePriority("announceXMana", game);
|
||||||
game.firePlayXManaEvent(playerId, "Pay {X}: {X}=" + cost.getAmount());
|
game.fireGetAmountEvent(playerId, message, min, max);
|
||||||
waitForResponse();
|
waitForIntegerResponse();
|
||||||
if (response.getBoolean() != null) {
|
return response.getInteger();
|
||||||
if (!response.getBoolean())
|
|
||||||
return false;
|
|
||||||
game.informPlayers(getName() + " payed " + cost.getPayment().count() + " for " + cost.getText());
|
|
||||||
cost.setPaid();
|
|
||||||
} else if (response.getUUID() != null) {
|
|
||||||
playManaAbilities(game);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void playManaAbilities(Game game) {
|
protected void playManaAbilities(Game game) {
|
||||||
|
|
|
@ -362,24 +362,6 @@ public class RandomPlayer extends ComputerPlayer<RandomPlayer> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game) {
|
|
||||||
for (Permanent perm: this.getAvailableManaProducers(game)) {
|
|
||||||
for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) {
|
|
||||||
if (rnd.nextBoolean())
|
|
||||||
activateAbility(ability, game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't allow X=0
|
|
||||||
if (getManaPool().count() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cost.setPaid();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int chooseEffect(List<ReplacementEffect> rEffects, Game game) {
|
public int chooseEffect(List<ReplacementEffect> rEffects, Game game) {
|
||||||
return rnd.nextInt(rEffects.size());
|
return rnd.nextInt(rEffects.size());
|
||||||
|
|
|
@ -191,23 +191,26 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
||||||
// If the spell has a variable cost that will be paid as it's being cast (such as an {X} in
|
// If the spell has a variable cost that will be paid as it's being cast (such as an {X} in
|
||||||
// its mana cost; see rule 107.3), the player announces the value of that variable.
|
// its mana cost; see rule 107.3), the player announces the value of that variable.
|
||||||
// TODO: Handle announcing other variable costs here like: RemoveVariableCountersSourceCost
|
// TODO: Handle announcing other variable costs here like: RemoveVariableCountersSourceCost
|
||||||
if (game.getPlayer(this.controllerId).isHuman()) {
|
|
||||||
// AI can't handle this yet. Uses old way of playXMana
|
|
||||||
VariableManaCost variableManaCost = null;
|
VariableManaCost variableManaCost = null;
|
||||||
for (ManaCost cost: manaCostsToPay) {
|
for (ManaCost cost: manaCostsToPay) {
|
||||||
if (cost instanceof VariableManaCost && !cost.isPaid()) {
|
if (cost instanceof VariableManaCost) {
|
||||||
variableManaCost = (VariableManaCost) cost;
|
variableManaCost = (VariableManaCost) cost;
|
||||||
break; // only one VariableManCost per spell (or is it possible to have more?)
|
break; // only one VariableManCost per spell (or is it possible to have more?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (variableManaCost != null) {
|
if (variableManaCost != null) {
|
||||||
int amount = game.getPlayer(this.controllerId).getAmount(variableManaCost.getMinX(), Integer.MAX_VALUE, "Announce the value for " + variableManaCost.getText(), game);
|
int xValue;
|
||||||
game.informPlayers(new StringBuilder(game.getPlayer(this.controllerId).getName()).append(" announced a value of ").append(amount).append(" for ").append(variableManaCost.getText()).toString());
|
if (!variableManaCost.isPaid()) { // should only happen for human players
|
||||||
amount *= variableManaCost.getMultiplier();
|
if (!noMana) {
|
||||||
manaCostsToPay.add(new ManaCostsImpl(new StringBuilder("{").append(amount).append("}").toString()));
|
xValue = game.getPlayer(this.controllerId).announceXMana(variableManaCost.getMinX(), Integer.MAX_VALUE, "Announce the value for " + variableManaCost.getText(), game, this);
|
||||||
manaCostsToPay.setX(amount);
|
int amountMana = xValue * variableManaCost.getMultiplier();
|
||||||
|
manaCostsToPay.add(new ManaCostsImpl(new StringBuilder("{").append(amountMana).append("}").toString()));
|
||||||
|
manaCostsToPay.setX(amountMana);
|
||||||
|
}
|
||||||
variableManaCost.setPaid();
|
variableManaCost.setPaid();
|
||||||
}
|
}
|
||||||
|
xValue = getManaCostsToPay().getX();
|
||||||
|
game.informPlayers(new StringBuilder(game.getPlayer(this.controllerId).getName()).append(" announced a value of ").append(xValue).append(" for ").append(variableManaCost.getText()).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//20121001 - 601.2c
|
//20121001 - 601.2c
|
||||||
|
@ -230,7 +233,11 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
|
||||||
card.adjustTargets(this, game);
|
card.adjustTargets(this, game);
|
||||||
}
|
}
|
||||||
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
|
if (getTargets().size() > 0 && getTargets().chooseTargets(getEffects().get(0).getOutcome(), this.controllerId, this, game) == false) {
|
||||||
|
if (variableManaCost != null) {
|
||||||
|
game.informPlayers(new StringBuilder(card.getName()).append(": no valid targets with this value of X").toString());
|
||||||
|
} else {
|
||||||
logger.debug("activate failed - target");
|
logger.debug("activate failed - target");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,15 +120,16 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (ManaCost cost : this.getUnpaidVariableCosts()) {
|
// no more needed because X costs are added to the cost during announcing of the X costs
|
||||||
VariableManaCost vCost = (VariableManaCost) cost;
|
// for (ManaCost cost : this.getUnpaidVariableCosts()) {
|
||||||
while (!vCost.isPaid()) {
|
// VariableManaCost vCost = (VariableManaCost) cost;
|
||||||
if (player.playXMana(vCost, (ManaCosts<ManaCost>) this, game))
|
// while (!vCost.isPaid()) {
|
||||||
vCost.assignPayment(game, ability, player.getManaPool());
|
// if (player.playXMana(vCost, (ManaCosts<ManaCost>) this, game))
|
||||||
else
|
// vCost.assignPayment(game, ability, player.getManaPool());
|
||||||
return false;
|
// else
|
||||||
}
|
// return false;
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,9 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
boolean choose(Outcome outcome, Choice choice, Game game);
|
boolean choose(Outcome outcome, Choice choice, Game game);
|
||||||
boolean choosePile(Outcome outcome, String message, List<? extends Card> pile1, List<? extends Card> pile2, Game game);
|
boolean choosePile(Outcome outcome, String message, List<? extends Card> pile1, List<? extends Card> pile2, Game game);
|
||||||
boolean playMana(ManaCost unpaid, Game game);
|
boolean playMana(ManaCost unpaid, Game game);
|
||||||
boolean playXMana(VariableManaCost cost, ManaCosts<ManaCost> costs, Game game);
|
// set the value for X spells and abilities
|
||||||
|
int announceXMana(int min, int max, String message, Game game, Ability ability);
|
||||||
|
|
||||||
int chooseEffect(List<ReplacementEffect> rEffects, Game game);
|
int chooseEffect(List<ReplacementEffect> rEffects, Game game);
|
||||||
TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game);
|
TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game);
|
||||||
Mode chooseMode(Modes modes, Ability source, Game game);
|
Mode chooseMode(Modes modes, Ability source, Game game);
|
||||||
|
|
|
@ -1387,6 +1387,13 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
return playable;
|
return playable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only used for AIs
|
||||||
|
*
|
||||||
|
* @param ability
|
||||||
|
* @param game
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Ability> getPlayableOptions(Ability ability, Game game) {
|
public List<Ability> getPlayableOptions(Ability ability, Game game) {
|
||||||
List<Ability> options = new ArrayList<Ability>();
|
List<Ability> options = new ArrayList<Ability>();
|
||||||
|
@ -1394,7 +1401,12 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
if (ability.isModal()) {
|
if (ability.isModal()) {
|
||||||
addModeOptions(options, ability, game);
|
addModeOptions(options, ability, game);
|
||||||
} else if (ability.getTargets().getUnchosen().size() > 0) {
|
} else if (ability.getTargets().getUnchosen().size() > 0) {
|
||||||
|
// TODO: Handle other variable costs than mana costs
|
||||||
|
if (ability.getManaCosts().getVariableCosts().size() > 0) {
|
||||||
|
addVariableXOptions(options, ability, 0, game);
|
||||||
|
} else {
|
||||||
addTargetOptions(options, ability, 0, game);
|
addTargetOptions(options, ability, 0, game);
|
||||||
|
}
|
||||||
} else if (ability.getChoices().getUnchosen().size() > 0) {
|
} else if (ability.getChoices().getUnchosen().size() > 0) {
|
||||||
addChoiceOptions(options, ability, 0, game);
|
addChoiceOptions(options, ability, 0, game);
|
||||||
} else if (ability.getCosts().getTargets().getUnchosen().size() > 0) {
|
} else if (ability.getCosts().getTargets().getUnchosen().size() > 0) {
|
||||||
|
@ -1408,19 +1420,27 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
for (Mode mode: option.getModes().values()) {
|
for (Mode mode: option.getModes().values()) {
|
||||||
Ability newOption = option.copy();
|
Ability newOption = option.copy();
|
||||||
newOption.getModes().setMode(mode);
|
newOption.getModes().setMode(mode);
|
||||||
if (option.getTargets().getUnchosen().size() > 0) {
|
if (newOption.getTargets().getUnchosen().size() > 0) {
|
||||||
addTargetOptions(options, option, 0, game);
|
if (newOption.getManaCosts().getVariableCosts().size() > 0) {
|
||||||
} else if (option.getChoices().getUnchosen().size() > 0) {
|
addVariableXOptions(options, newOption, 0, game);
|
||||||
addChoiceOptions(options, option, 0, game);
|
} else {
|
||||||
} else if (option.getCosts().getTargets().getUnchosen().size() > 0) {
|
addTargetOptions(options, newOption, 0, game);
|
||||||
addCostTargetOptions(options, option, 0, game);
|
}
|
||||||
|
} else if (newOption.getChoices().getUnchosen().size() > 0) {
|
||||||
|
addChoiceOptions(options, newOption, 0, game);
|
||||||
|
} else if (newOption.getCosts().getTargets().getUnchosen().size() > 0) {
|
||||||
|
addCostTargetOptions(options, newOption, 0, game);
|
||||||
} else {
|
} else {
|
||||||
options.add(newOption);
|
options.add(newOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTargetOptions(List<Ability> options, Ability option, int targetNum, Game game) {
|
protected void addVariableXOptions(List<Ability> options, Ability option, int targetNum, Game game) {
|
||||||
|
addTargetOptions(options, option, targetNum, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addTargetOptions(List<Ability> options, Ability option, int targetNum, Game game) {
|
||||||
for (Target target: option.getTargets().getUnchosen().get(targetNum).getTargetOptions(option, game)) {
|
for (Target target: option.getTargets().getUnchosen().get(targetNum).getTargetOptions(option, game)) {
|
||||||
Ability newOption = option.copy();
|
Ability newOption = option.copy();
|
||||||
if (target instanceof TargetAmount) {
|
if (target instanceof TargetAmount) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue