1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-08 01:01:04 -09:00

- Added some Dragon Maze cards. Improved AI attacking with flying creatures.

This commit is contained in:
jeffwadsworth 2013-05-01 16:00:49 -05:00
parent 818ac06b88
commit ad99fcad23
5 changed files with 388 additions and 27 deletions
Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai
Mage.Sets/src/mage/sets/dragonsmaze

View file

@ -63,7 +63,6 @@ import java.io.File;
import java.util.*;
import java.util.concurrent.*;
/**
*
* @author nantuko
@ -85,7 +84,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
private List<String> suggested = new ArrayList<String>();
protected Set<String> actionCache;
private static final List<TreeOptimizer> optimizers = new ArrayList<TreeOptimizer>();
protected int lastLoggedTurn = 0;
static {
@ -327,7 +325,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
}
protected int minimaxAB(SimulationNode2 node, int depth, int alpha, int beta) {
logger.trace("Sim minimaxAB ["+depth+"] -- a: " + alpha + " b: " + beta + " <" + (node != null ? node.getScore() : "null")+">");
logger.trace("Sim minimaxAB [" + depth + "] -- a: " + alpha + " b: " + beta + " <" + (node != null ? node.getScore() : "null") + ">");
UUID currentPlayerId = node.getGame().getPlayerList().get();
SimulationNode2 bestChild = null;
for (SimulationNode2 child : node.getChildren()) {
@ -424,12 +422,11 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
/**
* Base call for simulation of AI actions
*
*
* @return
*/
protected Integer addActionsTimed() {
FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return addActions(root, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE);
@ -457,8 +454,8 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
}
protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) {
if (logger.isInfoEnabled() && node !=null && node.getAbilities() != null && !node.getAbilities().toString().equals("[Pass]")){
logger.info("Add actions [" + depth +"] " + (node.getAbilities().toString()+ " -- a: " + alpha + " b: " + beta));
if (logger.isInfoEnabled() && node != null && node.getAbilities() != null && !node.getAbilities().toString().equals("[Pass]")) {
logger.info("Add actions [" + depth + "] " + (node.getAbilities().toString() + " -- a: " + alpha + " b: " + beta));
}
Game game = node.getGame();
int val;
@ -546,23 +543,23 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
sim.checkStateAndTriggered();
int val = addActions(newNode, depth - 1, alpha, beta);
if (logger.isInfoEnabled() && depth == maxDepth) {
StringBuilder sb = new StringBuilder("Sim Prio [").append(depth).append("] #").append(counter)
.append(" <").append(val).append("> (").append(action)
.append(action.isModal() ? " Mode = "+action.getModes().getMode().toString():"")
.append(action.isModal() ? " Mode = " + action.getModes().getMode().toString() : "")
.append(listTargets(game, action.getTargets())).append(")")
.append(logger.isTraceEnabled()?" #" +newNode.hashCode():"");
.append(logger.isTraceEnabled() ? " #" + newNode.hashCode() : "");
SimulationNode2 logNode = newNode;
while (logNode.getChildren() != null && logNode.getChildren().size()>0) {
while (logNode.getChildren() != null && logNode.getChildren().size() > 0) {
logNode = logNode.getChildren().get(0);
if (logNode.getAbilities() != null && logNode.getAbilities().size()>0) {
if (logNode.getAbilities() != null && logNode.getAbilities().size() > 0) {
sb.append(" -> [").append(logNode.getDepth()).append("]").append(logNode.getAbilities().toString()).append("<").append(logNode.getScore()).append(">");
}
}
logger.info(sb);
}
if (currentPlayer.getId().equals(playerId)) {
if (val > alpha) {
alpha = val;
@ -622,7 +619,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
node.children.clear();
node.children.add(bestNode);
node.setScore(bestNode.getScore());
if (logger.isTraceEnabled() && !bestNode.getAbilities().toString().equals("[Pass]") ) {
if (logger.isTraceEnabled() && !bestNode.getAbilities().toString().equals("[Pass]")) {
logger.trace(new StringBuilder("Sim Prio [").append(depth).append("] -- Set after (depth=").append(depth).append(") <").append(bestNode.getScore()).append("> ").append(bestNode.getAbilities().toString()).toString());
}
}
@ -656,7 +653,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
optimizer.optimize(game, allActions);
}
Collections.sort(allActions, new Comparator<Ability>() {
@Override
public int compare(Ability ability, Ability ability1) {
String rule = ability.toString();
@ -1105,7 +1101,6 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
&& attacker.getToughness().getValue() <= blocker.getPower().getValue()) {
safeToAttack = false;
}
if (attacker.getToughness().getValue() == blocker.getPower().getValue()
&& attacker.getPower().getValue() == blocker.getToughness().getValue()) {
if (attackerValue > blockerValue
@ -1120,13 +1115,18 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
safeToAttack = false;
}
}
}
if (attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())
|| attacker.getAbilities().contains(new IndestructibleAbility())) {
safeToAttack = true;
}
if (attacker.getPower().getValue() == 0) {
safeToAttack = false;
if (attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())
|| attacker.getAbilities().contains(new IndestructibleAbility())) {
safeToAttack = true;
}
if (attacker.getAbilities().containsKey(FlyingAbility.getInstance().getId())
&& !blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId())
&& !blocker.getAbilities().containsKey(ReachAbility.getInstance().getId())) {
safeToAttack = true;
}
if (attacker.getPower().getValue() == 0) {
safeToAttack = false;
}
}
if (safeToAttack) {
attackingPlayer.declareAttacker(attacker.getId(), defenderId, game);
@ -1361,14 +1361,13 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
protected String listTargets(Game game, Targets targets) {
StringBuilder sb = new StringBuilder();
if (targets != null) {
for (Target target: targets) {
for (Target target : targets) {
sb.append("[").append(target.getTargetedName(game)).append("]");
}
if (sb.length()>0) {
sb.insert(0," targeting ");
if (sb.length() > 0) {
sb.insert(0, " targeting ");
}
}
return sb.toString();
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.dragonsmaze;
import java.util.UUID;
import mage.Constants;
import mage.Constants.CardType;
import mage.Constants.Rarity;
import mage.Constants.Zone;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.cards.CardImpl;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author jeffwadsworth
*/
public class SavagebornHydra extends CardImpl<SavagebornHydra> {
public SavagebornHydra(UUID ownerId) {
super(ownerId, 100, "Savageborn Hydra", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{X}{R}{G}");
this.expansionSetCode = "DGM";
this.subtype.add("Hydra");
this.color.setRed(true);
this.color.setGreen(true);
this.power = new MageInt(0);
this.toughness = new MageInt(0);
// Double strike
this.addAbility(DoubleStrikeAbility.getInstance());
// Savageborn Hydra enters the battlefield with X +1/+1 counters on it.
this.addAbility(new EntersBattlefieldAbility(new SavageBornHydraEffect(), true));
// {1}{RG}: Put a +1/+1 counter on Savageborn Hydra. Activate this ability only any time you could cast a sorcery.
this.addAbility(new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl("{1}{R/G}")));
}
public SavagebornHydra(final SavagebornHydra card) {
super(card);
}
@Override
public SavagebornHydra copy() {
return new SavagebornHydra(this);
}
}
class SavageBornHydraEffect extends OneShotEffect<SavageBornHydraEffect> {
public SavageBornHydraEffect() {
super(Constants.Outcome.BoostCreature);
}
public SavageBornHydraEffect(final SavageBornHydraEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
Object obj = getValue(mage.abilities.effects.EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY);
if (obj != null && obj instanceof SpellAbility) {
int amount = ((SpellAbility)obj).getManaCostsToPay().getX();
if (amount > 0) {
permanent.addCounters(CounterType.P1P1.createInstance(amount), game);
}
}
}
return true;
}
@Override
public SavageBornHydraEffect copy() {
return new SavageBornHydraEffect(this);
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.dragonsmaze;
import java.util.UUID;
import mage.Constants;
import mage.Constants.CardType;
import mage.Constants.Rarity;
import mage.Constants.TargetController;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author jeffwadsworth
*/
public class SpeciesGorger extends CardImpl<SpeciesGorger> {
public SpeciesGorger(UUID ownerId) {
super(ownerId, 105, "Species Gorger", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{G}{U}");
this.expansionSetCode = "DGM";
this.subtype.add("Frog");
this.subtype.add("Beast");
this.color.setBlue(true);
this.color.setGreen(true);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// At the beginning of your upkeep, return a creature you control to its owner's hand.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Constants.Zone.BATTLEFIELD, new ReturnToHandChooseEffect(), TargetController.YOU, false));
}
public SpeciesGorger(final SpeciesGorger card) {
super(card);
}
@Override
public SpeciesGorger copy() {
return new SpeciesGorger(this);
}
}
class ReturnToHandChooseEffect extends OneShotEffect<ReturnToHandChooseEffect> {
public ReturnToHandChooseEffect() {
super(Constants.Outcome.ReturnToHand);
this.staticText = "return a creature you control to its owner's hand";
}
public ReturnToHandChooseEffect(final ReturnToHandChooseEffect effect) {
super(effect);
}
@Override
public ReturnToHandChooseEffect copy() {
return new ReturnToHandChooseEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent();
if (player.choose(this.outcome, target, source.getSourceId(), game)) {
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
return permanent.moveToZone(Constants.Zone.HAND, source.getId(), game, false);
}
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.dragonsmaze;
import java.util.UUID;
import mage.Constants.CardType;
import mage.Constants.Rarity;
import mage.MageInt;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
/**
*
* @author jeffwadsworth
*/
public class SpikeJester extends CardImpl<SpikeJester> {
public SpikeJester(UUID ownerId) {
super(ownerId, 106, "Spike Jester", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{B}{R}");
this.expansionSetCode = "DGM";
this.subtype.add("Goblin");
this.subtype.add("Warrior");
this.color.setRed(true);
this.color.setBlack(true);
this.power = new MageInt(3);
this.toughness = new MageInt(1);
// Haste
this.addAbility(HasteAbility.getInstance());
}
public SpikeJester(final SpikeJester card) {
super(card);
}
@Override
public SpikeJester copy() {
return new SpikeJester(this);
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.dragonsmaze;
import java.util.UUID;
import mage.Constants.CardType;
import mage.Constants.Duration;
import mage.Constants.Rarity;
import mage.MageInt;
import mage.abilities.effects.common.continious.BoostSourceEffect;
import mage.abilities.keyword.BattalionAbility;
import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.CardImpl;
/**
*
* @author jeffwadsworth
*/
public class TajicBladeOfTheLegion extends CardImpl<TajicBladeOfTheLegion> {
public TajicBladeOfTheLegion(UUID ownerId) {
super(ownerId, 107, "Tajic, Blade of the Legion", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{W}");
this.expansionSetCode = "DGM";
this.supertype.add("Legendary");
this.subtype.add("Human");
this.subtype.add("Soldier");
this.color.setRed(true);
this.color.setWhite(true);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Tajic, Blade of the Legion is indestructible.
this.addAbility(new IndestructibleAbility());
// Battalion - Whenever Tajic and at least two other creatures attack, Tajic gets +5/+5 until end of turn.
this.addAbility(new BattalionAbility(new BoostSourceEffect(5, 5, Duration.EndOfTurn)));
}
public TajicBladeOfTheLegion(final TajicBladeOfTheLegion card) {
super(card);
}
@Override
public TajicBladeOfTheLegion copy() {
return new TajicBladeOfTheLegion(this);
}
}