package net.demilich.metastone.gui.battleofdecks;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.demilich.nittygrittymvc.SimpleCommand;
import net.demilich.nittygrittymvc.interfaces.INotification;
import net.demilich.metastone.GameNotification;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.behaviour.IBehaviour;
import net.demilich.metastone.game.cards.CardSet;
import net.demilich.metastone.game.decks.Deck;
import net.demilich.metastone.game.decks.DeckFormat;
import net.demilich.metastone.game.logic.GameLogic;
import net.demilich.metastone.game.gameconfig.PlayerConfig;
public class StartBattleOfDecksCommand extends SimpleCommand<GameNotification> {
private class PlayGameTask implements Callable<Void> {
private final PlayerConfig player1Config;
private final PlayerConfig player2Config;
private final BattleBatchResult batchResult;
public PlayGameTask(Deck deck1, Deck deck2, IBehaviour behaviour, BattleBatchResult batchResult) {
this.player1Config = new PlayerConfig(deck1, behaviour);
player1Config.setName("Player 1");
this.player2Config = new PlayerConfig(deck2, behaviour);
player2Config.setName("Player 2");
this.batchResult = batchResult;
}
@Override
public Void call() throws Exception {
Player player1 = new Player(player1Config);
Player player2 = new Player(player2Config);
DeckFormat deckFormat = new DeckFormat();
for (CardSet set : CardSet.values()) {
deckFormat.addSet(set);
}
GameContext newGame = new GameContext(player1, player2, new GameLogic(), deckFormat);
newGame.play();
batchResult.onGameEnded(newGame);
result.onGameEnded(newGame);
periodicUpdate();
newGame.dispose();
return null;
}
}
private static Logger logger = LoggerFactory.getLogger(StartBattleOfDecksCommand.class);
private BattleResult result;
private long lastUpdate;
@Override
public void execute(INotification<GameNotification> notification) {
BattleConfig battleConfig = (BattleConfig) notification.getBody();
result = new BattleResult(battleConfig.getNumberOfGames());
Thread t = new Thread(new Runnable() {
@Override
public void run() {
logger.info("Battle of Decks started");
ExecutorService executor = Executors.newWorkStealingPool();
List<Future<Void>> futures = new ArrayList<Future<Void>>();
HashSet<Deck> processedDecks = new HashSet<>();
for (Deck deck1 : battleConfig.getDecks()) {
processedDecks.add(deck1);
for (Deck deck2 : battleConfig.getDecks()) {
if (processedDecks.contains(deck2)) {
continue;
}
BattleBatchResult batchResult = new BattleBatchResult(deck1, deck2, battleConfig.getNumberOfGames());
result.addBatchResult(batchResult);
for (int i = 0; i < battleConfig.getNumberOfGames(); i++) {
PlayGameTask task = new PlayGameTask(deck1, deck2, battleConfig.getBehaviour(), batchResult);
Future<Void> future = executor.submit(task);
futures.add(future);
}
}
}
executor.shutdown();
boolean completed = false;
while (!completed) {
completed = true;
for (Future<Void> future : futures) {
if (!future.isDone()) {
completed = false;
continue;
}
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
logger.error(ExceptionUtils.getStackTrace(e));
e.printStackTrace();
System.exit(-1);
}
}
futures.removeIf(future -> future.isDone());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// getFacade().sendNotification(GameNotification.SIMULATION_RESULT,
// result);
logger.info("Battle of Decks finished");
}
});
t.setDaemon(true);
t.start();
}
private void periodicUpdate() {
if (System.currentTimeMillis() - lastUpdate > 1000) {
sendNotification(GameNotification.BATTLE_OF_DECKS_PROGRESS_UPDATE, result);
lastUpdate = System.currentTimeMillis();
}
}
}