diff --git a/Source/Core/Gen5/IVSeedCache.cpp b/Source/Core/Gen5/IVSeedCache.cpp index d8c0a67a..bd298710 100644 --- a/Source/Core/Gen5/IVSeedCache.cpp +++ b/Source/Core/Gen5/IVSeedCache.cpp @@ -20,38 +20,26 @@ #include "IVSeedCache.hpp" #include #include +#include #include #include #include -struct IV +enum class CacheType { - u16 hp : 1; - u16 atk : 5; - u16 def : 1; - u16 spa : 5; - u16 spd : 1; - u16 spe : 2; + Entralink, + Normal, + Roamer }; -static_assert(sizeof(IV) == 2); -#pragma pack(push, 1) -struct IVEntry -{ - u32 seed; - IV iv; -}; -#pragma pack(pop) -static_assert(sizeof(IVEntry) == 6); - -struct IVCache +struct SeedCache { std::array entralinkCount; std::array normalCount; std::array roamerCount; - IVEntry data[]; + u32 seeds[]; }; -static_assert(sizeof(IVCache) == 48); +static_assert(sizeof(SeedCache) == 48); static bool compareIVs(const std::array &ivs, const StateFilter &filter) { @@ -67,46 +55,68 @@ static bool compareIVs(const std::array &ivs, const StateFilter &filter) return filter.compareIV(ivs) && filter.compareHiddenPower(hiddenPower); } -static std::array computeIVs(IV iv) +template +static std::array computeIVs(u32 seed, u8 advance) { - // HP maps 0-1 to 30-31 - // Atk maps 0-31 to 0-31 - // Def maps 0-1 to 30-31 - // SpA maps 0-31 to 0-31 - // SpD maps 0-1 to 0-31 - // Spe maps 0-1 to 30-31 and 2-3 to 0-1 - return { static_cast(30 + iv.hp), static_cast(iv.atk), static_cast(30 + iv.def), - static_cast(iv.spa), static_cast(30 + iv.spd), static_cast((30 + iv.spe) & 0x1f) }; + std::array ivs; + + if constexpr (type == CacheType::Entralink) + { + advance += 22; + } + else if constexpr (type == CacheType::Roamer) + { + advance += 1; + } + + constexpr u16 size = type == CacheType::Entralink ? 37 : type == CacheType::Normal ? 13 : 12; + MTFast mt(seed, advance); + + ivs[0] = mt.next(); + ivs[1] = mt.next(); + ivs[2] = mt.next(); + if constexpr (type == CacheType::Roamer) + { + ivs[4] = mt.next(); + ivs[5] = mt.next(); + ivs[3] = mt.next(); + } + else + { + ivs[3] = mt.next(); + ivs[4] = mt.next(); + ivs[5] = mt.next(); + } + + return ivs; } namespace IVSeedCache { - std::array>, 6> getNormalCache(u32 initialAdvance, u32 maxAdvance, Game version, - const StateFilter &filter) + std::array>, 6> getEntralinkCache(u32 initialAdvance, u32 maxAdvance, + const StateFilter &filter) { std::array>, 6> cache; - bool bw = (version & Game::BW) != Game::None; - u32 size; u8 *data = Utilities::decompress(IVS.data(), IVS.size(), size); - const auto *ivCache = reinterpret_cast(data); + const auto *seedCache = reinterpret_cast(data); - u32 index = std::accumulate(ivCache->entralinkCount.begin(), ivCache->entralinkCount.end(), 0); + u32 index = 0; for (u32 i = initialAdvance; i <= (initialAdvance + maxAdvance) && i < cache.size(); i++) { - u16 count = ivCache->normalCount[i + (bw ? 0 : 2)]; + u16 count = seedCache->entralinkCount[i]; cache[i].reserve(count); - const IVEntry *entry = &ivCache->data[index]; - for (u16 j = 0; j < count; j++, entry++) + for (u16 j = 0; j < count; j++) { - auto ivs = computeIVs(entry->iv); + u32 seed = seedCache->seeds[index + j]; + auto ivs = computeIVs(seed, i); if (compareIVs(ivs, filter)) { - cache[i].emplace(entry->seed, ivs); + cache[i].emplace(seed, ivs); } } cache[i].max_load_factor(cache[i].max_load_factor_upper_limit()); @@ -119,30 +129,36 @@ namespace IVSeedCache return cache; } - std::array>, 6> getRoamerCache(u32 initialAdvance, u32 maxAdvance, const StateFilter &filter) + std::array>, 6> getNormalCache(u32 initialAdvance, u32 maxAdvance, Game version, + const StateFilter &filter) { std::array>, 6> cache; + bool bw = (version & Game::BW) != Game::None; + u32 size; u8 *data = Utilities::decompress(IVS.data(), IVS.size(), size); - const auto *ivCache = reinterpret_cast(data); + const auto *seedCache = reinterpret_cast(data); - u32 index = std::accumulate(ivCache->normalCount.begin(), ivCache->normalCount.end(), - std::accumulate(ivCache->entralinkCount.begin(), ivCache->entralinkCount.end(), 0)); + u32 index = std::accumulate(seedCache->entralinkCount.begin(), seedCache->entralinkCount.end(), 0); + if (!bw) + { + index += seedCache->normalCount[0] + seedCache->normalCount[1]; + } for (u32 i = initialAdvance; i <= (initialAdvance + maxAdvance) && i < cache.size(); i++) { - u16 count = ivCache->roamerCount[i]; + u16 count = seedCache->normalCount[i + (bw ? 0 : 2)]; cache[i].reserve(count); - const IVEntry *entry = &ivCache->data[index]; - for (u16 j = 0; j < count; j++, entry++) + for (u16 j = 0; j < count; j++) { - auto ivs = computeIVs(entry->iv); + u32 seed = seedCache->seeds[index + j]; + auto ivs = computeIVs(seed, i + (bw ? 0 : 2)); if (compareIVs(ivs, filter)) { - cache[i].emplace(entry->seed, ivs); + cache[i].emplace(seed, ivs); } } cache[i].max_load_factor(cache[i].max_load_factor_upper_limit()); @@ -155,30 +171,30 @@ namespace IVSeedCache return cache; } - std::array>, 6> getEntralinkCache(u32 initialAdvance, u32 maxAdvance, - const StateFilter &filter) + std::array>, 6> getRoamerCache(u32 initialAdvance, u32 maxAdvance, const StateFilter &filter) { std::array>, 6> cache; u32 size; u8 *data = Utilities::decompress(IVS.data(), IVS.size(), size); - const auto *ivCache = reinterpret_cast(data); + const auto *seedCache = reinterpret_cast(data); - u32 index = 0; + u32 index = std::accumulate(seedCache->normalCount.begin(), seedCache->normalCount.end(), + std::accumulate(seedCache->entralinkCount.begin(), seedCache->entralinkCount.end(), 0)); for (u32 i = initialAdvance; i <= (initialAdvance + maxAdvance) && i < cache.size(); i++) { - u16 count = ivCache->entralinkCount[i]; + u16 count = seedCache->roamerCount[i]; cache[i].reserve(count); - const IVEntry *entry = &ivCache->data[index]; - for (u16 j = 0; j < count; j++, entry++) + for (u16 j = 0; j < count; j++) { - auto ivs = computeIVs(entry->iv); + u32 seed = seedCache->seeds[index + j]; + auto ivs = computeIVs(seed, i); if (compareIVs(ivs, filter)) { - cache[i].emplace(entry->seed, ivs); + cache[i].emplace(seed, ivs); } } cache[i].max_load_factor(cache[i].max_load_factor_upper_limit()); diff --git a/Source/Core/Gen5/IVSeedCache.hpp b/Source/Core/Gen5/IVSeedCache.hpp index 2bd3f06b..1656fd19 100644 --- a/Source/Core/Gen5/IVSeedCache.hpp +++ b/Source/Core/Gen5/IVSeedCache.hpp @@ -33,31 +33,32 @@ enum class Game : u32; namespace IVSeedCache { /** - * @brief Returns the IV caches for most encounter types + * @brief Returns the IV caches for entralink * * @param initialAdvance Initial IV advances * @param maxAdvance Maximum IV advances - * @param version Game version * @param filter IV filter * * @return IV caches */ - std::array>, 6> getNormalCache(u32 initialAdvance, u32 maxAdvance, Game version, - const StateFilter &filter); + std::array>, 6> getEntralinkCache(u32 initialAdvance, u32 maxAdvance, + const StateFilter &filter); /** - * @brief Returns the IV caches for roamers + * @brief Returns the IV caches for most encounter types * * @param initialAdvance Initial IV advances * @param maxAdvance Maximum IV advances + * @param version Game version * @param filter IV filter * * @return IV caches */ - std::array>, 6> getRoamerCache(u32 initialAdvance, u32 maxAdvance, const StateFilter &filter); + std::array>, 6> getNormalCache(u32 initialAdvance, u32 maxAdvance, Game version, + const StateFilter &filter); /** - * @brief Returns the IV caches for entralink + * @brief Returns the IV caches for roamers * * @param initialAdvance Initial IV advances * @param maxAdvance Maximum IV advances @@ -65,8 +66,7 @@ namespace IVSeedCache * * @return IV caches */ - std::array>, 6> getEntralinkCache(u32 initialAdvance, u32 maxAdvance, - const StateFilter &filter); + std::array>, 6> getRoamerCache(u32 initialAdvance, u32 maxAdvance, const StateFilter &filter); }; #endif // IVSEEDCACHE_HPP diff --git a/Source/Core/Resources/IVs/ivs.bin b/Source/Core/Resources/IVs/ivs.bin index ccffc74d..2de81014 100644 Binary files a/Source/Core/Resources/IVs/ivs.bin and b/Source/Core/Resources/IVs/ivs.bin differ diff --git a/Source/Core/Resources/IVs/main.cpp b/Source/Core/Resources/IVs/main.cpp index 67827551..0d73614e 100644 --- a/Source/Core/Resources/IVs/main.cpp +++ b/Source/Core/Resources/IVs/main.cpp @@ -23,56 +23,14 @@ #include #include -#pragma pack(push, 1) -struct IVSeed -{ - u32 seed; - u16 hp : 1; - u16 atk : 5; - u16 def : 1; - u16 spa : 5; - u16 spd : 1; - u16 spe : 2; -}; -#pragma pack(pop) - -static bool compareIVSeed(const IVSeed &left, const IVSeed &right) -{ - return left.seed < right.seed; -} - -static IVSeed computeIVSeed(u32 seed, u8 hp, u8 atk, u8 def, u8 spa, u8 spd, u8 spe) -{ - IVSeed ivSeed = { 0 }; - - ivSeed.seed = seed; - ivSeed.hp = hp - 30; - ivSeed.atk = atk; - ivSeed.def = def - 30; - ivSeed.spa = spa; - ivSeed.spd = spd - 30; - - // Map speed of 0-1 to 2-3 and 30-31 to 0-1 - if (spe == 0 || spe == 1) - { - ivSeed.spe = 2 + spe; - } - else - { - ivSeed.spe = spe - 30; - } - - return ivSeed; -} - class IVTableSearcher { public: IVTableSearcher() { - std::generate(entralinkSeeds.begin(), entralinkSeeds.end(), [] { return new IVSeed[16384]; }); - std::generate(normalSeeds.begin(), normalSeeds.end(), [] { return new IVSeed[16384]; }); - std::generate(roamerSeeds.begin(), roamerSeeds.end(), [] { return new IVSeed[8192]; }); + std::generate(entralinkSeeds.begin(), entralinkSeeds.end(), [] { return new u32[16384]; }); + std::generate(normalSeeds.begin(), normalSeeds.end(), [] { return new u32[16384]; }); + std::generate(roamerSeeds.begin(), roamerSeeds.end(), [] { return new u32[8192]; }); entralinkSizes.fill(0); normalSizes.fill(0); @@ -122,26 +80,22 @@ class IVTableSearcher threadContainer[i].join(); } - delete[] threadContainer; - } - - void writeResults() - { for (int i = 0; i < entralinkSeeds.size(); i++) { - std::sort(&entralinkSeeds[i][0], &entralinkSeeds[i][entralinkSizes[i]], compareIVSeed); + std::sort(&entralinkSeeds[i][0], &entralinkSeeds[i][entralinkSizes[i]]); } for (int i = 0; i < normalSeeds.size(); i++) { - std::sort(&normalSeeds[i][0], &normalSeeds[i][normalSizes[i]], compareIVSeed); + std::sort(&normalSeeds[i][0], &normalSeeds[i][normalSizes[i]]); } for (int i = 0; i < roamerSeeds.size(); i++) { - std::sort(&roamerSeeds[i][0], &roamerSeeds[i][roamerSizes[i]], compareIVSeed); + std::sort(&roamerSeeds[i][0], &roamerSeeds[i][roamerSizes[i]]); } + // Save results std::ofstream file("ivs.bin", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); if (file.is_open()) { @@ -151,28 +105,30 @@ class IVTableSearcher for (int i = 0; i < entralinkSeeds.size(); i++) { - file.write(reinterpret_cast(entralinkSeeds[i]), sizeof(IVSeed) * entralinkSizes[i]); + file.write(reinterpret_cast(entralinkSeeds[i]), sizeof(u32) * entralinkSizes[i]); } for (int i = 0; i < normalSeeds.size(); i++) { - file.write(reinterpret_cast(normalSeeds[i]), sizeof(IVSeed) * normalSizes[i]); + file.write(reinterpret_cast(normalSeeds[i]), sizeof(u32) * normalSizes[i]); } for (int i = 0; i < roamerSeeds.size(); i++) { - file.write(reinterpret_cast(roamerSeeds[i]), sizeof(IVSeed) * roamerSizes[i]); + file.write(reinterpret_cast(roamerSeeds[i]), sizeof(u32) * roamerSizes[i]); } file.close(); } + + delete[] threadContainer; } private: std::mutex mutex; - std::array entralinkSeeds; - std::array normalSeeds; - std::array roamerSeeds; + std::array entralinkSeeds; + std::array normalSeeds; + std::array roamerSeeds; std::array entralinkSizes; std::array normalSizes; std::array roamerSizes; @@ -181,13 +137,14 @@ class IVTableSearcher { for (u32 seed = start;; seed++) { - MTFast<38, true> mt(seed); + MTFast<37, true> mt(seed); - std::array ivs; + std::array ivs; std::generate(ivs.begin(), ivs.end(), [&mt] { return mt.next(); }); for (u8 i = 0; i < 10; i++) { + // Entralink u8 hp = ivs[i + 22]; u8 atk = ivs[i + 23]; u8 def = ivs[i + 24]; @@ -196,11 +153,11 @@ class IVTableSearcher u8 spe = ivs[i + 27]; if (hp >= 30 && def >= 30 && spd >= 30 && (atk >= 30 || spa >= 30) && (spe <= 1 || spe >= 30)) { - IVSeed ivSeed = computeIVSeed(seed, hp, atk, def, spa, spd, spe); std::lock_guard lock(mutex); - entralinkSeeds[i][entralinkSizes[i]++] = ivSeed; + entralinkSeeds[i][entralinkSizes[i]++] = seed; } + // Normal if (i < 8) { hp = ivs[i]; @@ -212,12 +169,12 @@ class IVTableSearcher if (hp >= 30 && def >= 30 && spd >= 30 && (atk >= 30 || spa >= 30) && (spe <= 1 || spe >= 30)) { - IVSeed ivSeed = computeIVSeed(seed, hp, atk, def, spa, spd, spe); std::lock_guard lock(mutex); - normalSeeds[i][normalSizes[i]++] = ivSeed; + normalSeeds[i][normalSizes[i]++] = seed; } } + // Roamer if (i < 6) { hp = ivs[i + 1]; @@ -229,9 +186,8 @@ class IVTableSearcher if (hp >= 30 && def >= 30 && spd >= 30 && (atk >= 30 || spa >= 30) && spe >= 30) { - IVSeed ivSeed = computeIVSeed(seed, hp, atk, def, spa, spd, spe); std::lock_guard lock(mutex); - roamerSeeds[i][roamerSizes[i]++] = ivSeed; + roamerSeeds[i][roamerSizes[i]++] = seed; } } } @@ -248,5 +204,4 @@ int main() { IVTableSearcher searcher; searcher.startSearch(4); - searcher.writeResults(); }