more optimizations

This commit is contained in:
BetaSteward 2011-03-24 00:09:07 -04:00
parent 5097b0812b
commit 8287364f77
12 changed files with 146 additions and 30 deletions

View file

@ -40,11 +40,9 @@ import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import mage.Constants.Outcome;
import mage.Constants.PhaseStep;
import mage.Constants.RangeOfInfluence;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.common.PassAbility;
@ -55,7 +53,6 @@ import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.SearchEffect;
import mage.cards.Cards;
import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.filter.FilterAbility;
import mage.game.Game;
@ -98,6 +95,8 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
protected int maxDepth;
protected int maxNodes;
protected int nodeCount = 0;
protected long thinkTime = 0;
protected LinkedList<Ability> actions = new LinkedList<Ability>();
protected List<UUID> targets = new ArrayList<UUID>();
protected List<String> choices = new ArrayList<String>();
@ -190,6 +189,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
addActionsTimed(new FilterAbility());
else
addActions(root, new FilterAbility(), Integer.MIN_VALUE, Integer.MAX_VALUE);
logger.info(name + " simulated " + nodeCount + " nodes in " + thinkTime/1000000000.0 + "s - average " + nodeCount/(thinkTime/1000000000.0) + " nodes/s");
if (root.children.size() > 0) {
root = root.children.get(0);
actions = new LinkedList<Ability>(root.abilities);
@ -319,9 +319,15 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
return addActions(root, filter, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
});
long startTime = System.nanoTime();
pool.execute(task);
try {
task.get(Config.maxThinkSeconds, TimeUnit.SECONDS);
long endTime = System.nanoTime();
long duration = endTime - startTime;
logger.info("Calculated " + root.nodeCount + " nodes in " + duration/1000000000.0 + "s");
nodeCount += root.nodeCount;
thinkTime += duration;
} catch (TimeoutException e) {
logger.debug("simulating - timed out");
task.cancel(true);
@ -331,6 +337,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
} catch (InterruptedException ex) {
logger.fatal("can't sleep");
}
logger.info("Calculated " + root.nodeCount + " nodes in 30s");
} catch (ExecutionException e) {
logger.fatal("Simulation error", e);
task.cancel(true);
@ -712,6 +719,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
newPlayer.restore(origPlayer);
sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer);
}
sim.setSimulation(true);
return sim;
}

View file

@ -164,6 +164,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
addActionsTimed(new FilterAbility());
else
addActions(root, new FilterAbility(), Integer.MIN_VALUE, Integer.MAX_VALUE);
logger.info(name + " simulated " + nodeCount + " nodes in " + thinkTime/1000000000.0 + "s - average " + nodeCount/(thinkTime/1000000000.0) + " nodes/s");
if (root.children.size() > 0) {
root = root.children.get(0);
actions = new LinkedList<Ability>(root.abilities);
@ -187,6 +188,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
addActionsTimed(new FilterAbility());
else
addActions(root, new FilterAbility(), Integer.MIN_VALUE, Integer.MAX_VALUE);
logger.info(name + " simulated " + nodeCount + " nodes in " + thinkTime/1000000000.0 + "s - average " + nodeCount/(thinkTime/1000000000.0) + " nodes/s");
if (root.children.size() > 0) {
root = root.children.get(0);
actions = new LinkedList<Ability>(root.abilities);

View file

@ -38,6 +38,7 @@ import mage.abilities.keyword.TrampleAbility;
import mage.abilities.mana.ManaAbility;
import mage.counters.BoostCounter;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -76,6 +77,7 @@ public class GameStateEvaluator {
return WIN_SCORE;
}
int lifeScore = (player.getLife() - opponent.getLife()) * LIFE_FACTOR;
int poisonScore = (opponent.getCounters().getCount(CounterType.POISON) - player.getCounters().getCount(CounterType.POISON)) * LIFE_FACTOR * 2;
int permanentScore = 0;
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
permanentScore += evaluatePermanent(permanent, game, ignoreTapped);
@ -89,7 +91,7 @@ public class GameStateEvaluator {
handScore = player.getHand().size() - opponent.getHand().size();
handScore *= HAND_FACTOR;
int score = lifeScore + permanentScore + handScore;
int score = lifeScore + poisonScore + permanentScore + handScore;
if (logger.isDebugEnabled())
logger.debug("game state for player " + player.getName() + " evaluated to- lifeScore:" + lifeScore + " permanentScore:" + permanentScore + " handScore:" + handScore + " total:" + score);
return score;

View file

@ -27,6 +27,6 @@ public class Metalcraft implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return game.getBattlefield().countAll(filter, source.getControllerId()) >= 3;
return game.getBattlefield().contains(filter, source.getControllerId(), 3);
}
}

View file

@ -61,7 +61,7 @@ public class MetalcraftCost extends CostImpl<MetalcraftCost> {
@Override
public boolean canPay(UUID sourceId, UUID controllerId, Game game) {
return game.getBattlefield().countAll(filter, controllerId) >= 3;
return game.getBattlefield().contains(filter, controllerId, 3);
}
@Override

View file

@ -73,7 +73,7 @@ class LandwalkEffect extends RestrictionEffect<LandwalkEffect> {
@Override
public boolean canBlock(Permanent attacker, Permanent blocker, Game game) {
return game.getBattlefield().countAll(filter, blocker.getControllerId()) == 0;
return !game.getBattlefield().contains(filter, blocker.getControllerId(), 1);
}
@Override

View file

@ -107,6 +107,8 @@ public interface Game extends MageItem, Serializable {
public GameStates getGameStates();
public void loadGameStates(GameStates states);
public Game copy();
public boolean isSimulation();
public void setSimulation(boolean simulation);
public Card getLastKnownInformation(UUID objectId, Zone zone);
public void rememberLKI(UUID objectId, Zone zone, Card card);
public void resetLKI();
@ -119,7 +121,6 @@ public interface Game extends MageItem, Serializable {
public void fireSelectTargetEvent(UUID playerId, String message, Set<UUID> targets, boolean required, Map<String, Serializable> options);
public void fireSelectTargetEvent(UUID playerId, String message, Cards cards, boolean required);
public void fireSelectTargetEvent(UUID playerId, String message, TriggeredAbilities abilities, boolean required);
// public void fireRevealCardsEvent(String message, Cards cards);
public void fireSelectEvent(UUID playerId, String message);
public void fireLookAtCardsEvent(UUID playerId, String message, Cards cards);
public void firePriorityEvent(UUID playerId);
@ -136,7 +137,6 @@ public interface Game extends MageItem, Serializable {
public boolean replaceEvent(GameEvent event);
//game play methods
//public void init(UUID choosingPlayerId);
public void start(UUID choosingPlayerId);
public void start(UUID choosingPlayerId, GameOptions options);
public void end();

View file

@ -79,6 +79,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
private transient Stack<Integer> savedStates = new Stack<Integer>();
private transient Object customData;
protected boolean simulation = false;
protected final UUID id;
protected boolean ready;
@ -113,10 +114,18 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
this.range = game.range;
this.attackOption = game.attackOption;
this.state = game.state.copy();
// for (Map.Entry<UUID, Card> entry: game.gameCards.entrySet()) {
// this.gameCards.put(entry.getKey(), entry.getValue().copy());
// }
this.gameCards = game.gameCards;
this.simulation = game.simulation;
}
@Override
public boolean isSimulation() {
return simulation;
}
@Override
public void setSimulation(boolean simulation) {
this.simulation = simulation;
}
@Override
@ -273,22 +282,28 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override
public void bookmarkState() {
if (!simulation) {
saveState();
logger.fine("Bookmarking state: " + gameStates.getSize());
savedStates.push(gameStates.getSize() - 1);
}
}
@Override
public void restoreState() {
if (!simulation) {
GameState restore = gameStates.rollback(savedStates.pop());
if (restore != null)
state.restore(restore);
}
}
@Override
public void removeLastBookmark() {
if (!simulation) {
savedStates.pop();
}
}
@Override
public void start(UUID choosingPlayerId) {
@ -622,13 +637,13 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
}
}
//20091005 - 704.5j, 801.14
if (getBattlefield().countAll(filterPlaneswalker) > 1) { //don't bother checking if less than 2 planeswalkers in play
if (getBattlefield().contains(filterPlaneswalker, 2)) { //don't bother checking if less than 2 planeswalkers in play
for (Permanent planeswalker: getBattlefield().getAllActivePermanents(CardType.PLANESWALKER)) {
for (String planeswalkertype: planeswalker.getSubtype()) {
filterPlaneswalker.getSubtype().clear();
filterPlaneswalker.getSubtype().add(planeswalkertype);
filterPlaneswalker.setScopeSubtype(ComparisonScope.Any);
if (getBattlefield().count(filterPlaneswalker, planeswalker.getControllerId(), this) > 1) {
if (getBattlefield().contains(filterPlaneswalker, planeswalker.getControllerId(), this, 2)) {
for (Permanent perm: getBattlefield().getActivePermanents(filterPlaneswalker, planeswalker.getControllerId(), this)) {
perm.moveToZone(Zone.GRAVEYARD, null, this, false);
}
@ -660,11 +675,11 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
}
}
//20091005 - 704.5k, 801.12
if (getBattlefield().countAll(filterLegendary) > 1) { //don't bother checking if less than 2 legends in play
if (getBattlefield().contains(filterLegendary, 2)) { //don't bother checking if less than 2 legends in play
for (Permanent legend: getBattlefield().getAllActivePermanents(filterLegendary)) {
filterLegendName.getName().clear();
filterLegendName.getName().add(legend.getName());
if (getBattlefield().count(filterLegendName, legend.getControllerId(), this) > 1) {
if (getBattlefield().contains(filterLegendName, legend.getControllerId(), this, 2)) {
for (Permanent dupLegend: getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) {
dupLegend.moveToZone(Zone.GRAVEYARD, null, this, false);
}

View file

@ -138,6 +138,81 @@ public class Battlefield implements Serializable {
return count;
}
/**
* Returns true if the battlefield contains at least 1 {@link Permanent}
* that matches the filter.
* This method ignores the range of influence.
*
* @param filter
* @return boolean
*/
public boolean contains(FilterPermanent filter, int num) {
int count = 0;
for (Permanent permanent: field.values()) {
if (filter.match(permanent)) {
count++;
if (num == count)
return true;
}
}
return false;
}
/**
* Returns true if the battlefield contains at least 1 {@link Permanent}
* that matches the filter and is controlled by controllerId.
* This method ignores the range of influence.
*
* @param filter
* @param controllerId
* @return boolean
*/
public boolean contains(FilterPermanent filter, UUID controllerId, int num) {
int count = 0;
for (Permanent permanent: field.values()) {
if (permanent.getControllerId().equals(controllerId) && filter.match(permanent)) {
count++;
if (num == count)
return true;
}
}
return false;
}
/**
* Returns true if the battlefield contains at least 1 {@link Permanent}
* that is within the range of influence of the specified player id
* and that matches the supplied filter.
*
* @param filter
* @param sourcePlayerId
* @param game
* @return boolean
*/
public boolean contains(FilterPermanent filter, UUID sourcePlayerId, Game game, int num) {
int count = 0;
if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) {
for (Permanent permanent: field.values()) {
if (filter.match(permanent, sourcePlayerId, game)) {
count++;
if (num == count)
return true;
}
}
}
else {
Set<UUID> range = game.getPlayer(sourcePlayerId).getInRange();
for (Permanent permanent: field.values()) {
if (range.contains(permanent.getControllerId()) && filter.match(permanent, sourcePlayerId, game)) {
count++;
if (num == count)
return true;
}
}
}
return false;
}
public void addPermanent(Permanent permanent) {
field.put(permanent.getId(), permanent);
}

View file

@ -105,12 +105,15 @@ public class TargetPermanent<T extends TargetPermanent<T>> extends TargetObject<
*/
@Override
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
int remainingTargets = this.minNumberOfTargets - targets.size();
if (remainingTargets == 0)
return true;
int count = 0;
MageObject targetSource = game.getObject(sourceId);
for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource)) {
count++;
if (count >= this.minNumberOfTargets)
if (count >= remainingTargets)
return true;
}
}
@ -127,9 +130,18 @@ public class TargetPermanent<T extends TargetPermanent<T>> extends TargetObject<
*/
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
int possibleTargets = game.getBattlefield().count(filter, sourceControllerId, game);
return possibleTargets >= this.minNumberOfTargets &&
this.getTargets().size() < possibleTargets;
int remainingTargets = this.minNumberOfTargets - targets.size();
if (remainingTargets == 0)
return true;
int count = 0;
for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId())) {
count++;
if (count >= remainingTargets)
return true;
}
}
return false;
}
@Override
@ -137,7 +149,7 @@ public class TargetPermanent<T extends TargetPermanent<T>> extends TargetObject<
Set<UUID> possibleTargets = new HashSet<UUID>();
MageObject targetSource = game.getObject(sourceId);
for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource)) {
possibleTargets.add(permanent.getId());
}
}
@ -148,8 +160,10 @@ public class TargetPermanent<T extends TargetPermanent<T>> extends TargetObject<
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<UUID>();
for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId())) {
possibleTargets.add(permanent.getId());
}
}
return possibleTargets;
}