AI, tests: added stability tests to make sure AI simulations can process errors and freezes (part of #13638, #13766);

This commit is contained in:
Oleg Agafonov 2025-06-28 22:51:34 +04:00
parent 85c04bca59
commit c3a0c731d6
12 changed files with 298 additions and 20 deletions

View file

@ -114,6 +114,13 @@ public class ComputerPlayer6 extends ComputerPlayer {
this.actionCache = player.actionCache;
}
/**
* Change simulation timeout - used for AI stability tests only
*/
public void setMaxThinkTimeSecs(int maxThinkTimeSecs) {
this.maxThinkTimeSecs = maxThinkTimeSecs;
}
@Override
public ComputerPlayer6 copy() {
return new ComputerPlayer6(this);
@ -431,6 +438,8 @@ public class ComputerPlayer6 extends ComputerPlayer {
* @return
*/
protected Integer addActionsTimed() {
// TODO: all actions added and calculated one by one,
// multithreading do not supported here
// run new game simulation in parallel thread
FutureTask<Integer> task = new FutureTask<>(() -> addActions(root, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE));
threadPoolSimulations.execute(task);
@ -446,15 +455,15 @@ public class ComputerPlayer6 extends ComputerPlayer {
}
} catch (TimeoutException | InterruptedException e) {
// AI thinks too long
logger.info("ai simulating - timed out");
logger.warn("AI player thinks too long - " + getName() + " - " + root.game);
task.cancel(true);
} catch (ExecutionException e) {
// game error
logger.error("AI simulation catch game error: " + e, e);
logger.error("AI player catch game error in simulation - " + getName() + " - " + root.game + ": " + e, e);
task.cancel(true);
// real games: must catch and log
// unit tests: must raise again for fast fail
if (this.isTestsMode()) {
if (this.isTestMode() && this.isFastFailInTestMode()) {
throw new IllegalStateException("One of the simulated games raise the error: " + e, e);
}
} catch (Throwable e) {

View file

@ -142,7 +142,8 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
}
}
} else {
logger.info('[' + game.getPlayer(playerId).getName() + "][pre] Action: skip");
// nothing to choose or freeze/infinite game
logger.info("AI player can't find next action: " + getName());
}
} else {
logger.debug("Next Action exists!");

View file

@ -52,7 +52,7 @@ public class ComputerPlayer extends PlayerImpl {
protected static final int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are available
// debug only: set TRUE to debug simulation's code/games (on false sim thread will be stopped after few secs by timeout)
protected static final boolean COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS = true; // DebugUtil.AI_ENABLE_DEBUG_MODE;
public static final boolean COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS = false; // DebugUtil.AI_ENABLE_DEBUG_MODE;
// AI agents uses game simulation thread for all calcs and it's high CPU consumption
// More AI threads - more parallel AI games can be calculate
@ -64,7 +64,7 @@ public class ComputerPlayer extends PlayerImpl {
// * use yours CPU cores for best performance
// TODO: add server config to control max AI threads (with CPU cores by default)
// TODO: rework AI implementation to use multiple sims calculation instead one by one
final static int COMPUTER_MAX_THREADS_FOR_SIMULATIONS = 1;//DebugUtil.AI_ENABLE_DEBUG_MODE ? 1 : 5;
final static int COMPUTER_MAX_THREADS_FOR_SIMULATIONS = 5;//DebugUtil.AI_ENABLE_DEBUG_MODE ? 1 : 5;
// remember picked cards for better draft choices
@ -104,7 +104,7 @@ public class ComputerPlayer extends PlayerImpl {
@Override
public boolean chooseMulligan(Game game) {
if (hand.size() < 6
|| isTestsMode() // ignore mulligan in tests
|| isTestMode() // ignore mulligan in tests
|| game.getClass().getName().contains("Momir") // ignore mulligan in Momir games
) {
return false;

View file

@ -196,7 +196,7 @@ public class ComputerPlayerMCTS extends ComputerPlayer {
} catch (ExecutionException e) {
// real games: must catch and log
// unit tests: must raise again for fast fail
if (this.isTestsMode()) {
if (this.isTestMode() && this.isFastFailInTestMode()) {
throw new IllegalStateException("One of the simulated games raise the error: " + e, e);
}
}