61 auto currentTime = std::chrono::system_clock::now();
62 _jobId = std::chrono::duration_cast<std::chrono::seconds>(currentTime.time_since_epoch()).count();
66 auto configRemaining = config;
69 auto driverConfig = jaffarCommon::json::popObject(configRemaining,
"Driver Configuration");
72 _endOnFirstWinState = jaffarCommon::json::popBoolean(driverConfig,
"End On First Win State");
75 _maxSteps = jaffarCommon::json::popNumber<uint32_t>(driverConfig,
"Max Steps");
78 if (
auto* value = std::getenv(
"JAFFAR_DRIVER_OVERRIDE_DRIVER_MAX_STEP"))
_maxSteps = std::stoul(value);
81 auto saveIntermediateResultsJs = jaffarCommon::json::popObject(driverConfig,
"Save Intermediate Results");
86 jaffarCommon::json::checkEmpty(saveIntermediateResultsJs,
"Driver Configuration > Save Intermediate Results");
95 if (driverConfig.contains(
"Reference Reward Floor"))
97 auto refJs = jaffarCommon::json::popObject(driverConfig,
"Reference Reward Floor");
100 const auto refPath = jaffarCommon::json::popString(refJs,
"Path");
101 jaffarCommon::json::checkEmpty(refJs,
"Driver Configuration > Reference Reward Floor");
108 std::ifstream f(refPath);
109 if (f.good() ==
false) JAFFAR_THROW_RUNTIME(
"[ERROR] Could not open 'Reference Reward Floor' > 'Path': '%s'\n", refPath.c_str());
116 jaffarCommon::json::checkEmpty(driverConfig,
"Driver Configuration");
119 auto emulatorConfig = jaffarCommon::json::popObject(configRemaining,
"Emulator Configuration");
120 auto gameConfig = jaffarCommon::json::popObject(configRemaining,
"Game Configuration");
121 auto runnerConfig = jaffarCommon::json::popObject(configRemaining,
"Runner Configuration");
122 auto engineConfig = jaffarCommon::json::popObject(configRemaining,
"Engine Configuration");
125 jaffarCommon::json::checkEmpty(configRemaining,
"configuration root");
131 _engine = std::make_unique<Engine>(emulatorConfig, gameConfig, runnerConfig, engineConfig);
188 jaffarCommon::logger::initializeTerminal();
194 std::thread intermediateResultSaverThread;
208 if (
_engine->getStateCount() == 0)
230 jaffarCommon::logger::log(
"[J+] Best (%.6f) fell below reference floor (%.6f, tol %.4f) at step %lu by %.6f -- cancelling.\n",
_bestStateFloorReward,
243 const size_t ihCeiling =
_engine->getInputHistoryMaxMemoryBytes();
246 const size_t ihNow =
_engine->getInputHistoryApproxMemoryBytes();
247 const bool exhausted =
_engine->isInputHistoryExhausted();
250 const double GB = 1024.0 * 1024.0 * 1024.0;
251 jaffarCommon::logger::log(
"[J+] Input-history trie at %.1f / %.1f GB (%.0f%% of its hard ceiling)%s at step %lu -- stopping "
252 "gracefully. The Trie node pool grows ~ live-states x depth and cannot be enlarged past RAM; switch "
253 "Store Input History Type to \"Raw\" (bounded by 'State Database/Max Size (Mb)'), or lower the State "
254 "DB size so fewer live states slow the trie's growth.\n",
255 (
double)ihNow / GB, (
double)ihCeiling / GB, 100.0 * (
double)ihNow / (
double)ihCeiling, exhausted ?
" (pool exhausted)" :
"",
_currentStep);
285 jaffarCommon::logger::finalizeTerminal();
306 auto manualSaveSolution =
_engine->getManualSaveSolution();
308 if (manualSaveSolution.path !=
"")
312 _runner->setStepCount(manualSaveSolution.stepCount);
313 _engine->getStateDb()->loadStateIntoRunner(*
_runner, manualSaveSolution.stateData);
316 std::string solutionData =
_runner->getInputHistoryString();
317 jaffarCommon::file::saveStringToFile(solutionData, manualSaveSolution.path);
333 std::string jobSuffix = std::string(
".") + std::to_string(
_jobId);
334 std::string stepSuffix = std::string(
".") + std::to_string(
_currentStep);
358 std::string jobSuffix = std::string(
".") + std::to_string(
_jobId);
380 auto lastSaveTime = jaffarCommon::timing::now();
389 auto currentTime = jaffarCommon::timing::now();
390 auto timeElapsedSinceLastSave = jaffarCommon::timing::timeDeltaSeconds(currentTime, lastSaveTime);
400 lastSaveTime = jaffarCommon::timing::now();
415 if (
_engine->getStateDb()->getStateCount() == 0)
return;
421 auto worstState =
_engine->getStateDb()->getWorstState();
462 auto bestState =
_engine->getStateDb()->getBestState();
469 if (
_engine->getWinStatesFound() > 0)
472 auto winStateEntry =
_engine->getStepBestWinState();
516 jaffarCommon::logger::clearTerminal();
519 jaffarCommon::logger::log(
"[J+] Job Id: %lu\n",
_jobId);
520 jaffarCommon::logger::log(
"[J+] Script File: '%s'\n",
_configFilePath.c_str());
521 jaffarCommon::logger::log(
"[J+] Emulator Name: '%s'\n",
_runner->getGame()->getEmulator()->getName().c_str());
522 jaffarCommon::logger::log(
"[J+] Game Name: '%s'\n",
_runner->getGame()->getName().c_str());
523 jaffarCommon::logger::log(
"[J+] Current Step #: %lu",
_currentStep);
525 jaffarCommon::logger::log(
"\n");
543 jaffarCommon::logger::log(
"[J+] Reference Reward (Best - Ref): (none: step beyond reference trace)\n");
547 jaffarCommon::logger::log(
"[J+] Engine Information: \n");
555 jaffarCommon::logger::log(
"[J+] Runner Information (Best State): \n");
557 jaffarCommon::logger::log(
"[J+] Game Information (Best State): \n");
558 _runner->getGame()->printInfo();
559 jaffarCommon::logger::log(
"[J+] Emulator Information (Best State): \n");
560 _runner->getGame()->getEmulator()->printInfo();
563 jaffarCommon::logger::log(
"[J+] --------------------------------------------------------------\n");
566 jaffarCommon::logger::refreshTerminal();
575 static std::unique_ptr<Driver>
getDriver(
const std::string& configFilePath,
const nlohmann::json& config)
578 auto d = std::make_unique<Driver>(configFilePath, config);
Owns and runs the engine's step loop and reports how the run ended.
std::mutex _updateIntermediateResultMutex
Guards intermediate result storage between the main and saver threads.
size_t _bestWinStateStepCount
Depth of the best win state (recorded at capture; the count is not stored per-state).
float _saveIntermediateFrequency
Minimum interval, in seconds, between intermediate result saves.
std::string _bestSolutionStorage
Storage for the current best solution's input history.
size_t _winStatesFound
Total number of win states found so far.
float _worstStateReward
Reward for the worst state found so far.
int run()
Runs the engine's step loop until a termination condition is met.
size_t getCurrentStep()
Returns the current step counter.
exitReason_t
Reason the run loop terminated, returned by run.
@ outOfStates
Engine ran out of states.
@ bestBelowReference
The best state's reward fell below the reference reward floor at this step.
@ winStateFound
Found a win state.
@ maximumStepReached
Maximum step reached.
@ inputHistoryNearCapacity
The shared input-history trie neared/hit its hard memory ceiling.
size_t _jobId
Job identifier (derived from system time) distinguishing intermediate values between jobs.
std::string _bestStateStorage
Storage for the current best (win or otherwise) state.
std::unique_ptr< Runner > _runner
Runner used for printing information and saving partial results.
float _bestStateFloorReward
Un-biased progress (position) reward of the best state; used for the Reference Reward Floor compariso...
float _referenceFloorTolerance
Allowed shortfall of best below the reference per step.
std::vector< float > _referenceReward
Per-step reference reward floor (index = step).
size_t _currentStep
Counter for the number of steps performed; the initial state counts as step zero.
void storeManualSaveSolution()
Saves a solution explicitly requested by the engine, if any.
~Driver()
Destroys the driver.
void updateWorstState()
Refreshes the tracked worst state, its solution, and its reward.
__volatile__ bool _hasFinished
Internal flag indicating the driver has finished.
bool _referenceFloorEnabled
Whether the reference reward floor cancel is active.
static std::unique_ptr< Driver > getDriver(const std::string &configFilePath, const nlohmann::json &config)
Factory that constructs a driver from configuration.
float _bestStateReward
Ranking reward (magnet-biased) for the best state found so far; drives eviction/display.
void printInfo()
Prints the current state of execution to the logger.
std::string _saveIntermediateBestSolutionPath
Path to store the best solution found so far.
bool _endOnFirstWinState
Whether to end the run on the first win state found.
size_t _maxSteps
Maximum number of steps (zero = not established).
void updateBestState()
Refreshes the tracked best state, its solution, and its reward.
std::unique_ptr< Engine > _engine
Pointer to the internal Jaffar engine.
void initialize()
Resets the execution back to the starting point.
void saveBestStateInformation()
Writes the current best solution to file, under the mutex.
std::string _worstSolutionStorage
Storage for the current worst solution's input history.
bool _saveIntermediateResultsEnabled
Whether to store intermediate results at all.
void saveWorstStateInformation()
Writes the current worst solution to file, under the mutex.
float _bestWinStateReward
Reward for the best win state found so far.
size_t _stateSize
Storage size of a runner state.
Driver(const std::string &configFilePath, const nlohmann::json &config)
Constructs the driver and its engine/runner from the parsed configuration.
std::string _saveIntermediateWorstSolutionPath
Path to store the worst solution found so far.
void intermediateResultSaveLoop()
Background loop that periodically saves best and worst solutions to file.
std::string _worstStateStorage
Storage for the current worst (win or otherwise) state.
size_t _bestStateStepCount
Depth of the current best state, set by updateBestState() and reused by the printInfo reload.
const std::string _configFilePath
Path to the config file, kept for reference.
double _inputHistoryCapacityWatermark
Fraction of the input-history trie's hard ceiling at which the run stops gracefully (high-water mark)...
static std::unique_ptr< Runner > getRunner(const nlohmann::json &emulatorConfig, const nlohmann::json &gameConfig, const nlohmann::json &runnerConfig)
Creates a runner from the emulator, game and runner configurations.
Parallel breadth-first search engine that expands game states step by step, deduplicating via a hash ...
Abstract base for a JaffarPlus game: wraps an emulator, registers game properties,...
Drives a Game forward one input at a time, managing the allowed/candidate input sets,...