diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsList.form b/Mage.Client/src/main/java/mage/client/cards/CardsList.form index 38981bdff1..85696ffe74 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsList.form +++ b/Mage.Client/src/main/java/mage/client/cards/CardsList.form @@ -27,7 +27,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -57,13 +57,13 @@ - + - - - - - + + + + + diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsList.java b/Mage.Client/src/main/java/mage/client/cards/CardsList.java index 60556eafef..413b1b5201 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsList.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardsList.java @@ -200,13 +200,13 @@ public class CardsList extends javax.swing.JPanel implements MouseListener { jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addComponent(lblCount, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblCount, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lblCreatureCount, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblCreatureCount, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lblLandCount) + .addComponent(lblLandCount, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(cbSortBy, javax.swing.GroupLayout.PREFERRED_SIZE, 338, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(cbSortBy, 0, 353, Short.MAX_VALUE)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -222,14 +222,14 @@ public class CardsList extends javax.swing.JPanel implements MouseListener { layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 553, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 639, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 397, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index c7b14f1288..e489b8ebb9 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -15,11 +15,22 @@ Mage Player AI + + log4j + log4j + 1.2.14 + jar + ${project.groupId} Mage ${project.version} + + ${project.groupId} + Mage-Sets + ${project.version} + diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 399f7348d5..f9237e902a 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -33,11 +33,10 @@ import java.io.IOException; import java.io.Serializable; import java.util.*; import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.Constants; import mage.Constants.CardType; +import mage.Constants.ColoredManaSymbol; import mage.Constants.Outcome; import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; @@ -83,6 +82,7 @@ import mage.game.tournament.Tournament; import mage.player.ai.utils.RateCard; import mage.players.Player; import mage.players.PlayerImpl; +import mage.sets.Sets; import mage.target.Target; import mage.target.TargetAmount; import mage.target.TargetCard; @@ -93,8 +93,8 @@ import mage.target.common.TargetDiscard; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreatureOrPlayerAmount; import mage.util.Copier; -import mage.util.Logging; import mage.util.TreeNode; +import org.apache.log4j.Logger; /** * @@ -104,7 +104,7 @@ import mage.util.TreeNode; */ public class ComputerPlayer> extends PlayerImpl implements Player { - private final static transient Logger logger = Logging.getLogger(ComputerPlayer.class.getName()); + private final static transient Logger logger = Logger.getLogger(ComputerPlayer.class); private transient Map unplayable = new TreeMap(); private transient List playableNonInstant = new ArrayList(); private transient List playableInstant = new ArrayList(); @@ -127,7 +127,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean chooseMulligan(Game game) { - logger.fine("chooseMulligan"); + logger.debug("chooseMulligan"); if (hand.size() < 6) return false; Set lands = hand.getCards(new FilterLandCard(), game); @@ -143,8 +143,8 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean choose(Outcome outcome, Target target, Game game, Map options) { - if (logger.isLoggable(Level.FINE)) - logger.fine("chooseTarget: " + outcome.toString() + ":" + target.toString()); + if (logger.isDebugEnabled()) + logger.debug("chooseTarget: " + outcome.toString() + ":" + target.toString()); UUID opponentId = game.getOpponents(playerId).iterator().next(); if (target instanceof TargetPlayer) { if (outcome.isGood()) { @@ -209,8 +209,8 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { - if (logger.isLoggable(Level.FINE)) - logger.fine("chooseTarget: " + outcome.toString() + ":" + target.toString()); + if (logger.isDebugEnabled()) + logger.debug("chooseTarget: " + outcome.toString() + ":" + target.toString()); UUID opponentId = game.getOpponents(playerId).iterator().next(); if (target instanceof TargetPlayer) { if (outcome.isGood()) { @@ -303,8 +303,8 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { - if (logger.isLoggable(Level.FINE)) - logger.fine("chooseTarget: " + outcome.toString() + ":" + target.toString()); + if (logger.isDebugEnabled()) + logger.debug("chooseTarget: " + outcome.toString() + ":" + target.toString()); UUID opponentId = game.getOpponents(playerId).iterator().next(); if (target instanceof TargetCreatureOrPlayerAmount) { if (game.getPlayer(opponentId).getLife() <= target.getAmountRemaining()) { @@ -332,7 +332,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public void priority(Game game) { - logger.fine("priority"); + logger.debug("priority"); UUID opponentId = game.getOpponents(playerId).iterator().next(); if (game.getActivePlayerId().equals(playerId)) { if (game.isMainPhase() && game.getStack().isEmpty()) { @@ -418,7 +418,7 @@ public class ComputerPlayer> extends PlayerImpl i } protected void playLand(Game game) { - logger.fine("playLand"); + logger.debug("playLand"); Set lands = hand.getCards(new FilterLandCard(), game); while (lands.size() > 0 && this.landsPlayed < this.landsPerTurn) { if (lands.size() == 1) @@ -430,7 +430,7 @@ public class ComputerPlayer> extends PlayerImpl i } protected void playALand(Set lands, Game game) { - logger.fine("playALand"); + logger.debug("playALand"); //play a land that will allow us to play an unplayable for (Mana mana: unplayable.keySet()) { for (Card card: lands) { @@ -538,19 +538,19 @@ public class ComputerPlayer> extends PlayerImpl i } } } - if (logger.isLoggable(Level.FINE)) - logger.fine("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() ); + if (logger.isDebugEnabled()) + logger.debug("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() ); } @Override protected ManaOptions getManaAvailable(Game game) { -// logger.fine("getManaAvailable"); +// logger.debug("getManaAvailable"); return super.getManaAvailable(game); } @Override public boolean playMana(ManaCost unpaid, Game game) { -// logger.fine("playMana"); +// logger.debug("playMana"); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { @@ -627,8 +627,14 @@ public class ComputerPlayer> extends PlayerImpl i } } } - if (score > 0) // score mana producers that produce other types higher + if (score > 0) { // score mana producers that produce other mana types and have other uses higher score += permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD).size(); + score += permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD).size(); + if (!permanent.getCardType().contains(CardType.LAND)) + score+=2; + else if(permanent.getCardType().contains(CardType.CREATURE)) + score+=2; + } scored.put(permanent, score); } return sortByValue(scored); @@ -652,7 +658,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean playXMana(VariableManaCost cost, Game game) { - logger.fine("playXMana"); + logger.debug("playXMana"); //put everything into X for (Permanent perm: this.getAvailableManaProducers(game)) { for (ManaAbility ability: perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { @@ -671,14 +677,14 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean chooseUse(Outcome outcome, String message, Game game) { - logger.fine("chooseUse"); + logger.debug("chooseUse"); //TODO: improve this return outcome.isGood(); } @Override public boolean choose(Outcome outcome, Choice choice, Game game) { - logger.fine("choose"); + logger.debug("choose"); //TODO: improve this choice.setChoice(choice.getChoices().iterator().next()); return true; @@ -686,7 +692,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean chooseTarget(Cards cards, TargetCard target, Ability source, Game game) { - logger.fine("chooseTarget"); + logger.debug("chooseTarget"); //TODO: improve this //return first match if (!target.doneChosing()) { @@ -702,7 +708,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public boolean choose(Cards cards, TargetCard target, Game game) { - logger.fine("choose"); + logger.debug("choose"); //TODO: improve this //return first match if (!target.doneChosing()) { @@ -718,7 +724,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public void selectAttackers(Game game) { - logger.fine("selectAttackers"); + logger.debug("selectAttackers"); UUID opponentId = game.getCombat().getDefenders().iterator().next(); Attackers attackers = getPotentialAttackers(game); List blockers = getOpponentBlockers(opponentId, game); @@ -745,7 +751,7 @@ public class ComputerPlayer> extends PlayerImpl i @Override public void selectBlockers(Game game) { - logger.fine("selectBlockers"); + logger.debug("selectBlockers"); List blockers = getAvailableBlockers(game); @@ -761,14 +767,14 @@ public class ComputerPlayer> extends PlayerImpl i @Override public int chooseEffect(List rEffects, Game game) { - logger.fine("chooseEffect"); + logger.debug("chooseEffect"); //TODO: implement this return 0; } @Override public TriggeredAbility chooseTriggeredAbility(TriggeredAbilities abilities, Game game) { - logger.fine("chooseTriggeredAbility"); + logger.debug("chooseTriggeredAbility"); //TODO: improve this if (abilities.size() > 0) return abilities.get(0); @@ -777,21 +783,21 @@ public class ComputerPlayer> extends PlayerImpl i @Override public void assignDamage(int damage, List targets, UUID sourceId, Game game) { - logger.fine("assignDamage"); + logger.debug("assignDamage"); //TODO: improve this game.getPermanent(targets.get(0)).damage(damage, sourceId, game, true, false); } @Override public int getAmount(int min, int max, String message, Game game) { - logger.fine("getAmount"); + logger.debug("getAmount"); //TODO: improve this return min; } @Override protected List getAvailableManaProducers(Game game) { -// logger.fine("getAvailableManaProducers"); +// logger.debug("getAvailableManaProducers"); return super.getAvailableManaProducers(game); } @@ -803,12 +809,73 @@ public class ComputerPlayer> extends PlayerImpl i @Override public void construct(Tournament tournament, Deck deck) { - //TODO: improve this if (deck.getCards().size() < 40) { - while (deck.getCards().size() < 40) { - Card card = deck.getSideboard().iterator().next(); - deck.getCards().add(card); - deck.getSideboard().remove(card); + //pick the top 23 cards + if (chosenColors == null) { + for (Card card: deck.getSideboard()) { + rememberPick(card, RateCard.rateCard(card, null)); + } + chosenColors = chooseDeckColorsIfPossible(); + } + List sortedCards = new ArrayList(deck.getSideboard()); + Collections.sort(sortedCards, new Comparator() { + @Override + public int compare(Card o1, Card o2) { + Integer score1 = RateCard.rateCard(o1, chosenColors); + Integer score2 = RateCard.rateCard(o2, chosenColors); + return score2.compareTo(score1); + } + }); + int cardNum = 0; + while (deck.getCards().size() < 23 && sortedCards.size() > cardNum) { + Card card = sortedCards.get(cardNum); + if (!card.getSupertype().contains("Basic")) { + deck.getCards().add(card); + deck.getSideboard().remove(card); + } + cardNum++; + } + // add basic lands + // TODO: compensate for non basic lands + Mana mana = new Mana(); + for (Card card: deck.getCards()) { + mana.add(card.getManaCost().getMana()); + } + double total = mana.getBlack() + mana.getBlue() + mana.getGreen() + mana.getRed() + mana.getWhite(); + if (mana.getGreen() > 0) { + int numGreen = (int) Math.round(mana.getGreen() / total * 17); + for (int i = 0; i < numGreen; i++) { + Card land = Sets.findCard("Forest", true); + deck.getCards().add(land); + } + } + if (mana.getBlack() > 0) { + int numBlack = (int) Math.round(mana.getBlack() / total * 17); + for (int i = 0; i < numBlack; i++) { + Card land = Sets.findCard("Swamp", true); + deck.getCards().add(land); + } + } + if (mana.getBlue() > 0) { + int numBlue = (int) Math.round(mana.getBlue() / total * 17); + for (int i = 0; i < numBlue; i++) { + Card land = Sets.findCard("Island", true); + deck.getCards().add(land); + } + } + if (mana.getWhite() > 0) { + int numWhite = (int) Math.round(mana.getWhite() / total * 17); + for (int i = 0; i < numWhite; i++) { + Card land = Sets.findCard("Plains", true); + deck.getCards().add(land); + } + } + if (mana.getRed() > 0) { + int numRed = (int) Math.round(mana.getRed() / total * 17); + for (int i = 0; i < numRed; i++) { + Card land = Sets.findCard("Mountain", true); + deck.getCards().add(land); + } } } tournament.submitDeck(playerId, deck); @@ -926,7 +993,7 @@ public class ComputerPlayer> extends PlayerImpl i } protected Attackers getPotentialAttackers(Game game) { - logger.fine("getAvailableAttackers"); + logger.debug("getAvailableAttackers"); Attackers attackers = new Attackers(); List creatures = super.getAvailableAttackers(game); for (Permanent creature: creatures) { @@ -942,7 +1009,7 @@ public class ComputerPlayer> extends PlayerImpl i } protected int combatPotential(Permanent creature, Game game) { - logger.fine("combatPotential"); + logger.debug("combatPotential"); if (!creature.canAttack(game)) return 0; int potential = creature.getPower().getValue(); @@ -955,21 +1022,21 @@ public class ComputerPlayer> extends PlayerImpl i } // protected List getAvailableBlockers(Game game) { -// logger.fine("getAvailableBlockers"); +// logger.debug("getAvailableBlockers"); // FilterCreatureForCombat blockFilter = new FilterCreatureForCombat(); // List blockers = game.getBattlefield().getAllActivePermanents(blockFilter, playerId); // return blockers; // } protected List getOpponentBlockers(UUID opponentId, Game game) { - logger.fine("getOpponentBlockers"); + logger.debug("getOpponentBlockers"); FilterCreatureForCombat blockFilter = new FilterCreatureForCombat(); List blockers = game.getBattlefield().getAllActivePermanents(blockFilter, opponentId); return blockers; } protected CombatSimulator simulateAttack(Attackers attackers, List blockers, UUID opponentId, Game game) { - logger.fine("simulateAttack"); + logger.debug("simulateAttack"); List attackersList = attackers.getAttackers(); CombatSimulator best = new CombatSimulator(); int bestResult = 0; @@ -1000,7 +1067,7 @@ public class ComputerPlayer> extends PlayerImpl i } protected CombatSimulator simulateBlock(CombatSimulator combat, List blockers, Game game) { - logger.fine("simulateBlock"); + logger.debug("simulateBlock"); TreeNode simulations; @@ -1073,8 +1140,8 @@ public class ComputerPlayer> extends PlayerImpl i } protected void logState(Game game) { - if (logger.isLoggable(Level.FINE)) - logList("computer player hand: ", new ArrayList(hand.getCards(game))); + if (logger.isDebugEnabled()) + logList("computer player " + name + " hand: ", new ArrayList(hand.getCards(game))); } protected void logList(String message, List list) { @@ -1083,7 +1150,7 @@ public class ComputerPlayer> extends PlayerImpl i for (MageObject object: list) { sb.append(object.getName()).append(","); } - logger.fine(sb.toString()); + logger.debug(sb.toString()); } protected void logAbilityList(String message, List list) { @@ -1092,7 +1159,7 @@ public class ComputerPlayer> extends PlayerImpl i for (Ability ability: list) { sb.append(ability.getRule()).append(","); } - logger.fine(sb.toString()); + logger.debug(sb.toString()); } private void playRemoval(List creatures, Game game) { @@ -1146,4 +1213,3 @@ public class ComputerPlayer> extends PlayerImpl i } } - diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java index ab15d6f8da..7ced3b867f 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java @@ -44,6 +44,7 @@ import mage.Constants.PhaseStep; import mage.Constants.RangeOfInfluence; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; +import mage.abilities.common.PassAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.SearchEffect; import mage.cards.Cards; @@ -161,6 +162,8 @@ public class ComputerPlayer2 extends ComputerPlayer implements while (actions.peek() != null) { Ability ability = actions.poll(); this.activateAbility((ActivatedAbility) ability, game); + if (logger.isDebugEnabled()) + logger.debug("activating: " + ability); if (ability.isUsesStack()) usedStack = true; } @@ -174,7 +177,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements if (!getNextAction(game)) { Game sim = createSimulation(game); SimulationNode.resetCount(); - root = new SimulationNode(sim, maxDepth, playerId); + root = new SimulationNode(null, sim, maxDepth, playerId); logger.debug("simulating actions"); addActionsTimed(new FilterAbility()); if (root.children.size() > 0) { @@ -224,7 +227,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements if (val < beta) { beta = val; bestChild = child; - if (node.getCombat() == null) +// if (node.getCombat() == null) node.setCombat(child.getCombat()); } } @@ -232,7 +235,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements if (val > alpha) { alpha = val; bestChild = child; - if (node.getCombat() == null) +// if (node.getCombat() == null) node.setCombat(child.getCombat()); } } @@ -272,7 +275,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements SearchEffect newEffect = getSearchEffect((StackAbility) newAbility); newEffect.getTarget().addTarget(targetId, newAbility, sim); sim.getStack().push(newAbility); - SimulationNode newNode = new SimulationNode(sim, depth, ability.getControllerId()); + SimulationNode newNode = new SimulationNode(node, sim, depth, ability.getControllerId()); node.children.add(newNode); newNode.getTargets().add(targetId); logger.debug("simulating search -- node#: " + SimulationNode.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName()); @@ -381,12 +384,14 @@ public class ComputerPlayer2 extends ComputerPlayer implements Game sim = game.copy(); if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { sim.applyEffects(); + if (checkForRepeatedAction(sim, node, action, currentPlayer.getId())) + continue; if (!sim.isGameOver() && action.isUsesStack()) { // only pass if the last action uses the stack sim.getPlayer(currentPlayer.getId()).pass(); sim.getPlayerList().getNext(); } - SimulationNode newNode = new SimulationNode(sim, action, depth, currentPlayer.getId()); + SimulationNode newNode = new SimulationNode(node, sim, action, depth, currentPlayer.getId()); if (logger.isDebugEnabled()) logger.debug("simulating -- node #:" + SimulationNode.getCount() + " actions:" + action); sim.checkStateAndTriggered(); @@ -561,7 +566,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); - SimulationNode newNode = new SimulationNode(sim, node.getDepth()-1, activePlayerId); + SimulationNode newNode = new SimulationNode(node, sim, node.getDepth()-1, activePlayerId); logger.debug("simulating -- node #:" + SimulationNode.getCount() + " declare attakers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); @@ -582,7 +587,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); - SimulationNode newNode = new SimulationNode(sim, node.getDepth()-1, defenderId); + SimulationNode newNode = new SimulationNode(node, sim, node.getDepth()-1, defenderId); logger.debug("simulating -- node #:" + SimulationNode.getCount() + " declare blockers"); newNode.setCombat(sim.getCombat()); node.children.add(newNode); @@ -648,4 +653,22 @@ public class ComputerPlayer2 extends ComputerPlayer implements return sim; } + private boolean checkForRepeatedAction(Game sim, SimulationNode node, Ability action, UUID playerId) { + if (action instanceof PassAbility) + return false; + int val = GameStateEvaluator.evaluate(playerId, sim); + SimulationNode test = node.getParent(); + while (test != null && !test.getPlayerId().equals(playerId)) { + test = test.getParent(); + } + if (test != null && test.getAbilities() != null && test.getAbilities().size() == 1) { + if (action.toString().equals(test.getAbilities().get(0).toString()) && GameStateEvaluator.evaluate(playerId, sim) == val) { + if (logger.isDebugEnabled()) + logger.debug("found repeated action " + action); + return true; + } + } + return false; + } + } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java index 2e8a2b2dad..5400751b70 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java @@ -98,6 +98,8 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { @Override public void priority(Game game) { logState(game); + if (logger.isDebugEnabled()) + logger.debug("Game State: Turn-" + game.getTurnNum() + " Step-" + game.getTurn().getStepType() + " ActivePlayer-" + game.getPlayer(game.getActivePlayerId()).getName() + " PriorityPlayer-" + name); game.firePriorityEvent(playerId); switch (game.getTurn().getStepType()) { case UPKEEP: @@ -154,7 +156,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { currentScore = GameStateEvaluator.evaluate(playerId, game); Game sim = createSimulation(game); SimulationNode.resetCount(); - root = new SimulationNode(sim, maxDepth, playerId); + root = new SimulationNode(null, sim, maxDepth, playerId); logger.debug("simulating pre combat actions -----------------------------------------------------------------------------------------"); addActionsTimed(new FilterAbility()); @@ -171,7 +173,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { currentScore = GameStateEvaluator.evaluate(playerId, game); Game sim = createSimulation(game); SimulationNode.resetCount(); - root = new SimulationNode(sim, maxDepth, playerId); + root = new SimulationNode(null, sim, maxDepth, playerId); logger.debug("simulating post combat actions ----------------------------------------------------------------------------------------"); addActionsTimed(new FilterAbility()); if (root.children.size() > 0) { @@ -227,13 +229,13 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { else { switch (game.getTurn().getStepType()) { case PRECOMBAT_MAIN: - val = -simulateCombat(game, node, depth-1, alpha, beta, false); + val = simulateCombat(game, node, depth-1, alpha, beta, false); break; case POSTCOMBAT_MAIN: - val = -simulateCounterAttack(game, node, depth-1, alpha, beta); + val = simulateCounterAttack(game, node, depth-1, alpha, beta); break; default: - val = -GameStateEvaluator.evaluate(playerId, game); + val = GameStateEvaluator.evaluate(playerId, game); break; } } @@ -316,6 +318,8 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { SimulationNode bestNode = null; SimulatedPlayer attacker = (SimulatedPlayer) game.getPlayer(attackerId); + if (logger.isDebugEnabled()) + logger.debug(attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(game)); for (Combat engagement: attacker.addAttackers(game)) { if (alpha >= beta) { logger.debug("simulating -- pruning attackers"); @@ -329,9 +333,9 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId)); - SimulationNode newNode = new SimulationNode(sim, depth, game.getActivePlayerId()); + SimulationNode newNode = new SimulationNode(node, sim, depth, attackerId); if (logger.isDebugEnabled()) - logger.debug("simulating attack -- node#: " + SimulationNode.getCount()); + logger.debug("simulating attack for player:" + game.getPlayer(newNode.getPlayerId()).getName()); sim.checkStateAndTriggered(); while (!sim.getStack().isEmpty()) { sim.getStack().resolve(sim); @@ -379,6 +383,8 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { //check if defender is being attacked if (game.getCombat().isAttacked(defenderId, game)) { SimulatedPlayer defender = (SimulatedPlayer) game.getPlayer(defenderId); + if (logger.isDebugEnabled()) + logger.debug(defender.getName() + "'s possible blockers: " + defender.getAvailableBlockers(game)); for (Combat engagement: defender.addBlockers(game)) { if (alpha >= beta) { logger.debug("simulating -- pruning blockers"); @@ -394,9 +400,9 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { } } sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId)); - SimulationNode newNode = new SimulationNode(sim, depth, defenderId); + SimulationNode newNode = new SimulationNode(node, sim, depth, defenderId); if (logger.isDebugEnabled()) - logger.debug("simulating block -- node#: " + SimulationNode.getCount()); + logger.debug("simulating block for player:" + game.getPlayer(newNode.getPlayerId()).getName()); sim.checkStateAndTriggered(); while (!sim.getStack().isEmpty()) { sim.getStack().resolve(sim); diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java index f4734f9bbc..90a8b0ec58 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java @@ -6,8 +6,6 @@ package mage.player.ai; import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.Constants.CardType; import mage.Constants.Zone; import mage.abilities.ActivatedAbility; @@ -18,7 +16,7 @@ import mage.abilities.mana.ManaAbility; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.util.Logging; +import org.apache.log4j.Logger; /** * @@ -29,7 +27,7 @@ import mage.util.Logging; */ public class GameStateEvaluator { - private final static transient Logger logger = Logging.getLogger(GameStateEvaluator.class.getName()); + private final static transient Logger logger = Logger.getLogger(GameStateEvaluator.class); private static final int LIFE_FACTOR = Config.evaluatorLifeFactor; private static final int PERMANENT_FACTOR = Config.evaluatorPermanentFactor; @@ -56,13 +54,12 @@ public class GameStateEvaluator { permanentScore *= PERMANENT_FACTOR; int handScore = 0; - handScore = 7 - opponent.getHand().size(); - handScore += Math.min(7, player.getHand().size()); + handScore = player.getHand().size() - opponent.getHand().size(); handScore *= HAND_FACTOR; int score = lifeScore + permanentScore + handScore; - if (logger.isLoggable(Level.FINE)) - logger.fine("game state evaluated to- lifeScore:" + lifeScore + " permanentScore:" + permanentScore + " handScore:" + handScore + " total:" + score); + if (logger.isDebugEnabled()) + logger.debug("game state evaluated to- lifeScore:" + lifeScore + " permanentScore:" + permanentScore + " handScore:" + handScore + " total:" + score); return score; } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java index 48d4c97903..0bd6533cdf 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java @@ -221,7 +221,7 @@ public class SimulatedPlayer extends ComputerPlayer { sim.getStack().push(new StackAbility(ability, playerId)); ability.activate(sim, false); sim.applyEffects(); - SimulationNode newNode = new SimulationNode(sim, depth, playerId); + SimulationNode newNode = new SimulationNode(parent, sim, depth, playerId); logger.debug("simulating -- node #:" + SimulationNode.getCount() + " triggered ability option"); for (Target target: ability.getTargets()) { for (UUID targetId: target.getTargets()) { diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulationNode.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulationNode.java index 954e4c7097..002ce922ab 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulationNode.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/SimulationNode.java @@ -49,12 +49,14 @@ public class SimulationNode implements Serializable { protected List abilities; protected int depth; protected List children = new ArrayList(); + protected SimulationNode parent; protected List targets = new ArrayList(); protected List choices = new ArrayList(); protected UUID playerId; protected Combat combat; - public SimulationNode(Game game, int depth, UUID playerId) { + public SimulationNode(SimulationNode parent, Game game, int depth, UUID playerId) { + this.parent = parent; this.game = game; this.depth = depth; this.playerId = playerId; @@ -62,13 +64,13 @@ public class SimulationNode implements Serializable { nodeCount++; } - public SimulationNode(Game game, List abilities, int depth, UUID playerId) { - this(game, depth, playerId); + public SimulationNode(SimulationNode parent, Game game, List abilities, int depth, UUID playerId) { + this(parent, game, depth, playerId); this.abilities = abilities; } - public SimulationNode(Game game, Ability ability, int depth, UUID playerId) { - this(game, depth, playerId); + public SimulationNode(SimulationNode parent, Game game, Ability ability, int depth, UUID playerId) { + this(parent, game, depth, playerId); this.abilities = new ArrayList(); abilities.add(ability); } @@ -97,6 +99,10 @@ public class SimulationNode implements Serializable { return this.abilities; } + public SimulationNode getParent() { + return this.parent; + } + public List getChildren() { return this.children; } diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index 4e151620eb..45016d5014 100644 Binary files a/Mage.Server/plugins/mage-player-ai.jar and b/Mage.Server/plugins/mage-player-ai.jar differ diff --git a/Mage.Server/plugins/mage-player-aiminimax.jar b/Mage.Server/plugins/mage-player-aiminimax.jar index 6f0d28c6ed..72624ad402 100644 Binary files a/Mage.Server/plugins/mage-player-aiminimax.jar and b/Mage.Server/plugins/mage-player-aiminimax.jar differ diff --git a/Mage.Server/plugins/mage-tournament-sealed.jar b/Mage.Server/plugins/mage-tournament-sealed.jar new file mode 100644 index 0000000000..e4a8584a98 Binary files /dev/null and b/Mage.Server/plugins/mage-tournament-sealed.jar differ diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java index 9c18fefe56..b01511d9de 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java @@ -191,7 +191,7 @@ public class TournamentController { TableManager.getInstance().construct(tableId); } - private synchronized void construct(UUID sessionId, Deck deck, int timeout) { + private void construct(UUID sessionId, Deck deck, int timeout) { if (tournamentSessions.containsKey(sessionId)) tournamentSessions.get(sessionId).construct(deck, timeout); } diff --git a/Mage/src/mage/Mana.java b/Mage/src/mage/Mana.java index 2ba46f9fa6..4b31e628dc 100644 --- a/Mage/src/mage/Mana.java +++ b/Mage/src/mage/Mana.java @@ -66,6 +66,26 @@ public class Mana implements Comparable, Serializable, Copyable { any = mana.any; } + public Mana(ColoredManaSymbol color) { + switch (color) { + case G: + green = 1; + break; + case R: + red = 1; + break; + case B: + black = 1; + break; + case U: + blue = 1; + break; + case W: + white = 1; + break; + } + } + public static Mana RedMana(int num) { return new Mana(num, 0, 0, 0, 0, 0, 0); } diff --git a/Mage/src/mage/abilities/costs/mana/ColoredManaCost.java b/Mage/src/mage/abilities/costs/mana/ColoredManaCost.java index ba9d31cc10..155ad4bb7b 100644 --- a/Mage/src/mage/abilities/costs/mana/ColoredManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/ColoredManaCost.java @@ -38,6 +38,7 @@ public class ColoredManaCost extends ManaCostImpl { public ColoredManaCost(ColoredManaSymbol mana) { this.mana = mana; + this.cost = new Mana(mana); addColoredOption(mana); } @@ -46,10 +47,6 @@ public class ColoredManaCost extends ManaCostImpl { this.mana = cost.mana; } - public ColoredManaSymbol getMana() { - return mana; - } - @Override public int convertedManaCost() { return 1; diff --git a/Mage/src/mage/abilities/costs/mana/GenericManaCost.java b/Mage/src/mage/abilities/costs/mana/GenericManaCost.java index f4f95d3976..0e1e7aae9b 100644 --- a/Mage/src/mage/abilities/costs/mana/GenericManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/GenericManaCost.java @@ -37,6 +37,7 @@ public class GenericManaCost extends ManaCostImpl { public GenericManaCost(int mana) { this.mana = mana; + this.cost = Mana.ColorlessMana(mana); this.options.addMana(Mana.ColorlessMana(mana)); } @@ -45,10 +46,6 @@ public class GenericManaCost extends ManaCostImpl { this.mana = cost.mana; } - public int getMana() { - return mana; - } - public void setMana(int mana) { this.mana = mana; } diff --git a/Mage/src/mage/abilities/costs/mana/HybridManaCost.java b/Mage/src/mage/abilities/costs/mana/HybridManaCost.java index 3176a3515b..306466efdf 100644 --- a/Mage/src/mage/abilities/costs/mana/HybridManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/HybridManaCost.java @@ -39,6 +39,8 @@ public class HybridManaCost extends ManaCostImpl { public HybridManaCost(ColoredManaSymbol mana1, ColoredManaSymbol mana2) { this.mana1 = mana1; this.mana2 = mana2; + this.cost = new Mana(mana1); + this.cost.add(new Mana(mana2)); addColoredOption(mana1); addColoredOption(mana2); } @@ -54,14 +56,6 @@ public class HybridManaCost extends ManaCostImpl { return 1; } - public ColoredManaSymbol getMana1() { - return mana1; - } - - public ColoredManaSymbol getMana2() { - return mana2; - } - @Override public boolean isPaid() { if (paid || isColoredPaid(this.mana1) || isColoredPaid(this.mana2)) diff --git a/Mage/src/mage/abilities/costs/mana/ManaCost.java b/Mage/src/mage/abilities/costs/mana/ManaCost.java index 8aa0ccc298..31291b1629 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCost.java @@ -36,6 +36,7 @@ import mage.players.ManaPool; public interface ManaCost extends Cost { public int convertedManaCost(); + public Mana getMana(); public Mana getPayment(); public void assignPayment(ManaPool pool); @Override @@ -46,4 +47,5 @@ public interface ManaCost extends Cost { @Override public ManaCost copy(); + } diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java index 671092ac60..3729aaeddf 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java @@ -31,7 +31,6 @@ package mage.abilities.costs.mana; import java.util.UUID; import mage.Constants.ColoredManaSymbol; import mage.Mana; -import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.abilities.mana.ManaOptions; import mage.game.Game; @@ -41,6 +40,7 @@ import mage.players.Player; public abstract class ManaCostImpl> extends CostImpl implements ManaCost { protected Mana payment; + protected Mana cost; protected ManaOptions options; @Override @@ -62,6 +62,11 @@ public abstract class ManaCostImpl> extends CostImpl extends List, ManaCost { public List getVariableCosts(); public void load(String mana); public List getSymbols(); + public Mana getMana(); @Override public ManaCosts copy(); diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java index eba66b665a..c396e45190 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java @@ -81,6 +81,15 @@ public class ManaCostsImpl extends ArrayList implements M return total; } + @Override + public Mana getMana() { + Mana mana = new Mana(); + for (ManaCost cost: this) { + mana.add(cost.getMana()); + } + return mana; + } + @Override public Mana getPayment() { Mana manaTotal = new Mana(); diff --git a/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java b/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java index 732007a5cf..e6c1624c9c 100644 --- a/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java @@ -39,6 +39,8 @@ public class MonoHybridManaCost extends ManaCostImpl { public MonoHybridManaCost(ColoredManaSymbol mana) { this.mana = mana; + this.cost = new Mana(mana); + this.cost.add(Mana.ColorlessMana(2)); addColoredOption(mana); options.add(Mana.ColorlessMana(2)); } @@ -54,10 +56,6 @@ public class MonoHybridManaCost extends ManaCostImpl { return 2; } - public ColoredManaSymbol getMana() { - return mana; - } - @Override public boolean isPaid() { if (paid || isColoredPaid(this.mana)) diff --git a/Mage/src/mage/abilities/costs/mana/VariableManaCost.java b/Mage/src/mage/abilities/costs/mana/VariableManaCost.java index 80e9fb6438..94aece97b4 100644 --- a/Mage/src/mage/abilities/costs/mana/VariableManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/VariableManaCost.java @@ -43,6 +43,7 @@ public class VariableManaCost extends ManaCostImpl implements public VariableManaCost() { this(1); + this.cost = new Mana(); options.add(new Mana()); } diff --git a/Mage/src/mage/game/draft/DraftImpl.java b/Mage/src/mage/game/draft/DraftImpl.java index 64bcece061..a1804fddb6 100644 --- a/Mage/src/mage/game/draft/DraftImpl.java +++ b/Mage/src/mage/game/draft/DraftImpl.java @@ -58,7 +58,7 @@ public abstract class DraftImpl> implements Draft { protected int boosterNum = 0; protected int cardNum = 0; protected TimingOption timing; - protected int[] times = {40, 40, 35, 30, 25, 25, 20, 20, 15, 10, 10, 5, 5, 5, 5}; + protected int[] times = {75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5}; protected transient TableEventSource tableEventSource = new TableEventSource(); protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); diff --git a/Mage/src/mage/game/draft/DraftPlayer.java b/Mage/src/mage/game/draft/DraftPlayer.java index 0e7bbbb9c2..671d262fa5 100644 --- a/Mage/src/mage/game/draft/DraftPlayer.java +++ b/Mage/src/mage/game/draft/DraftPlayer.java @@ -28,6 +28,7 @@ package mage.game.draft; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.cards.Card; @@ -68,12 +69,16 @@ public class DraftPlayer { public void addPick(Card card) { deck.getSideboard().add(card); - booster.remove(card); + synchronized(booster) { + booster.remove(card); + } picking = false; } public void openBooster(ExpansionSet set) { - booster = set.createBooster(); + synchronized(booster) { + booster = set.createBooster(); + } } public void setBooster(List booster) { @@ -81,7 +86,9 @@ public class DraftPlayer { } public List getBooster() { - return booster; + synchronized(booster) { + return new ArrayList(booster); + } } public void setPicking() { diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index ad7e09c8c7..44856bd24a 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -104,6 +104,11 @@ public abstract class PermanentImpl> extends CardImpl this.attachedTo = permanent.attachedTo; } + @Override + public String toString() { + return this.name + "-" + this.expansionSetCode; + } + @Override public void reset(Game game) { // this.controllerId = ownerId; diff --git a/Mage/src/mage/game/tournament/TournamentImpl.java b/Mage/src/mage/game/tournament/TournamentImpl.java index fd75633b11..6c48e4ebee 100644 --- a/Mage/src/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/mage/game/tournament/TournamentImpl.java @@ -228,9 +228,15 @@ public abstract class TournamentImpl implements Tournament { public void construct() { tableEventSource.fireTableEvent(EventType.CONSTRUCT); - for (TournamentPlayer player: players.values()) { + for (final TournamentPlayer player: players.values()) { player.setConstructing(); - player.getPlayer().construct(this, player.getDeck()); + new Thread( + new Runnable() { + public void run() { + player.getPlayer().construct(TournamentImpl.this, player.getDeck()); + } + } + ).start(); } synchronized(this) { while (!isDoneConstructing()) {