AI fixes and deck construction

This commit is contained in:
BetaSteward 2011-02-18 23:22:31 -05:00
parent 4f74ae204d
commit 659f790325
27 changed files with 271 additions and 119 deletions

View file

@ -27,7 +27,7 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="553" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="639" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -35,7 +35,7 @@
<Group type="102" attributes="0">
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="23" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="397" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -57,13 +57,13 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="lblCount" max="32767" attributes="0"/>
<Component id="lblCount" min="-2" pref="81" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="lblCreatureCount" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="lblLandCount" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="cbSortBy" min="-2" pref="338" max="-2" attributes="0"/>
<Component id="lblCreatureCount" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="lblLandCount" min="-2" pref="75" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="cbSortBy" pref="353" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View file

@ -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))
);
}// </editor-fold>//GEN-END:initComponents

View file

@ -15,11 +15,22 @@
<name>Mage Player AI</name>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>Mage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>Mage-Sets</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>

View file

@ -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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<Mana, Card> unplayable = new TreeMap<Mana, Card>();
private transient List<Card> playableNonInstant = new ArrayList<Card>();
private transient List<Card> playableInstant = new ArrayList<Card>();
@ -127,7 +127,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
@Override
public boolean chooseMulligan(Game game) {
logger.fine("chooseMulligan");
logger.debug("chooseMulligan");
if (hand.size() < 6)
return false;
Set<Card> lands = hand.getCards(new FilterLandCard(), game);
@ -143,8 +143,8 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
@Override
public boolean choose(Outcome outcome, Target target, Game game, Map<String, Serializable> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
protected void playLand(Game game) {
logger.fine("playLand");
logger.debug("playLand");
Set<Card> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
protected void playALand(Set<Card> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<Permanent> producers;
if (unpaid instanceof ManaCosts) {
@ -627,8 +627,14 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<Permanent> blockers = getOpponentBlockers(opponentId, game);
@ -745,7 +751,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
@Override
public void selectBlockers(Game game) {
logger.fine("selectBlockers");
logger.debug("selectBlockers");
List<Permanent> blockers = getAvailableBlockers(game);
@ -761,14 +767,14 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
@Override
public int chooseEffect(List<ReplacementEffect> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
@Override
public void assignDamage(int damage, List<UUID> 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<Permanent> getAvailableManaProducers(Game game) {
// logger.fine("getAvailableManaProducers");
// logger.debug("getAvailableManaProducers");
return super.getAvailableManaProducers(game);
}
@ -803,12 +809,73 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<Card> sortedCards = new ArrayList<Card>(deck.getSideboard());
Collections.sort(sortedCards, new Comparator<Card>() {
@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<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
protected Attackers getPotentialAttackers(Game game) {
logger.fine("getAvailableAttackers");
logger.debug("getAvailableAttackers");
Attackers attackers = new Attackers();
List<Permanent> creatures = super.getAvailableAttackers(game);
for (Permanent creature: creatures) {
@ -942,7 +1009,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
// protected List<Permanent> getAvailableBlockers(Game game) {
// logger.fine("getAvailableBlockers");
// logger.debug("getAvailableBlockers");
// FilterCreatureForCombat blockFilter = new FilterCreatureForCombat();
// List<Permanent> blockers = game.getBattlefield().getAllActivePermanents(blockFilter, playerId);
// return blockers;
// }
protected List<Permanent> getOpponentBlockers(UUID opponentId, Game game) {
logger.fine("getOpponentBlockers");
logger.debug("getOpponentBlockers");
FilterCreatureForCombat blockFilter = new FilterCreatureForCombat();
List<Permanent> blockers = game.getBattlefield().getAllActivePermanents(blockFilter, opponentId);
return blockers;
}
protected CombatSimulator simulateAttack(Attackers attackers, List<Permanent> blockers, UUID opponentId, Game game) {
logger.fine("simulateAttack");
logger.debug("simulateAttack");
List<Permanent> attackersList = attackers.getAttackers();
CombatSimulator best = new CombatSimulator();
int bestResult = 0;
@ -1000,7 +1067,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
protected CombatSimulator simulateBlock(CombatSimulator combat, List<Permanent> blockers, Game game) {
logger.fine("simulateBlock");
logger.debug("simulateBlock");
TreeNode<CombatSimulator> simulations;
@ -1073,8 +1140,8 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> 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<MageObject> list) {
@ -1083,7 +1150,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
for (MageObject object: list) {
sb.append(object.getName()).append(",");
}
logger.fine(sb.toString());
logger.debug(sb.toString());
}
protected void logAbilityList(String message, List<Ability> list) {
@ -1092,7 +1159,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
for (Ability ability: list) {
sb.append(ability.getRule()).append(",");
}
logger.fine(sb.toString());
logger.debug(sb.toString());
}
private void playRemoval(List<UUID> creatures, Game game) {
@ -1146,4 +1213,3 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
}

View file

@ -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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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<ComputerPlayer2> 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;
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -221,7 +221,7 @@ public class SimulatedPlayer extends ComputerPlayer<SimulatedPlayer> {
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()) {

View file

@ -49,12 +49,14 @@ public class SimulationNode implements Serializable {
protected List<Ability> abilities;
protected int depth;
protected List<SimulationNode> children = new ArrayList<SimulationNode>();
protected SimulationNode parent;
protected List<UUID> targets = new ArrayList<UUID>();
protected List<String> choices = new ArrayList<String>();
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<Ability> abilities, int depth, UUID playerId) {
this(game, depth, playerId);
public SimulationNode(SimulationNode parent, Game game, List<Ability> 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<Ability>();
abilities.add(ability);
}
@ -97,6 +99,10 @@ public class SimulationNode implements Serializable {
return this.abilities;
}
public SimulationNode getParent() {
return this.parent;
}
public List<SimulationNode> getChildren() {
return this.children;
}

Binary file not shown.

View file

@ -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);
}

View file

@ -66,6 +66,26 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
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);
}

View file

@ -38,6 +38,7 @@ public class ColoredManaCost extends ManaCostImpl<ColoredManaCost> {
public ColoredManaCost(ColoredManaSymbol mana) {
this.mana = mana;
this.cost = new Mana(mana);
addColoredOption(mana);
}
@ -46,10 +47,6 @@ public class ColoredManaCost extends ManaCostImpl<ColoredManaCost> {
this.mana = cost.mana;
}
public ColoredManaSymbol getMana() {
return mana;
}
@Override
public int convertedManaCost() {
return 1;

View file

@ -37,6 +37,7 @@ public class GenericManaCost extends ManaCostImpl<GenericManaCost> {
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<GenericManaCost> {
this.mana = cost.mana;
}
public int getMana() {
return mana;
}
public void setMana(int mana) {
this.mana = mana;
}

View file

@ -39,6 +39,8 @@ public class HybridManaCost extends ManaCostImpl<HybridManaCost> {
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<HybridManaCost> {
return 1;
}
public ColoredManaSymbol getMana1() {
return mana1;
}
public ColoredManaSymbol getMana2() {
return mana2;
}
@Override
public boolean isPaid() {
if (paid || isColoredPaid(this.mana1) || isColoredPaid(this.mana2))

View file

@ -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();
}

View file

@ -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<T extends ManaCostImpl<T>> extends CostImpl<T> implements ManaCost {
protected Mana payment;
protected Mana cost;
protected ManaOptions options;
@Override
@ -62,6 +62,11 @@ public abstract class ManaCostImpl<T extends ManaCostImpl<T>> extends CostImpl<T
return payment;
}
@Override
public Mana getMana() {
return cost;
}
@Override
public ManaOptions getOptions() {
return options;

View file

@ -29,6 +29,7 @@
package mage.abilities.costs.mana;
import java.util.List;
import mage.Mana;
import mage.abilities.costs.VariableCost;
/**
@ -41,6 +42,7 @@ public interface ManaCosts<T extends ManaCost> extends List<T>, ManaCost {
public List<VariableCost> getVariableCosts();
public void load(String mana);
public List<String> getSymbols();
public Mana getMana();
@Override
public ManaCosts<T> copy();

View file

@ -81,6 +81,15 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> 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();

View file

@ -39,6 +39,8 @@ public class MonoHybridManaCost extends ManaCostImpl<MonoHybridManaCost> {
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<MonoHybridManaCost> {
return 2;
}
public ColoredManaSymbol getMana() {
return mana;
}
@Override
public boolean isPaid() {
if (paid || isColoredPaid(this.mana))

View file

@ -43,6 +43,7 @@ public class VariableManaCost extends ManaCostImpl<VariableManaCost> implements
public VariableManaCost() {
this(1);
this.cost = new Mana();
options.add(new Mana());
}

View file

@ -58,7 +58,7 @@ public abstract class DraftImpl<T extends DraftImpl<T>> 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();

View file

@ -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<Card> booster) {
@ -81,7 +86,9 @@ public class DraftPlayer {
}
public List<Card> getBooster() {
return booster;
synchronized(booster) {
return new ArrayList<Card>(booster);
}
}
public void setPicking() {

View file

@ -104,6 +104,11 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
this.attachedTo = permanent.attachedTo;
}
@Override
public String toString() {
return this.name + "-" + this.expansionSetCode;
}
@Override
public void reset(Game game) {
// this.controllerId = ownerId;

View file

@ -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()) {