mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
more optimizations
This commit is contained in:
parent
5097b0812b
commit
8287364f77
12 changed files with 146 additions and 30 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,21 +282,27 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
|
|||
|
||||
@Override
|
||||
public void bookmarkState() {
|
||||
saveState();
|
||||
logger.fine("Bookmarking state: " + gameStates.getSize());
|
||||
savedStates.push(gameStates.getSize() - 1);
|
||||
if (!simulation) {
|
||||
saveState();
|
||||
logger.fine("Bookmarking state: " + gameStates.getSize());
|
||||
savedStates.push(gameStates.getSize() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState() {
|
||||
GameState restore = gameStates.rollback(savedStates.pop());
|
||||
if (restore != null)
|
||||
state.restore(restore);
|
||||
if (!simulation) {
|
||||
GameState restore = gameStates.rollback(savedStates.pop());
|
||||
if (restore != null)
|
||||
state.restore(restore);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLastBookmark() {
|
||||
savedStates.pop();
|
||||
if (!simulation) {
|
||||
savedStates.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,7 +160,9 @@ 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)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
if (!targets.containsKey(permanent.getId())) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue