From 6c55f42ce2d0ae0eba9de4f06c893d21ba34da0e Mon Sep 17 00:00:00 2001 From: gymnast86 Date: Thu, 9 Apr 2026 15:38:56 -0700 Subject: [PATCH] Wrap generator in Randomizer class --- files.cmake | 2 - src/dusk/randomizer/logic/area.cpp | 8 +- src/dusk/randomizer/logic/area.hpp | 4 - src/dusk/randomizer/logic/generate.cpp | 112 -------------------- src/dusk/randomizer/logic/generate.hpp | 24 ----- src/dusk/randomizer/logic/search.cpp | 18 ++-- src/dusk/randomizer/logic/search.hpp | 7 +- src/dusk/randomizer/logic/spoiler_log.cpp | 36 ++++--- src/dusk/randomizer/logic/spoiler_log.hpp | 11 +- src/dusk/randomizer/logic/world.cpp | 44 +++----- src/dusk/randomizer/logic/world.hpp | 24 ++--- src/dusk/randomizer/randomizer.cmake | 1 + src/dusk/randomizer/randomizer.cpp | 119 +++++++++++++++++++--- src/dusk/randomizer/randomizer.hpp | 40 +++++++- src/dusk/randomizer/test/test.cpp | 8 +- src/dusk/randomizer/utility/log.cpp | 4 +- src/m_Do/m_Do_main.cpp | 8 +- 17 files changed, 225 insertions(+), 245 deletions(-) delete mode 100644 src/dusk/randomizer/logic/generate.cpp delete mode 100644 src/dusk/randomizer/logic/generate.hpp diff --git a/files.cmake b/files.cmake index 9f48a109fe..16733f480e 100644 --- a/files.cmake +++ b/files.cmake @@ -1389,8 +1389,6 @@ set(DUSK_FILES src/dusk/randomizer/logic/flatten/flatten.hpp src/dusk/randomizer/logic/flatten/simplify_algebraic.cpp src/dusk/randomizer/logic/flatten/simplify_algebraic.hpp - src/dusk/randomizer/logic/generate.cpp - src/dusk/randomizer/logic/generate.hpp src/dusk/randomizer/logic/item.cpp src/dusk/randomizer/logic/item.hpp src/dusk/randomizer/logic/item_pool.cpp diff --git a/src/dusk/randomizer/logic/area.cpp b/src/dusk/randomizer/logic/area.cpp index d2eed637a4..7be29d03fc 100644 --- a/src/dusk/randomizer/logic/area.cpp +++ b/src/dusk/randomizer/logic/area.cpp @@ -2,6 +2,7 @@ #include "search.hpp" #include "world.hpp" +#include "../randomizer.hpp" #include #include @@ -10,15 +11,12 @@ namespace randomizer::logic::area { - int LocationAccess::_idCounter = 0; - int Area::_idCounter = 0; - LocationAccess::LocationAccess(randomizer::logic::location::Location* loc, const randomizer::logic::requirement::Requirement& req, Area* area): _loc(loc), _req(std::move(req)), _area(area) { - this->_id = this->_idCounter++; + this->_id = area->GetWorld()->GetRandomizer()->GetNewLocAccID(); } randomizer::logic::location::Location* LocationAccess::GetLocation() const @@ -63,7 +61,7 @@ namespace randomizer::logic::area Area::Area(const std::string& name, randomizer::logic::world::World* world): _name(name), _world(world) { - this->_id = this->_idCounter++; + this->_id = world->GetRandomizer()->GetNewAreaID(); } std::string Area::GetName() const diff --git a/src/dusk/randomizer/logic/area.hpp b/src/dusk/randomizer/logic/area.hpp index b56025bd39..f014860d74 100644 --- a/src/dusk/randomizer/logic/area.hpp +++ b/src/dusk/randomizer/logic/area.hpp @@ -36,8 +36,6 @@ namespace randomizer::logic::area int GetID() const; private: - static int _idCounter; - int _id = -1; randomizer::logic::location::Location* _loc = nullptr; randomizer::logic::requirement::Requirement _req; @@ -97,8 +95,6 @@ namespace randomizer::logic::area void AssignHintRegionsAndDungeonLocations(); private: - static int _idCounter; - int _id = -1; std::string _name = ""; std::string _hardAssignedRegion = ""; diff --git a/src/dusk/randomizer/logic/generate.cpp b/src/dusk/randomizer/logic/generate.cpp deleted file mode 100644 index 546da3a96e..0000000000 --- a/src/dusk/randomizer/logic/generate.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "generate.hpp" - -#include "entrance_shuffle.hpp" -#include "fill.hpp" -#include "flatten/flatten.hpp" -#include "plandomizer.hpp" -#include "search.hpp" -#include "spoiler_log.hpp" -#include "../seedgen/config.hpp" -#include "../seedgen/settings.hpp" -#include "../utility/log.hpp" -#include "../utility/time.hpp" - -#include - -namespace randomizer::logic::generate -{ - randomizer::logic::world::WorldPool GenerateWorlds() - { - randomizer::utility::time::ScopedTimer<"Seed generation took ", std::chrono::milliseconds> timer; - randomizer::seedgen::config::Config config; - config.LoadFromFile(SETTINGS_PATH, PREFERENCES_PATH); - - randomizer::utility::platform::Log(std::string("Seed: ") + config.GetSeed()); - - randomizer::logic::world::WorldPool worlds = {}; - GenerateRandomizer(config, worlds); - - return std::move(worlds); - } - - void GenerateRandomizer(randomizer::seedgen::config::Config& config, randomizer::logic::world::WorldPool& worlds) - { - randomizer::seedgen::config::SeedRNG(config, true, false); - // Set the hash now before anything else random is decided. This allows us to show the hash for a seed - // before generating it later - auto hash = config.GetHash(); - randomizer::utility::platform::Log(std::string("Hash: ") + hash); - - // Build all worlds - int worldId = 1; - for (const auto& settings : config.GetSettingsList()) - { - std::unique_ptr world = std::make_unique(worldId++); - world->SetSettings(settings); - world->ResolveRandomSettings(); - world->ResolveConflictingSettings(); - world->Build(); - worlds.emplace_back(std::move(world)); - } - - // Give each world a pointer to the world pool - for (auto& world : worlds) - { - world->SetWorlds(&worlds); - } - - // Process Plando Data for all worlds - if (config.IsUsingPlandomizer()) - { - randomizer::logic::plandomizer::LoadPlandomizerData(worlds, config.GetPlandomizerPath()); - } - - // Pre Entrance Shuffle Tasks - for (auto& world : worlds) - { - world->PerformPreEntranceShuffleTasks(); - } - - randomizer::utility::platform::Log("Shuffling Entrances..."); - for (auto& world : worlds) - { - randomizer::logic::entrance_shuffle::ShuffleWorldEntrances(world.get(), worlds); - } - - // Post Entrance Shuffle Tasks - for (auto& world : worlds) - { - world->PerformPostEntranceShuffleTasks(); - } - randomizer::logic::fill::CacheExitTimeForms(worlds); - - // Flattening isn't used for anything yet, but flattens down the requirements for - // each location and entrance into a single statement. This will be useful for hints and could potentially - // be used to speed up the fill algorithm (but the fill algorithm is already pretty fast, so we'd only gain maybe like - // 0.2 seconds back or something) - randomizer::utility::platform::Log("Flattening..."); - FlattenSearch search = FlattenSearch(worlds.at(0).get()); - search.doSearch(); - - randomizer::utility::platform::Log("Filling Worlds..."); - randomizer::logic::fill::FillWorlds(worlds); - - // Post Fill Tasks - for (auto& world : worlds) - { - world->PerformPostFillTasks(); - } - - // Generate Playthrough - randomizer::logic::search::GeneratePlaythrough(&worlds); - - // TODO: Generate Hints - - // Write Logs - if (config.IsGeneratingSpoilerLog()) - { - randomizer::logic::spoiler_log::GenerateSpoilerLog(worlds, config); - } - randomizer::logic::spoiler_log::GenerateAntiSpoilerLog(worlds, config); - } -} // namespace randomizer::logic::generate diff --git a/src/dusk/randomizer/logic/generate.hpp b/src/dusk/randomizer/logic/generate.hpp deleted file mode 100644 index e5ec40b1a6..0000000000 --- a/src/dusk/randomizer/logic/generate.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "world.hpp" -#include "../seedgen/config.hpp" - -namespace randomizer::logic::generate -{ - /** - * @brief Generates a complete randomizer seed - * - * @param worlds The list of worlds for the generated randomizer seed - * @return the worldpool which was generated - */ - randomizer::logic::world::WorldPool GenerateWorlds(); - - /** - * @brief Generates a complete randomizer seed with the provided config - * - * @param config The configuration to use for this seed - * @param worlds The list of worlds for the generated randomizer seed - * @return 0 if no errors. 1 if there were errors - */ - void GenerateRandomizer(randomizer::seedgen::config::Config& config, randomizer::logic::world::WorldPool& worlds); -} // namespace randomizer::logic::generate diff --git a/src/dusk/randomizer/logic/search.cpp b/src/dusk/randomizer/logic/search.cpp index 028a381fca..960a06b266 100644 --- a/src/dusk/randomizer/logic/search.cpp +++ b/src/dusk/randomizer/logic/search.cpp @@ -1,6 +1,7 @@ #include "search.hpp" #include "world.hpp" +#include "../randomizer.hpp" #include "../utility/general.hpp" #include "../utility/platform.hpp" @@ -520,11 +521,12 @@ namespace randomizer::logic::search return std::nullopt; } - void GeneratePlaythrough(randomizer::logic::world::WorldPool* worlds) + void GeneratePlaythrough(randomizer::Randomizer* randomizer) { + auto& worlds = randomizer->GetWorlds(); LOG_TO_DEBUG("Generating Playthrough"); // Generate Initial Playthrough - auto playthroughSearch = Search::Playthrough(worlds); + auto playthroughSearch = Search::Playthrough(&worlds); playthroughSearch.SearchWorlds(); auto& playthroughSpheres = playthroughSearch._playthroughSpheres; @@ -542,7 +544,7 @@ namespace randomizer::logic::search } // Remove all items from locations that are not part of the playthrough set - for (const auto& world : *worlds) + for (const auto& world : worlds) { for (const auto& location : world->GetAllLocations()) { @@ -567,7 +569,7 @@ namespace randomizer::logic::search // If the game is beatable, temporarily take this item away and erase the location from the playthrough // locations - if (GameBeatable(worlds)) + if (GameBeatable(&worlds)) { tempEmptyLocations[location] = itemAtLocation; playthroughLocationsSet.erase(location); @@ -581,7 +583,7 @@ namespace randomizer::logic::search // Generate a new playthrough search incase some spheres were flattened by the previous generation having access // to extra items - auto newSearch = Search::Playthrough(worlds); + auto newSearch = Search::Playthrough(&worlds); newSearch.SearchWorlds(); // Now do the same process for entrances to pare down the entrance playthrough @@ -594,7 +596,7 @@ namespace randomizer::logic::search for (const auto& entrance : sphereCopy) { auto connectedArea = entrance->Disconnect(); - if (GameBeatable(worlds)) + if (GameBeatable(&worlds)) { // If the game is still beatable then this entrance is not required sphere.erase(std::remove(sphere.begin(), sphere.end(), entrance), sphere.end()); @@ -636,8 +638,8 @@ namespace randomizer::logic::search // Remove any empty spheres newSearch.RemoveEmptySpheres(); - worlds->at(0)->SetPlaythroughSpheres(newSearch._playthroughSpheres); - worlds->at(0)->SetEntranceSpheres(newSearch._entranceSpheres); + randomizer->GetPlaythroughSpheres() = newSearch._playthroughSpheres; + randomizer->GetEntranceSpheres() = newSearch._entranceSpheres; } bool GameBeatable(randomizer::logic::world::WorldPool* worlds, const randomizer::logic::item_pool::ItemPool& items /* = {} */) diff --git a/src/dusk/randomizer/logic/search.hpp b/src/dusk/randomizer/logic/search.hpp index 77a14ac3a5..c515dbf0c2 100644 --- a/src/dusk/randomizer/logic/search.hpp +++ b/src/dusk/randomizer/logic/search.hpp @@ -12,6 +12,11 @@ #include // Forward Declarations (we have a lot here) +namespace randomizer +{ + class Randomizer; +} + namespace randomizer::logic::world { class World; @@ -156,6 +161,6 @@ namespace randomizer::logic::search */ std::optional VerifyLogic(randomizer::logic::world::WorldPool* worlds, const randomizer::logic::item_pool::ItemPool& items = {}); - void GeneratePlaythrough(randomizer::logic::world::WorldPool* worlds); + void GeneratePlaythrough(randomizer::Randomizer* randomizer); bool GameBeatable(randomizer::logic::world::WorldPool* worlds, const randomizer::logic::item_pool::ItemPool& items = {}); } // namespace randomizer::logic::search diff --git a/src/dusk/randomizer/logic/spoiler_log.cpp b/src/dusk/randomizer/logic/spoiler_log.cpp index 07373b2d8a..667d6f84a6 100644 --- a/src/dusk/randomizer/logic/spoiler_log.cpp +++ b/src/dusk/randomizer/logic/spoiler_log.cpp @@ -1,6 +1,7 @@ #include "spoiler_log.hpp" #include "entrance_shuffle.hpp" +#include "../randomizer.hpp" #include "../utility/file.hpp" #include "../utility/platform.hpp" #include "../utility/yaml.hpp" @@ -28,23 +29,23 @@ namespace randomizer::logic::spoiler_log return entrance->GetAlias() + ": " + spaces + replacement->GetAliasFrom(); } - void LogBasicInfo(std::ofstream& log, randomizer::seedgen::config::Config& config, randomizer::logic::world::WorldPool& worlds) + void LogBasicInfo(std::ofstream& log, randomizer::Randomizer* randomizer) { log << "Dusk Randomizer Version: " << "1.0.0" << std::endl; - log << "Seed: " << config.GetSeed() << std::endl; + log << "Seed: " << randomizer->GetConfig().GetSeed() << std::endl; // TODO: Setting string - log << "Hash: " << config.GetHash() << std::endl; + log << "Hash: " << randomizer->GetConfig().GetHash() << std::endl; } - void LogSettings(std::ofstream& log, randomizer::seedgen::config::Config& config, randomizer::logic::world::WorldPool& worlds) + void LogSettings(std::ofstream& log, randomizer::Randomizer* randomizer) { log << std::endl << "# Settings" << std::endl; - log << YAML::Dump(config.SettingsToYaml()) << std::endl; + log << YAML::Dump(randomizer->GetConfig().SettingsToYaml()) << std::endl; } - void GenerateSpoilerLog(randomizer::logic::world::WorldPool& worlds, randomizer::seedgen::config::Config& config) + void GenerateSpoilerLog(randomizer::Randomizer* randomizer) { randomizer::utility::platform::Log("Generating Spoiler Log"); @@ -54,11 +55,14 @@ namespace randomizer::logic::spoiler_log randomizer::utility::file::create_directories(LOGS_PATH); } + auto& config = randomizer->GetConfig(); + auto& worlds = randomizer->GetWorlds(); + std::string filepath = std::string(LOGS_PATH) + config.GetHash() + " Spoiler Log.txt"; std::ofstream spoilerLog; spoilerLog.open(filepath); - LogBasicInfo(spoilerLog, config, worlds); + LogBasicInfo(spoilerLog, randomizer); // Gather worlds with starting inventories std::list worldswithStartingInventories = {}; @@ -87,7 +91,7 @@ namespace randomizer::logic::spoiler_log // Get name lengths for pretty formatting size_t longestNameLength = 0; - for (const auto& sphere : worlds.at(0)->GetPlaythroughSpheres()) + for (const auto& sphere : randomizer->GetPlaythroughSpheres()) { for (const auto& location : sphere) { @@ -98,7 +102,7 @@ namespace randomizer::logic::spoiler_log // Print playthrough int sphereNum = 0; spoilerLog << std::endl << "Playthrough:" << std::endl; - for (auto& sphere : worlds.at(0)->GetPlaythroughSpheres()) + for (auto& sphere : randomizer->GetPlaythroughSpheres()) { sphereNum += 1; spoilerLog << " Sphere " << sphereNum << ":" << std::endl; @@ -111,7 +115,7 @@ namespace randomizer::logic::spoiler_log // Get name lengths for pretty formatting longestNameLength = 0; - for (const auto& sphere : worlds.at(0)->GetEntranceSpheres()) + for (const auto& sphere : randomizer->GetEntranceSpheres()) { for (const auto& entrance : sphere) { @@ -125,7 +129,7 @@ namespace randomizer::logic::spoiler_log { spoilerLog << std::endl << "Entrance Playthrough:" << std::endl; } - for (auto& sphere : worlds.at(0)->GetEntranceSpheres()) + for (auto& sphere : randomizer->GetEntranceSpheres()) { sphereNum += 1; if (sphere.empty()) @@ -220,14 +224,14 @@ namespace randomizer::logic::spoiler_log // TODO: Hints // Log Settings - LogSettings(spoilerLog, config, worlds); + LogSettings(spoilerLog, randomizer); spoilerLog.close(); randomizer::utility::platform::Log("Wrote spoiler log to " + filepath); } - void GenerateAntiSpoilerLog(randomizer::logic::world::WorldPool& worlds, randomizer::seedgen::config::Config& config) + void GenerateAntiSpoilerLog(randomizer::Randomizer* randomizer) { // Create logs folder if it doesn't exist if (!randomizer::utility::file::dirExists(LOGS_PATH)) @@ -235,11 +239,11 @@ namespace randomizer::logic::spoiler_log randomizer::utility::file::create_directories(LOGS_PATH); } - std::string filepath = std::string(LOGS_PATH) + config.GetHash() + " Anti-Spoiler Log.txt"; + std::string filepath = std::string(LOGS_PATH) + randomizer->GetConfig().GetHash() + " Anti-Spoiler Log.txt"; std::ofstream antiSpoilerLog; antiSpoilerLog.open(filepath); - LogBasicInfo(antiSpoilerLog, config, worlds); - LogSettings(antiSpoilerLog, config, worlds); + LogBasicInfo(antiSpoilerLog, randomizer); + LogSettings(antiSpoilerLog, randomizer); } } // namespace randomizer::logic::spoiler_log diff --git a/src/dusk/randomizer/logic/spoiler_log.hpp b/src/dusk/randomizer/logic/spoiler_log.hpp index 1811f5676e..ee4a51c306 100644 --- a/src/dusk/randomizer/logic/spoiler_log.hpp +++ b/src/dusk/randomizer/logic/spoiler_log.hpp @@ -1,10 +1,13 @@ #pragma once -#include "world.hpp" -#include "../seedgen/config.hpp" +// Forward Declarations +namespace randomizer +{ + class Randomizer; +} namespace randomizer::logic::spoiler_log { - void GenerateSpoilerLog(randomizer::logic::world::WorldPool& worlds, randomizer::seedgen::config::Config& config); - void GenerateAntiSpoilerLog(randomizer::logic::world::WorldPool& worlds, randomizer::seedgen::config::Config& config); + void GenerateSpoilerLog(randomizer::Randomizer* randomizer); + void GenerateAntiSpoilerLog(randomizer::Randomizer* randomizer); } // namespace randomizer::logic::spoiler_log diff --git a/src/dusk/randomizer/logic/world.cpp b/src/dusk/randomizer/logic/world.cpp index 75be85a3ef..93fb9862b0 100644 --- a/src/dusk/randomizer/logic/world.cpp +++ b/src/dusk/randomizer/logic/world.cpp @@ -2,6 +2,7 @@ #include "search.hpp" +#include "../randomizer.hpp" #include "../utility/exception.hpp" #include "../utility/file.hpp" #include "../utility/general.hpp" @@ -17,12 +18,9 @@ namespace randomizer::logic::world { - int World::_eventIdCounter = 0; - - World::World(const int& id) - { - this->_id = id; - } + World::World(const int& id, randomizer::Randomizer* randomizer) : + _id(id), _randomizer(randomizer) + {} int World::GetID() const { @@ -36,9 +34,13 @@ namespace randomizer::logic::world { return this->_settings; } - void World::SetWorlds(WorldPool* worlds) + void World::SetRandomizer(Randomizer* randomizer) { - _worlds = worlds; + this->_randomizer = randomizer; + } + Randomizer* World::GetRandomizer() const + { + return this->_randomizer; } void World::ResolveRandomSettings() @@ -773,8 +775,8 @@ namespace randomizer::logic::world // Check if the game is beatable, set dungeon as required if so. If the dungeon is not required and barren // unrequired dungeons is on, then set all the locations in the unrequired dungeon as nonprogress. - auto completeItemPool = randomizer::logic::item_pool::GetCompleteItemPool(*(this->_worlds)); - if (!randomizer::logic::search::GameBeatable(this->_worlds, completeItemPool)) + auto completeItemPool = randomizer::logic::item_pool::GetCompleteItemPool(this->_randomizer->GetWorlds()); + if (!randomizer::logic::search::GameBeatable(&(this->_randomizer->GetWorlds()), completeItemPool)) { dungeon->SetRequired(true); } @@ -1123,7 +1125,7 @@ namespace randomizer::logic::world // Add the event if it doesn't exist yet if (!this->_eventIndexes.contains(eventName)) { - auto index = this->_eventIdCounter++; + auto index = this->_randomizer->GetNewEventID(); this->_eventIndexes.emplace(eventName, index); this->_eventNames.emplace(index, eventName); LOG_TO_DEBUG("Event \"" + eventName + "\" was assigned eventIndex " + std::to_string(index)); @@ -1151,24 +1153,4 @@ namespace randomizer::logic::world } return settings.GetMap().at(settingName); } - - void World::SetPlaythroughSpheres(const std::list>& playthroughSpheres) - { - this->_playthroughSpheres = playthroughSpheres; - } - - std::list> World::GetPlaythroughSpheres() const - { - return this->_playthroughSpheres; - } - - void World::SetEntranceSpheres(const std::list>& entranceSpheres) - { - this->_entranceSpheres = entranceSpheres; - } - - std::list> World::GetEntranceSpheres() const - { - return this->_entranceSpheres; - } } // namespace randomizer::logic::world diff --git a/src/dusk/randomizer/logic/world.hpp b/src/dusk/randomizer/logic/world.hpp index 3c8f02c0ca..e70154f7b0 100644 --- a/src/dusk/randomizer/logic/world.hpp +++ b/src/dusk/randomizer/logic/world.hpp @@ -19,6 +19,11 @@ #include // Forward Declarations +namespace randomizer +{ + class Randomizer; +} + namespace randomizer::logic::search { class Search; @@ -32,12 +37,13 @@ namespace randomizer::logic::world class World { public: - World(const int& id); + World(const int& id, randomizer::Randomizer* randomizer); int GetID() const; void SetSettings(const randomizer::seedgen::settings::Settings& settings); const randomizer::seedgen::settings::Settings& GetSettings() const; - void SetWorlds(WorldPool* worlds); + void SetRandomizer(Randomizer* randomizer); + Randomizer* GetRandomizer() const; /** * @brief Resolves all remaining random settings within a specific world @@ -133,16 +139,10 @@ namespace randomizer::logic::world std::string GetEventName(const int& eventIndex); randomizer::seedgen::settings::Setting& Setting(const std::string& settingName); - void SetPlaythroughSpheres(const std::list>& playthroughSpheres); - std::list> GetPlaythroughSpheres() const; - void SetEntranceSpheres(const std::list>& entranceSpheres); - std::list> GetEntranceSpheres() const; private: int _id = -1; - - static int _eventIdCounter; // Needs to be shared for events across all worlds - int _entranceIdCounter = 0; // Specific for this world + int _entranceIdCounter = 0; randomizer::seedgen::settings::Settings _settings; std::map> _itemTable = {}; @@ -159,14 +159,10 @@ namespace randomizer::logic::world randomizer::logic::item_pool::ItemPool _startingItemPool = {}; std::unordered_map _exitTimeFormCache = {}; - // Playthroughs will be stored in world 0 for convenience - std::list> _playthroughSpheres = {}; - std::list> _entranceSpheres = {}; - // Plandomizer Data std::unordered_map _plandomizerLocations = {}; std::unordered_map _plandomizerEntrances = {}; - WorldPool* _worlds = nullptr; + Randomizer* _randomizer = nullptr; }; } // namespace randomizer::logic::world diff --git a/src/dusk/randomizer/randomizer.cmake b/src/dusk/randomizer/randomizer.cmake index b890dad145..43375e656d 100644 --- a/src/dusk/randomizer/randomizer.cmake +++ b/src/dusk/randomizer/randomizer.cmake @@ -58,5 +58,6 @@ string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE) set(GAME_COMPILE_DEFS ${GAME_COMPILE_DEFS} SOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}) set(GAME_LIBS ${GAME_LIBS} yaml-cpp::yaml-cpp zlib base64pp) +make_directory("${CMAKE_BINARY_DIR}/randomizer") # Put data files together for easier manipulation # file(COPY "${CMAKE_SOURCE_DIR}/src/dusk/randomizer/data/" DESTINATION "${CMAKE_BINARY_DIR}/randomizer/data/" REGEX "^.*example.*$" EXCLUDE) # World, macros, and location info diff --git a/src/dusk/randomizer/randomizer.cpp b/src/dusk/randomizer/randomizer.cpp index b359723d36..4f7f94c62a 100644 --- a/src/dusk/randomizer/randomizer.cpp +++ b/src/dusk/randomizer/randomizer.cpp @@ -1,29 +1,116 @@ #include "randomizer.hpp" -#include "logic/generate.hpp" +#include "logic/entrance_shuffle.hpp" +#include "logic/fill.hpp" +#include "logic/flatten/flatten.hpp" +#include "logic/plandomizer.hpp" +#include "logic/search.hpp" +#include "logic/spoiler_log.hpp" #include "logic/world.hpp" #include "test/test.hpp" +#include "seedgen/config.hpp" +#include "seedgen/settings.hpp" #include "utility/log.hpp" +#include "utility/time.hpp" #include -int randomizerMain() +namespace randomizer { - try + int Randomizer::Generate() { -#ifdef LOGIC_TESTS - randomizer::test::test::RunTests(); + try + { + GenerateWorlds(); + } + catch(const std::exception& e) + { + std::cout << "============================================================" << std::endl; + std::cout << "The following exception occured: " << e.what() << std::endl; + return 1; + } + return 0; -#else - auto worlds = randomizer::logic::generate::GenerateWorlds(); -#endif - } - catch(const std::exception& e) - { - std::cout << "============================================================" << std::endl; - std::cout << "The following exception occured: " << e.what() << std::endl; - return 1; } - return 0; -} + void Randomizer::GenerateWorlds() + { + utility::time::ScopedTimer<"Seed generation took ", std::chrono::milliseconds> timer; + this->_worlds.clear(); + this->_config.LoadFromFile(SETTINGS_PATH, PREFERENCES_PATH); + + utility::platform::Log(std::string("Seed: ") + this->_config.GetSeed()); + + seedgen::config::SeedRNG(this->_config, true, false); + // Set the hash now before anything else random is decided. This allows us to show the hash for a seed + // before generating it later + auto hash = this->_config.GetHash(); + utility::platform::Log(std::string("Hash: ") + hash); + + // Build all worlds + int worldId = 1; + for (const auto& settings : this->_config.GetSettingsList()) + { + std::unique_ptr world = std::make_unique(worldId++, this); + world->SetSettings(settings); + world->ResolveRandomSettings(); + world->ResolveConflictingSettings(); + world->Build(); + this->_worlds.emplace_back(std::move(world)); + } + + // Process Plando Data for all worlds + if (this->_config.IsUsingPlandomizer()) + { + logic::plandomizer::LoadPlandomizerData(this->_worlds, this->_config.GetPlandomizerPath()); + } + + // Pre Entrance Shuffle Tasks + for (auto& world : this->_worlds) + { + world->PerformPreEntranceShuffleTasks(); + } + + utility::platform::Log("Shuffling Entrances..."); + for (auto& world : this->_worlds) + { + logic::entrance_shuffle::ShuffleWorldEntrances(world.get(), this->_worlds); + } + + // Post Entrance Shuffle Tasks + for (auto& world : this->_worlds) + { + world->PerformPostEntranceShuffleTasks(); + } + logic::fill::CacheExitTimeForms(this->_worlds); + + // Flattening isn't used for anything yet, but flattens down the requirements for + // each location and entrance into a single statement. This will be useful for hints and could potentially + // be used to speed up the fill algorithm (but the fill algorithm is already pretty fast, so we'd only gain maybe like + // 0.2 seconds back or something) + utility::platform::Log("Flattening..."); + FlattenSearch search = FlattenSearch(this->_worlds.at(0).get()); + search.doSearch(); + + utility::platform::Log("Filling Worlds..."); + logic::fill::FillWorlds(this->_worlds); + + // Post Fill Tasks + for (auto& world : this->_worlds) + { + world->PerformPostFillTasks(); + } + + // Generate Playthrough + logic::search::GeneratePlaythrough(this); + + // TODO: Generate Hints + + // Write Logs + if (this->_config.IsGeneratingSpoilerLog()) + { + logic::spoiler_log::GenerateSpoilerLog(this); + } + logic::spoiler_log::GenerateAntiSpoilerLog(this); + } +} // namespace randomizer diff --git a/src/dusk/randomizer/randomizer.hpp b/src/dusk/randomizer/randomizer.hpp index 788d40a541..38a3e62c33 100644 --- a/src/dusk/randomizer/randomizer.hpp +++ b/src/dusk/randomizer/randomizer.hpp @@ -1,3 +1,41 @@ #pragma once -int randomizerMain(); \ No newline at end of file +#include "logic/world.hpp" + +namespace randomizer +{ + class Randomizer + { + public: + explicit Randomizer() = default; + + /** + * @brief Generates a complete randomizer seed + * + * @return 0 if no errors. 1 if there were errors + */ + int Generate(); + void GenerateWorlds(); + + auto& GetConfig() { return this->_config; } + auto& GetWorlds() { return this->_worlds; } + + int GetNewEventID() { return ++(this->_eventIdCounter); } + int GetNewAreaID() { return ++(this->_areaIdCounter); } + int GetNewLocAccID() { return ++(this->_locAccIdCounter); } + + auto& GetPlaythroughSpheres() { return this->_playthroughSpheres; } + auto& GetEntranceSpheres() { return this->_entranceSpheres; } + private: + seedgen::config::Config _config{}; + logic::world::WorldPool _worlds{}; + + int _eventIdCounter{}; + int _areaIdCounter{}; + int _locAccIdCounter{}; + + // Playthrough data + std::list> _playthroughSpheres{}; + std::list> _entranceSpheres{}; + }; +} // namespace randomizer diff --git a/src/dusk/randomizer/test/test.cpp b/src/dusk/randomizer/test/test.cpp index 73eeddabe2..21476af6b3 100644 --- a/src/dusk/randomizer/test/test.cpp +++ b/src/dusk/randomizer/test/test.cpp @@ -1,7 +1,6 @@ #include "test.hpp" -#include "../logic/generate.hpp" -#include "../logic/world.hpp" +#include "../randomizer.hpp" #include "../utility/string.hpp" #include @@ -23,11 +22,12 @@ namespace randomizer::test::test std::cout << "Testing " << testName << std::endl; try { - randomizer::logic::generate::GenerateWorlds(); + randomizer::Randomizer r{}; + r.GenerateWorlds(); } catch(const std::exception& e) { std::cout << "Test \"" << testName << "\" failed! Failed settings saved to " << SETTINGS_PATH << std::endl; - std::cout << "Error Message:" << std::endl; + std::cout << "Error Message: " << std::endl; throw e; } diff --git a/src/dusk/randomizer/utility/log.cpp b/src/dusk/randomizer/utility/log.cpp index 8b96e7e415..ca4337c10c 100644 --- a/src/dusk/randomizer/utility/log.cpp +++ b/src/dusk/randomizer/utility/log.cpp @@ -30,7 +30,7 @@ namespace randomizer::utility::log #ifdef RANDO_ERROR_LOG output.open(LOG_PATH); output << "Program opened " << randomizer::utility::time::ProgramTime::getDateStr(); // time string ends with \n - output << "Twilight Princess HD Randomizer Version " << RANDOMIZER_VERSION << std::endl; + output << "Dusk Randomizer Version " << RANDOMIZER_VERSION << std::endl; output << std::endl << std::endl; #endif } @@ -77,7 +77,7 @@ namespace randomizer::utility::log { output.open(LOG_PATH); output << "Program opened " << randomizer::utility::time::ProgramTime::getDateStr(); // time string ends with \n - output << "Twilight Princess HD Randomizer Version " << RANDOMIZER_VERSION << std::endl; + output << "Dusk Randomizer Version " << RANDOMIZER_VERSION << std::endl; output << std::endl << std::endl; } diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 6b905be1ed..a5861d20f7 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -63,6 +63,7 @@ #if RANDOMIZER_ONLY #include "dusk/randomizer/randomizer.hpp" +#include "dusk/randomizer/test/test.hpp" #endif // --- GLOBALS --- @@ -288,7 +289,12 @@ static const char* CalculateConfigPath() { int game_main(int argc, char* argv[]) { #if RANDOMIZER_ONLY - randomizerMain(); + #ifdef LOGIC_TESTS + randomizer::test::test::RunTests(); + #else + randomizer::Randomizer rando{}; + rando.Generate(); + #endif exit(0); #endif