Package mage.player.ai

Source Code of mage.player.ai.SimulatedPlayer

/*
*  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.player.ai;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.PassAbility;
import mage.abilities.mana.ManaOptions;
import mage.choices.Choice;
import mage.filter.FilterAbility;
import mage.game.Game;
import mage.game.combat.Combat;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility;
import mage.target.Target;
import mage.util.Copier;
import mage.util.Logging;

/**
*
* @author BetaSteward_at_googlemail.com
*/
public class SimulatedPlayer extends ComputerPlayer<SimulatedPlayer> {

  private final static transient Logger logger = Logging.getLogger(SimulatedPlayer.class.getName());
  private boolean isSimulatedPlayer;
  private FilterAbility filter;
  private transient ConcurrentLinkedQueue<Ability> allActions;
  private static PassAbility pass = new PassAbility();

  public SimulatedPlayer(UUID id, boolean isSimulatedPlayer) {
    super(id);
    pass.setControllerId(playerId);
    this.isSimulatedPlayer = isSimulatedPlayer;
  }

  public SimulatedPlayer(final SimulatedPlayer player) {
    super(player);
    this.isSimulatedPlayer = player.isSimulatedPlayer;
    if (player.filter != null)
      this.filter = player.filter.copy();
  }

  @Override
  public SimulatedPlayer copy() {
    return new SimulatedPlayer(this);
  }

  public List<Ability> simulatePriority(Game game, FilterAbility filter) {
    allActions = new ConcurrentLinkedQueue<Ability>();
    Game sim = game.copy();
    this.filter = filter;

    simulateOptions(sim, pass);

    ArrayList<Ability> list = new ArrayList<Ability>(allActions);
    Collections.reverse(list);
    return list;
  }

  protected void simulateOptions(Game game, Ability previousActions) {
    allActions.add(previousActions);
    ManaOptions available = getManaAvailable(game);
    available.addMana(manaPool.getMana());
    List<Ability> playables = game.getPlayer(playerId).getPlayable(game, filter, available, isSimulatedPlayer);
    for (Ability ability: playables) {
      List<Ability> options = game.getPlayer(playerId).getPlayableOptions(ability, game);
      if (options.size() == 0) {
        allActions.add(ability);
//        simulateAction(game, previousActions, ability);
      }
      else {
//        ExecutorService simulationExecutor = Executors.newFixedThreadPool(4);
        for (Ability option: options) {
          allActions.add(option);
//          SimulationWorker worker = new SimulationWorker(game, this, previousActions, option);
//          simulationExecutor.submit(worker);
        }
//        simulationExecutor.shutdown();
//        while(!simulationExecutor.isTerminated()) {}
      }
    }
  }

//  protected void simulateAction(Game game, SimulatedAction previousActions, Ability action) {
//    List<Ability> actions = new ArrayList<Ability>(previousActions.getAbilities());
//    actions.add(action);
//    Game sim = game.copy();
//    if (sim.getPlayer(playerId).activateAbility((ActivatedAbility) action.copy(), sim)) {
//      sim.applyEffects();
//      sim.getPlayers().resetPassed();
//      allActions.add(new SimulatedAction(sim, actions));
//    }
//  }

  public List<Combat> addAttackers(Game game) {
    Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
    //useful only for two player games - will only attack first opponent
    UUID defenderId = game.getOpponents(playerId).iterator().next();
    List<Permanent> attackersList = super.getAvailableAttackers(game);
    //use binary digits to calculate powerset of attackers
    int powerElements = (int) Math.pow(2, attackersList.size());
    StringBuilder binary = new StringBuilder();
    for (int i = powerElements - 1; i >= 0; i--) {
      Game sim = game.copy();
      binary.setLength(0);
      binary.append(Integer.toBinaryString(i));
      while (binary.length() < attackersList.size()) {
        binary.insert(0, "0");
      }
      for (int j = 0; j < attackersList.size(); j++) {
        if (binary.charAt(j) == '1')
          sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, sim);
      }
      if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null) {
        logger.fine("simulating -- found redundant attack combination");
      }
      else if (logger.isLoggable(Level.FINE)) {
        logger.fine("simulating -- attack:" + sim.getCombat().getGroups().size());
      }
    }
    return new ArrayList<Combat>(engagements.values());
  }

  public List<Combat> addBlockers(Game game) {
    Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
    int numGroups = game.getCombat().getGroups().size();
    if (numGroups == 0) return new ArrayList<Combat>();

    //add a node with no blockers
    Game sim = game.copy();
    engagements.put(sim.getCombat().getValue(sim), sim.getCombat());
    sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId));

    List<Permanent> blockers = getAvailableBlockers(game);
    addBlocker(game, blockers, engagements);

    return new ArrayList<Combat>(engagements.values());
  }

  protected void addBlocker(Game game, List<Permanent> blockers, Map<Integer, Combat> engagements) {
    if (blockers.size() == 0)
      return;
    int numGroups = game.getCombat().getGroups().size();
    //try to block each attacker with each potential blocker
    Permanent blocker = blockers.get(0);
    if (logger.isLoggable(Level.FINE))
      logger.fine("simulating -- block:" + blocker);
    List<Permanent> remaining = remove(blockers, blocker);
    for (int i = 0; i < numGroups; i++) {
      if (game.getCombat().getGroups().get(i).canBlock(blocker, game)) {
        Game sim = game.copy();
        sim.getCombat().getGroups().get(i).addBlocker(blocker.getId(), playerId, sim);
        if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null)
          logger.fine("simulating -- found redundant block combination");
        addBlocker(sim, remaining, engagements)// and recurse minus the used blocker
      }
    }
    addBlocker(game, remaining, engagements);
  }

  @Override
  public boolean triggerAbility(TriggeredAbility source, Game game) {
    Ability ability = source.copy();
    List<Ability> options = getPlayableOptions(ability, game);
    if (options.size() == 0) {
      if (logger.isLoggable(Level.FINE))
        logger.fine("simulating -- triggered ability:" + ability);
      game.getStack().push(new StackAbility(ability, playerId));
      ability.activate(game, false);
      game.applyEffects();
      game.getPlayers().resetPassed();
    }
    else {
      SimulationNode parent = (SimulationNode) game.getCustomData();
      int depth = parent.getDepth() - 1;
      if (depth == 0) return true;
      logger.fine("simulating -- triggered ability - adding children:" + options.size());
      for (Ability option: options) {
        addAbilityNode(parent, option, depth, game);
      }
    }
    return true;
  }

  protected void addAbilityNode(SimulationNode parent, Ability ability, int depth, Game game) {
    Game sim = game.copy();
    sim.getStack().push(new StackAbility(ability, playerId));
    ability.activate(sim, false);
    sim.applyEffects();
    SimulationNode newNode = new SimulationNode(sim, depth, playerId);
    logger.fine("simulating -- node #:" + SimulationNode.getCount() + " triggered ability option");
    for (Target target: ability.getTargets()) {
      for (UUID targetId: target.getTargets()) {
        newNode.getTargets().add(targetId);
      }
    }
    for (Choice choice: ability.getChoices()) {
      newNode.getChoices().add(choice.getChoice());
    }
    parent.children.add(newNode);
  }

  @Override
  public void priority(Game game) {
    //should never get here
  }

}
TOP

Related Classes of mage.player.ai.SimulatedPlayer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.