package net.demilich.metastone.game.behaviour;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.actions.GameAction;
import net.demilich.metastone.game.cards.Card;
public class FlatMonteCarlo extends Behaviour {
private final static Logger logger = LoggerFactory.getLogger(FlatMonteCarlo.class);
private int iterations;
public FlatMonteCarlo(int iterations) {
this.iterations = iterations;
}
private GameAction getBestAction(HashMap<GameAction, Double> actionScores) {
GameAction bestAction = null;
double bestScore = Integer.MIN_VALUE;
for (GameAction actionEntry : actionScores.keySet()) {
double score = actionScores.get(actionEntry);
if (score > bestScore) {
bestAction = actionEntry;
bestScore = score;
}
}
logger.debug("Best action determined by MonteCarlo: " + bestAction.getActionType());
return bestAction;
}
@Override
public String getName() {
return "Flat Monte-Carlo " + iterations;
}
@Override
public List<Card> mulligan(GameContext context, Player player, List<Card> cards) {
List<Card> discardedCards = new ArrayList<Card>();
for (Card card : cards) {
if (card.getBaseManaCost() >= 4) {
discardedCards.add(card);
}
}
return discardedCards;
}
private int playRandomUntilEnd(GameContext simulation, int playerId) {
for (Player player : simulation.getPlayers()) {
player.setBehaviour(new PlayRandomBehaviour());
}
simulation.playFromState();
return simulation.getWinningPlayerId() == playerId ? 1 : 0;
}
@Override
public GameAction requestAction(GameContext context, Player player, List<GameAction> validActions) {
if (validActions.size() == 1) {
return validActions.get(0);
}
HashMap<GameAction, Double> actionScores = new HashMap<>();
for (GameAction gameAction : validActions) {
double score = simulate(context, player.getId(), gameAction);
actionScores.put(gameAction, score);
logger.debug("Action {} gets score of {}", gameAction.getActionType(), score);
}
GameAction bestAction = getBestAction(actionScores);
return bestAction;
}
private double simulate(GameContext context, int playerId, GameAction action) {
GameContext simulation = context.clone();
simulation.getLogic().performGameAction(simulation.getActivePlayer().getId(), action);
if (simulation.gameDecided()) {
return simulation.getWinningPlayerId() == playerId ? 1 : 0;
}
double score = 0;
for (int i = 0; i < iterations; i++) {
score += playRandomUntilEnd(simulation.clone(), playerId);
}
return score;
}
}