Error handling and thread timeout added to simulated matches to allow large AI tournaments without infinite length games due to loops. AI tournaments should now always finish - if the matches take too long they are scored as a draw.

This commit is contained in:
austinio7116
2018-02-18 18:07:57 +00:00
committed by maustin
parent 52ae852953
commit 13560e3b53
2 changed files with 75 additions and 8 deletions

View File

@@ -3,9 +3,12 @@ package forge.view;
import java.io.File;
import java.io.FilenameFilter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import forge.LobbyPlayer;
import forge.deck.DeckGroup;
import forge.game.*;
import forge.properties.ForgeConstants;
import forge.tournament.system.*;
import forge.util.TextUtil;
@@ -15,12 +18,6 @@ import org.apache.commons.lang3.time.StopWatch;
import forge.deck.Deck;
import forge.deck.io.DeckSerializer;
import forge.game.Game;
import forge.game.GameLogEntry;
import forge.game.GameRules;
import forge.game.GameType;
import forge.game.GameLogEntryType;
import forge.game.Match;
import forge.game.player.RegisteredPlayer;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
@@ -161,14 +158,38 @@ public class SimulateMatch {
System.out.println("\tq - Quiet flag. Output just the game result, not the entire game log.");
}
private static void simulateSingleMatch(Match mc, int iGame, boolean outputGamelog) {
StopWatch sw = new StopWatch();
sw.start();
Game g1 = mc.createGame();
// will run match in the same thread
mc.startGame(g1);
sw.stop();
long startTime = System.currentTimeMillis();
try {
TimeLimitedCodeBlock.runWithTimeout(new Runnable() {
@Override
public void run() {
mc.startGame(g1);
sw.stop();
}
}, 120, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
System.out.println("Stopping slow match as draw");
g1.setGameOver(GameEndReason.Draw);
sw.stop();
}catch (Exception e){
e.printStackTrace();
g1.setGameOver(GameEndReason.Draw);
sw.stop();
}catch(StackOverflowError e){
g1.setGameOver(GameEndReason.Draw);
sw.stop();
}
List<GameLogEntry> log;
if (outputGamelog) {

View File

@@ -0,0 +1,46 @@
package forge.view;
import java.util.concurrent.*;
/**
* Created by maustin on 08/02/2018.
*/
public class TimeLimitedCodeBlock {
public static void runWithTimeout(final Runnable runnable, long timeout, TimeUnit timeUnit) throws Exception {
runWithTimeout(new Callable<Object>() {
@Override
public Object call() throws Exception {
runnable.run();
return null;
}
}, timeout, timeUnit);
}
public static <T> T runWithTimeout(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
final ExecutorService executor = Executors.newSingleThreadExecutor();
final Future<T> future = executor.submit(callable);
executor.shutdown(); // This does not cancel the already-scheduled task.
try {
return future.get(timeout, timeUnit);
}
catch (TimeoutException e) {
//remove this if you do not want to cancel the job in progress
//or set the argument to 'false' if you do not want to interrupt the thread
future.cancel(true);
throw e;
}
catch (ExecutionException e) {
//unwrap the root cause
Throwable t = e.getCause();
if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof Exception) {
throw (Exception) t;
} else {
throw new IllegalStateException(t);
}
}
}
}