From 579ed93500f882177bb8c2337844d2640000cebb Mon Sep 17 00:00:00 2001 From: ar664 Date: Tue, 7 Jan 2025 11:02:49 -0500 Subject: [PATCH 1/5] Example of brute force for a generalized filter --- src/main.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index f8dba31..b9fba80 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,97 @@ #include #include +//Unfinished code, proof of concept +//Brute force filtering method, checking all items for those in list + +std::vector itemList; +//std::vector enhancementList //Todo check for enhancements, seals, editions +std::vector amountList; +std::vector anteList; //Until what ante to check for x item in itemList +long filter_all(Instance inst) { + std::vector amountFoundList; + amountFoundList.resize(itemList.size()); + std:fill(amountFoundList.begin(), amountFoundList.end(), 0); + + for (int i = 0; i < itemList.size(); i++) { + + //Check the amount of antes given for that item + for (int ante = 1; ante <= anteList[i]; ante++) { + int max_packs = 4; + if (ante > 1) max_packs = 6; + + int max_store_items = 10; + if (ante > 1) max_store_items = 50; + + int max_tags = 2; + + //Check packs + for (int p = 1; p <= max_packs; p++) { + Pack pack = packInfo(inst.nextPack(ante)); + if (pack.type == itemList[i]) { + amountFoundList[i]++; + continue; + } + + //Do this for each pack type, possibly roll into a function + if (pack.type == Item::Arcana_Pack){ + auto packContents = inst.nextArcanaPack(pack.size, 1); + for (int x = 0; x < pack.size; x++) { + if (packContents[x] == itemList[i]) + amountFoundList[i]++; + } + } + + } + //Check store + for (int s = 1; s <= max_store_items; s++) { + ShopItem shop_item = inst.nextShopItem(ante); + if (shop_item.item == itemList[i]) { + amountFoundList[i]++; + } + } + + //Check vouchers + if (inst.nextVoucher(ante) == itemList[i]) { + amountFoundList[i]++; + } + + //Check tags (Possible improvement is checking for double tags) + for (int t = 1; t <= max_tags; t++) { + Item tag = inst.nextTag(ante); + if (tag == itemList[i]) { + amountFoundList[i]++; + continue; + } + + //Do this for each pack type, possibly roll into a function + if (tag == Item::Buffoon_Tag) { + auto packContents = inst.nextBuffoonPack(2, 1); + for (int x = 0; x < 2; x++) { + if (packContents[x].joker == itemList[i]) + amountFoundList[i]++; + } + } + } + } + //Reset instance (Not sure if I need to do it anywhere else) + inst.reset(inst.seed); + } + + //Check if you have found all the items in a list + int correct_amounts = 0; + for (int i = 0; i < amountList.size(); i++) { + if (amountFoundList[i] >= amountList[i]) { + correct_amounts++; + } + } + if (correct_amounts == amountList.size()) { + return 1; + } + return 0; + +} + long filter(Instance inst) { long legendaries = 0; inst.nextPack(1); From 661a6dd607f75e573043d10702c43327d71b0170 Mon Sep 17 00:00:00 2001 From: ar664 Date: Wed, 8 Jan 2025 14:10:27 -0500 Subject: [PATCH 2/5] Example of filter class to be populated from JSON, using searchable types and objects --- src/filters.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ src/filters.hpp | 57 +++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 src/filters.cpp create mode 100644 src/filters.hpp diff --git a/src/filters.cpp b/src/filters.cpp new file mode 100644 index 0000000..42a9b81 --- /dev/null +++ b/src/filters.cpp @@ -0,0 +1,79 @@ +#include "filters.hpp" +#include "functions.hpp" +#include +#include + +void Filter::parseJSON(std::string input) { + //Populate Lists with variables from the Json + return; +} + + +long searchWithFilter(Instance inst, Filter &filter) { + std::vector amountFoundList; + amountFoundList.resize(filter.searchList.size()); + std:fill(amountFoundList.begin(), amountFoundList.end(), 0); + + for (int ante = 1; ante <= filter.maxAnte; ante++) { + for (int i = 0; i < filter.searchList.size(); i++) { + if (ante > filter.searchList[i].maxAnte) { continue; } + amountFoundList[i] += searchWithObject(inst, filter.searchList[i], ante); + } + } + + //Check if you have found all the items in a list + int correct_amounts = 0; + for (int i = 0; i < filter.searchList.size(); i++) { + if (amountFoundList[i] >= filter.searchList[i].amount) { + correct_amounts++; + } + } + if (correct_amounts == filter.searchList.size()) { + return 1; + } + return 0; + +} + +long searchWithObject(Instance inst, SearchObject searchObject, int ante){ + switch (searchObject.searchType) { + case SearchableType::Joker: + return searchForJoker(inst, searchObject, ante); + default: + return 0; + } +} + +long searchForJoker(Instance inst, SearchObject searchObject, int ante) { + int amount_found = 0; + int max_packs = 4; + if (ante > 1) max_packs = 6; + int max_store_items = 10; + if (ante > 1) max_store_items = 50; + + //Check packs + for (int p = 1; p <= max_packs; p++) { + Pack pack = packInfo(inst.nextPack(ante)); + if (pack.type == Item::Buffoon_Pack || + pack.type == Item::Jumbo_Buffoon_Pack || + pack.type == Item::Mega_Buffoon_Pack) { + auto packContents = inst.nextArcanaPack(pack.size, 1); + for (int x = 0; x < pack.size; x++) { + if (packContents[x] == searchObject.item) { + amount_found++; + } + } + } + continue; + } + + //Check shop + for (int s = 1; s <= max_store_items; s++) { + ShopItem shop_item = inst.nextShopItem(ante); + if (shop_item.item == searchObject.item) { + amount_found++; + } + } + + return amount_found; +} \ No newline at end of file diff --git a/src/filters.hpp b/src/filters.hpp new file mode 100644 index 0000000..fce1785 --- /dev/null +++ b/src/filters.hpp @@ -0,0 +1,57 @@ +#ifndef FILTERS_HPP +#define FILTERS_HPP + +#include "instance.hpp" +#include +#include + +//Defining searchable types here +enum class SearchableType { +//Objects + Joker, + Voucher, + Tag, + Tarot, + Planet, + Spectral, + Card, + Booster_Pack, +//Modifiers + Suit, + Rank, + Enhancement, + Seal, + Edition, +//Other + Deck, + Hand, + Blind + +}; + +struct SearchObject { + Item item; + SearchableType searchType; + int maxAnte; + int amount; +}; + +//Possible optimizations for bigger searchList +//Generating all the items before searching +class Filter { +public: + bool orderedSearch = true; + bool preGenItems = false; + int maxAnte = 1; + + std::vector searchList; + + void parseJSON(std::string input); + long generateObjects(Instance inst); +}; + +long searchWithFilter(Instance inst, Filter &filter); +long searchWithObject(Instance inst, SearchObject searchObject, int ante); +long searchForJoker(Instance inst, SearchObject searchObject, int ante); + +#endif \ No newline at end of file From 975adc5218f4686177016b77e5b21843f475a005 Mon Sep 17 00:00:00 2001 From: ar664 Date: Mon, 13 Jan 2025 16:38:58 -0500 Subject: [PATCH 3/5] Added more example functions. Added instance modifiers to filter class. --- src/filters.cpp | 171 ++++++++++++++++++++++++++++++++++++++++++++++++ src/filters.hpp | 20 ++++++ 2 files changed, 191 insertions(+) diff --git a/src/filters.cpp b/src/filters.cpp index 42a9b81..e4ea68d 100644 --- a/src/filters.cpp +++ b/src/filters.cpp @@ -15,6 +15,7 @@ long searchWithFilter(Instance inst, Filter &filter) { std:fill(amountFoundList.begin(), amountFoundList.end(), 0); for (int ante = 1; ante <= filter.maxAnte; ante++) { + //TODO: Check instance modifiers here, maybe? for (int i = 0; i < filter.searchList.size(); i++) { if (ante > filter.searchList[i].maxAnte) { continue; } amountFoundList[i] += searchWithObject(inst, filter.searchList[i], ante); @@ -39,6 +40,18 @@ long searchWithObject(Instance inst, SearchObject searchObject, int ante){ switch (searchObject.searchType) { case SearchableType::Joker: return searchForJoker(inst, searchObject, ante); + case SearchableType::Tarot: + return searchForTarot(inst, searchObject, ante); + case SearchableType::Planet: + return searchForPlanet(inst, searchObject, ante); + case SearchableType::Spectral: + return searchForSpectral(inst, searchObject, ante); + case SearchableType::Card: + return searchForCard(inst, searchObject, ante); + case SearchableType::Tag: + return searchForTag(inst, searchObject, ante); + case SearchableType::Voucher: + return searchForVoucher(inst, searchObject, ante); default: return 0; } @@ -76,4 +89,162 @@ long searchForJoker(Instance inst, SearchObject searchObject, int ante) { } return amount_found; +} + +long searchForTarot(Instance inst, SearchObject searchObject, int ante) { + int amount_found = 0; + int max_packs = 4; + if (ante > 1) max_packs = 6; + int max_store_items = 10; + if (ante > 1) max_store_items = 50; + + //Check packs + for (int p = 1; p <= max_packs; p++) { + Pack pack = packInfo(inst.nextPack(ante)); + if (pack.type == Item::Arcana_Pack || + pack.type == Item::Jumbo_Arcana_Pack || + pack.type == Item::Mega_Arcana_Pack) { + auto packContents = inst.nextArcanaPack(pack.size, 1); + for (int x = 0; x < pack.size; x++) { + if (packContents[x] == searchObject.item) { + amount_found++; + } + } + } + continue; + } + + //Check shop + for (int s = 1; s <= max_store_items; s++) { + ShopItem shop_item = inst.nextShopItem(ante); + if (shop_item.item == searchObject.item) { + amount_found++; + } + } + + return amount_found; +} + +long searchForPlanet(Instance inst, SearchObject searchObject, int ante) { + int amount_found = 0; + int max_packs = 4; + if (ante > 1) max_packs = 6; + int max_store_items = 10; + if (ante > 1) max_store_items = 50; + + //Check packs + for (int p = 1; p <= max_packs; p++) { + Pack pack = packInfo(inst.nextPack(ante)); + if (pack.type == Item::Celestial_Pack || + pack.type == Item::Jumbo_Celestial_Pack || + pack.type == Item::Mega_Celestial_Pack) { + auto packContents = inst.nextArcanaPack(pack.size, 1); + for (int x = 0; x < pack.size; x++) { + if (packContents[x] == searchObject.item) { + amount_found++; + } + } + } + continue; + } + + //Check shop + for (int s = 1; s <= max_store_items; s++) { + ShopItem shop_item = inst.nextShopItem(ante); + if (shop_item.item == searchObject.item) { + amount_found++; + } + } + + return amount_found; +} + +long searchForSpectral(Instance inst, SearchObject searchObject, int ante) { + int amount_found = 0; + int max_packs = 4; + if (ante > 1) max_packs = 6; + int max_store_items = 10; + if (ante > 1) max_store_items = 50; + + //Check packs + for (int p = 1; p <= max_packs; p++) { + Pack pack = packInfo(inst.nextPack(ante)); + if (pack.type == Item::Spectral_Pack || + pack.type == Item::Jumbo_Spectral_Pack || + pack.type == Item::Mega_Spectral_Pack) { + auto packContents = inst.nextArcanaPack(pack.size, 1); + for (int x = 0; x < pack.size; x++) { + if (packContents[x] == searchObject.item) { + amount_found++; + } + } + } + continue; + } + + //Check shop TODO: Setup instance + /*for (int s = 1; s <= max_store_items; s++) { + ShopItem shop_item = inst.nextShopItem(ante); + if (shop_item.item == searchObject.item) { + amount_found++; + } + }*/ + + return amount_found; +} + +long searchForCard(Instance inst, SearchObject searchObject, int ante) { + int amount_found = 0; + int max_packs = 4; + if (ante > 1) max_packs = 6; + int max_store_items = 10; + if (ante > 1) max_store_items = 50; + + //Check packs + for (int p = 1; p <= max_packs; p++) { + Pack pack = packInfo(inst.nextPack(ante)); + if (pack.type == Item::Standard_Pack || + pack.type == Item::Jumbo_Standard_Pack || + pack.type == Item::Mega_Standard_Pack) { + auto packContents = inst.nextArcanaPack(pack.size, 1); + for (int x = 0; x < pack.size; x++) { + if (packContents[x] == searchObject.item) { + amount_found++; + } + } + } + continue; + } + + //Check shop TODO: Setup instance + /*for (int s = 1; s <= max_store_items; s++) { + ShopItem shop_item = inst.nextShopItem(ante); + if (shop_item.item == searchObject.item) { + amount_found++; + } + }*/ + + return amount_found; +} + + +long seachForTag(Instance inst, SearchObject searchObject, int ante) { + int amount_found = 0; + + for(int i = 1; i <=2; i++) { + if(inst.nextTag(ante) == searchObject.item) { + amount_found++; + } + } + + return amount_found; +} + +//TODO: Setup instance prior to calling this +// May want to seperate ante 1 loop for examples like perkeo_observatory +long searchForVoucher(Instance inst, SearchObject searchObject, int ante) { + if(inst.nextVoucher(ante) == searchObject.item) { + return 1; + } + return 0; } \ No newline at end of file diff --git a/src/filters.hpp b/src/filters.hpp index fce1785..3388bf2 100644 --- a/src/filters.hpp +++ b/src/filters.hpp @@ -36,6 +36,12 @@ struct SearchObject { int amount; }; +struct InstanceModifier { + Item modifier; + int startAnte; + int maxAnte; +}; + //Possible optimizations for bigger searchList //Generating all the items before searching class Filter { @@ -45,6 +51,7 @@ class Filter { int maxAnte = 1; std::vector searchList; + std::vector instanceModList; void parseJSON(std::string input); long generateObjects(Instance inst); @@ -52,6 +59,19 @@ class Filter { long searchWithFilter(Instance inst, Filter &filter); long searchWithObject(Instance inst, SearchObject searchObject, int ante); + +//Appear in shop & packs +//TODO: Possibly combine some of these functions (They use similar code) long searchForJoker(Instance inst, SearchObject searchObject, int ante); +long searchForTarot(Instance inst, SearchObject searchObject, int ante); +long searchForPlanet(Instance inst, SearchObject searchObject, int ante); + +//Appear in packs (mostly) +long searchForSpectral(Instance inst, SearchObject searchObject, int ante); +long searchForCard(Instance inst, SearchObject searchObject, int ante); + +//Appears on ante +long searchForTag(Instance inst, SearchObject searchObject, int ante); +long searchForVoucher(Instance inst, SearchObject searchObject, int ante); #endif \ No newline at end of file From 0495b367a7004988735adb6fb2592e6e10108f46 Mon Sep 17 00:00:00 2001 From: ar664 Date: Wed, 15 Jan 2025 16:31:11 -0500 Subject: [PATCH 4/5] Built, ran, and tested sucessfully. Awfully slow at ~1m-500k seeds/s with just the search for 1 joker Further optimizations needed, but it did find seeds with a blueprint joker in shop. --- CMakeLists.txt | 1 + src/filters.cpp | 63 ++++++++++------------- src/filters.hpp | 27 +++++----- src/main.cpp | 134 ++++++++++++++---------------------------------- 4 files changed, 81 insertions(+), 144 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f2b8e8..b5937ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(LIB_SOURCES src/functions.hpp src/instance.hpp + src/filters.cpp src/items.cpp src/rng.cpp src/search.cpp diff --git a/src/filters.cpp b/src/filters.cpp index e4ea68d..7c98be4 100644 --- a/src/filters.cpp +++ b/src/filters.cpp @@ -10,13 +10,12 @@ void Filter::parseJSON(std::string input) { long searchWithFilter(Instance inst, Filter &filter) { - std::vector amountFoundList; - amountFoundList.resize(filter.searchList.size()); - std:fill(amountFoundList.begin(), amountFoundList.end(), 0); + int searchSize = filter.searchList.size(); + std::vector amountFoundList(searchSize, 0); for (int ante = 1; ante <= filter.maxAnte; ante++) { //TODO: Check instance modifiers here, maybe? - for (int i = 0; i < filter.searchList.size(); i++) { + for (int i = 0; i < searchSize; i++) { if (ante > filter.searchList[i].maxAnte) { continue; } amountFoundList[i] += searchWithObject(inst, filter.searchList[i], ante); } @@ -24,19 +23,20 @@ long searchWithFilter(Instance inst, Filter &filter) { //Check if you have found all the items in a list int correct_amounts = 0; - for (int i = 0; i < filter.searchList.size(); i++) { + for (int i = 0; i < searchSize; i++) { if (amountFoundList[i] >= filter.searchList[i].amount) { correct_amounts++; } } - if (correct_amounts == filter.searchList.size()) { + if (correct_amounts == searchSize) { return 1; } + return 0; } -long searchWithObject(Instance inst, SearchObject searchObject, int ante){ +inline long searchWithObject(Instance inst, SearchObject &searchObject, int ante){ switch (searchObject.searchType) { case SearchableType::Joker: return searchForJoker(inst, searchObject, ante); @@ -57,33 +57,26 @@ long searchWithObject(Instance inst, SearchObject searchObject, int ante){ } } -long searchForJoker(Instance inst, SearchObject searchObject, int ante) { +long searchForJoker(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; - int max_store_items = 10; - if (ante > 1) max_store_items = 50; - //Check packs - for (int p = 1; p <= max_packs; p++) { - Pack pack = packInfo(inst.nextPack(ante)); - if (pack.type == Item::Buffoon_Pack || - pack.type == Item::Jumbo_Buffoon_Pack || - pack.type == Item::Mega_Buffoon_Pack) { - auto packContents = inst.nextArcanaPack(pack.size, 1); - for (int x = 0; x < pack.size; x++) { - if (packContents[x] == searchObject.item) { - amount_found++; - } - } + //Checking the next X jokers that appear in shop and then + //counting shop items which are jokers might be faster than + //calling next shop item X times + //nextShopItem instantiates a new shop object every call, allocating wasteful mem. + //for now we'll just approximate it at ~25% of the store depth given + + int max_store_items = (searchObject.storeDepth >> 2) + 1; + for(int s = 1; s <= max_store_items; s++) { + if (inst.nextJoker(ItemSource::Shop, ante, false).joker == searchObject.item) { + amount_found++; } - continue; } - //Check shop - for (int s = 1; s <= max_store_items; s++) { - ShopItem shop_item = inst.nextShopItem(ante); - if (shop_item.item == searchObject.item) { + for (int p = 1; p <= max_packs; p++) { + if (inst.nextJoker(ItemSource::Buffoon_Pack, ante, false).joker == searchObject.item) { amount_found++; } } @@ -91,7 +84,7 @@ long searchForJoker(Instance inst, SearchObject searchObject, int ante) { return amount_found; } -long searchForTarot(Instance inst, SearchObject searchObject, int ante) { +long searchForTarot(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; @@ -125,7 +118,7 @@ long searchForTarot(Instance inst, SearchObject searchObject, int ante) { return amount_found; } -long searchForPlanet(Instance inst, SearchObject searchObject, int ante) { +long searchForPlanet(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; @@ -159,7 +152,7 @@ long searchForPlanet(Instance inst, SearchObject searchObject, int ante) { return amount_found; } -long searchForSpectral(Instance inst, SearchObject searchObject, int ante) { +long searchForSpectral(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; @@ -185,7 +178,7 @@ long searchForSpectral(Instance inst, SearchObject searchObject, int ante) { //Check shop TODO: Setup instance /*for (int s = 1; s <= max_store_items; s++) { ShopItem shop_item = inst.nextShopItem(ante); - if (shop_item.item == searchObject.item) { + if (shop_item.item == &searchObject.item) { amount_found++; } }*/ @@ -193,7 +186,7 @@ long searchForSpectral(Instance inst, SearchObject searchObject, int ante) { return amount_found; } -long searchForCard(Instance inst, SearchObject searchObject, int ante) { +long searchForCard(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; @@ -219,7 +212,7 @@ long searchForCard(Instance inst, SearchObject searchObject, int ante) { //Check shop TODO: Setup instance /*for (int s = 1; s <= max_store_items; s++) { ShopItem shop_item = inst.nextShopItem(ante); - if (shop_item.item == searchObject.item) { + if (shop_item.item == &searchObject.item) { amount_found++; } }*/ @@ -228,7 +221,7 @@ long searchForCard(Instance inst, SearchObject searchObject, int ante) { } -long seachForTag(Instance inst, SearchObject searchObject, int ante) { +long searchForTag(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; for(int i = 1; i <=2; i++) { @@ -242,7 +235,7 @@ long seachForTag(Instance inst, SearchObject searchObject, int ante) { //TODO: Setup instance prior to calling this // May want to seperate ante 1 loop for examples like perkeo_observatory -long searchForVoucher(Instance inst, SearchObject searchObject, int ante) { +long searchForVoucher(Instance inst, SearchObject &searchObject, int ante) { if(inst.nextVoucher(ante) == searchObject.item) { return 1; } diff --git a/src/filters.hpp b/src/filters.hpp index 3388bf2..629feeb 100644 --- a/src/filters.hpp +++ b/src/filters.hpp @@ -1,7 +1,7 @@ #ifndef FILTERS_HPP #define FILTERS_HPP -#include "instance.hpp" +#include "functions.hpp" #include #include @@ -32,14 +32,15 @@ enum class SearchableType { struct SearchObject { Item item; SearchableType searchType; - int maxAnte; - int amount; + int8_t storeDepth; + int8_t maxAnte; + int8_t amount; }; struct InstanceModifier { Item modifier; - int startAnte; - int maxAnte; + int8_t startAnte; + int8_t maxAnte; }; //Possible optimizations for bigger searchList @@ -58,20 +59,20 @@ class Filter { }; long searchWithFilter(Instance inst, Filter &filter); -long searchWithObject(Instance inst, SearchObject searchObject, int ante); +long searchWithObject(Instance inst, SearchObject &searchObject, int ante); //Appear in shop & packs //TODO: Possibly combine some of these functions (They use similar code) -long searchForJoker(Instance inst, SearchObject searchObject, int ante); -long searchForTarot(Instance inst, SearchObject searchObject, int ante); -long searchForPlanet(Instance inst, SearchObject searchObject, int ante); +long searchForJoker(Instance inst, SearchObject &searchObject, int ante); +long searchForTarot(Instance inst, SearchObject &searchObject, int ante); +long searchForPlanet(Instance inst, SearchObject &searchObject, int ante); //Appear in packs (mostly) -long searchForSpectral(Instance inst, SearchObject searchObject, int ante); -long searchForCard(Instance inst, SearchObject searchObject, int ante); +long searchForSpectral(Instance inst, SearchObject &searchObject, int ante); +long searchForCard(Instance inst, SearchObject &searchObject, int ante); //Appears on ante -long searchForTag(Instance inst, SearchObject searchObject, int ante); -long searchForVoucher(Instance inst, SearchObject searchObject, int ante); +long searchForTag(Instance inst, SearchObject &searchObject, int ante); +long searchForVoucher(Instance inst, SearchObject &searchObject, int ante); #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b9fba80..b0e78ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,99 +1,11 @@ #include "functions.hpp" #include "search.hpp" +#include "filters.hpp" #include #include #include -//Unfinished code, proof of concept -//Brute force filtering method, checking all items for those in list - -std::vector itemList; -//std::vector enhancementList //Todo check for enhancements, seals, editions -std::vector amountList; -std::vector anteList; //Until what ante to check for x item in itemList -long filter_all(Instance inst) { - std::vector amountFoundList; - amountFoundList.resize(itemList.size()); - std:fill(amountFoundList.begin(), amountFoundList.end(), 0); - - for (int i = 0; i < itemList.size(); i++) { - - //Check the amount of antes given for that item - for (int ante = 1; ante <= anteList[i]; ante++) { - int max_packs = 4; - if (ante > 1) max_packs = 6; - - int max_store_items = 10; - if (ante > 1) max_store_items = 50; - - int max_tags = 2; - - //Check packs - for (int p = 1; p <= max_packs; p++) { - Pack pack = packInfo(inst.nextPack(ante)); - if (pack.type == itemList[i]) { - amountFoundList[i]++; - continue; - } - - //Do this for each pack type, possibly roll into a function - if (pack.type == Item::Arcana_Pack){ - auto packContents = inst.nextArcanaPack(pack.size, 1); - for (int x = 0; x < pack.size; x++) { - if (packContents[x] == itemList[i]) - amountFoundList[i]++; - } - } - - } - //Check store - for (int s = 1; s <= max_store_items; s++) { - ShopItem shop_item = inst.nextShopItem(ante); - if (shop_item.item == itemList[i]) { - amountFoundList[i]++; - } - } - - //Check vouchers - if (inst.nextVoucher(ante) == itemList[i]) { - amountFoundList[i]++; - } - - //Check tags (Possible improvement is checking for double tags) - for (int t = 1; t <= max_tags; t++) { - Item tag = inst.nextTag(ante); - if (tag == itemList[i]) { - amountFoundList[i]++; - continue; - } - - //Do this for each pack type, possibly roll into a function - if (tag == Item::Buffoon_Tag) { - auto packContents = inst.nextBuffoonPack(2, 1); - for (int x = 0; x < 2; x++) { - if (packContents[x].joker == itemList[i]) - amountFoundList[i]++; - } - } - } - } - //Reset instance (Not sure if I need to do it anywhere else) - inst.reset(inst.seed); - } - - //Check if you have found all the items in a list - int correct_amounts = 0; - for (int i = 0; i < amountList.size(); i++) { - if (amountFoundList[i] >= amountList[i]) { - correct_amounts++; - } - } - if (correct_amounts == amountList.size()) { - return 1; - } - return 0; - -} +Filter globalFilter; long filter(Instance inst) { long legendaries = 0; @@ -238,11 +150,15 @@ long filter_test(Instance inst) { return 0; } +long filter_custom(Instance inst) { + return searchWithFilter(inst, globalFilter); +} + // Benchmark function // Runs 1 billion seeds of perkeo observatory // And prints total time and seeds per second void benchmark() { - long total = 0; + //long total = 0; long start = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); @@ -260,7 +176,7 @@ void benchmark() { } void benchmark_quick() { - long total = 0; + //long total = 0; long start = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); @@ -278,7 +194,7 @@ void benchmark_quick() { } void benchmark_quick_lucky() { - long total = 0; + //long total = 0; long start = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); @@ -296,7 +212,7 @@ void benchmark_quick_lucky() { } void benchmark_single() { - long total = 0; + //long total = 0; long start = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); @@ -314,7 +230,7 @@ void benchmark_single() { } void benchmark_blank() { - long total = 0; + //long total = 0; long start = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); @@ -330,11 +246,37 @@ void benchmark_blank() { << 100000000 / ((end - start) / 1000.0) << "\n"; } +void benchmark_custom() { + //long total = 0; + long start = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + Search search(filter_custom, "IMMOLATE", 12, 100000000); + search.highScore = 10; // No output + search.printDelay = 100000000000; + search.search(); + long end = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + std::cout << "----CUSTOM FILTER----\n"; + std::cout << "Total time: " << end - start << "ms\n"; + std::cout << "Seeds per second: " << std::fixed << std::setprecision(0) + << 100000000 / ((end - start) / 1000.0) << "\n"; +} + +void setup_custom_filter() { + globalFilter.maxAnte = 1; + globalFilter.searchList = std::vector(); + globalFilter.searchList.push_back({Item::Blueprint, SearchableType::Joker, 40, 1, 1}); +} + int main() { + setup_custom_filter(); + benchmark_blank(); benchmark_single(); benchmark_quick(); + benchmark_custom(); benchmark_quick_lucky(); - benchmark_blank(); benchmark(); return 1; } \ No newline at end of file From 168800cf587641c677eaf864aa009296d0700d66 Mon Sep 17 00:00:00 2001 From: ar664 Date: Mon, 27 Jan 2025 13:32:12 -0500 Subject: [PATCH 5/5] Optimized looking for jokers by adding Instance.nextJokerOnly Started using Tracy to profile the performance. --- CMakeLists.txt | 21 +++++++++++++++++++-- src/filters.cpp | 32 ++++++++++++++++---------------- src/filters.hpp | 4 +++- src/functions.hpp | 36 ++++++++++++++++++++++++++++++++++++ src/instance.hpp | 1 + src/main.cpp | 20 +++++++++++++------- src/util.hpp | 1 + 7 files changed, 89 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5937ae..0def394 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,12 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +include(FetchContent) +option(TRACY_ENABLE "" ON) +include_directories( + ${PROJECT_SOURCE_DIR}/tracy +) + # Define sources for the library set(LIB_SOURCES src/functions.hpp @@ -17,18 +23,29 @@ set(LIB_SOURCES src/seed.cpp src/util.cpp src/functions.cpp + tracy/tracy/Tracy.hpp +) + +FetchContent_Declare ( + tracy + GIT_REPOSITORY https://github.com/wolfpld/tracy.git + GIT_TAG master + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE ) +FetchContent_MakeAvailable(tracy) # Define sources for the executable set(EXECUTABLE_SOURCES src/main.cpp + tracy/TracyClient.cpp ) # Set optimization flags based on the compiler if(MSVC) set(OPTIMIZATION_FLAGS "/Ox") # Full optimization for MSVC else() - set(OPTIMIZATION_FLAGS "-O3 -g -std=c++20 -Wall -Wextra -Wpedantic -Wno-c++17-extensions -gdwarf-3 -ldl") # Full optimization for GCC/Clang, plus debugging info + set(OPTIMIZATION_FLAGS "-O3 -g -std=c++20 -Wall -Wextra -Wpedantic -Wno-c++17-extensions -gdwarf-3 -march=native -lpthread -ldl") # Full optimization for GCC/Clang, plus debugging info endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPTIMIZATION_FLAGS}") @@ -62,4 +79,4 @@ generate_export_header(${PROJECT_NAME} ) add_executable(immol ${EXECUTABLE_SOURCES}) -target_link_libraries(immol ${PROJECT_NAME}) \ No newline at end of file +target_link_libraries(immol ${PROJECT_NAME} TracyClient) \ No newline at end of file diff --git a/src/filters.cpp b/src/filters.cpp index 7c98be4..d18dbf7 100644 --- a/src/filters.cpp +++ b/src/filters.cpp @@ -1,5 +1,4 @@ #include "filters.hpp" -#include "functions.hpp" #include #include @@ -11,10 +10,15 @@ void Filter::parseJSON(std::string input) { long searchWithFilter(Instance inst, Filter &filter) { int searchSize = filter.searchList.size(); - std::vector amountFoundList(searchSize, 0); + int modSize = filter.instanceModList.size(); + int amountFoundList[MAX_SEARCH_LIST_SIZE] = {0}; for (int ante = 1; ante <= filter.maxAnte; ante++) { - //TODO: Check instance modifiers here, maybe? + for(int m = 1; m <= modSize; m++) { + if(m >= filter.instanceModList[m-1].startAnte && m <= filter.instanceModList[m-1].endAnte) { + inst.unlock(filter.instanceModList[m].modifier); + } + } for (int i = 0; i < searchSize; i++) { if (ante > filter.searchList[i].maxAnte) { continue; } amountFoundList[i] += searchWithObject(inst, filter.searchList[i], ante); @@ -62,21 +66,17 @@ long searchForJoker(Instance inst, SearchObject &searchObject, int ante) { int max_packs = 4; if (ante > 1) max_packs = 6; - //Checking the next X jokers that appear in shop and then - //counting shop items which are jokers might be faster than - //calling next shop item X times - //nextShopItem instantiates a new shop object every call, allocating wasteful mem. - //for now we'll just approximate it at ~25% of the store depth given + //I created nextJokerOnly to save on mem + //for now we'll just use storedepth given - int max_store_items = (searchObject.storeDepth >> 2) + 1; - for(int s = 1; s <= max_store_items; s++) { - if (inst.nextJoker(ItemSource::Shop, ante, false).joker == searchObject.item) { + for(int s = 1; s <= searchObject.storeDepth; s++) { + if (inst.nextJokerOnly(ItemSource::Shop, ante) == searchObject.item) { amount_found++; } } for (int p = 1; p <= max_packs; p++) { - if (inst.nextJoker(ItemSource::Buffoon_Pack, ante, false).joker == searchObject.item) { + if (inst.nextJokerOnly(ItemSource::Buffoon_Pack, ante) == searchObject.item) { amount_found++; } } @@ -156,8 +156,8 @@ long searchForSpectral(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; - int max_store_items = 10; - if (ante > 1) max_store_items = 50; + // int max_store_items = 10; + // if (ante > 1) max_store_items = 50; //Check packs for (int p = 1; p <= max_packs; p++) { @@ -190,8 +190,8 @@ long searchForCard(Instance inst, SearchObject &searchObject, int ante) { int amount_found = 0; int max_packs = 4; if (ante > 1) max_packs = 6; - int max_store_items = 10; - if (ante > 1) max_store_items = 50; + // int max_store_items = 10; + // if (ante > 1) max_store_items = 50; //Check packs for (int p = 1; p <= max_packs; p++) { diff --git a/src/filters.hpp b/src/filters.hpp index 629feeb..5388028 100644 --- a/src/filters.hpp +++ b/src/filters.hpp @@ -40,7 +40,7 @@ struct SearchObject { struct InstanceModifier { Item modifier; int8_t startAnte; - int8_t maxAnte; + int8_t endAnte; }; //Possible optimizations for bigger searchList @@ -58,6 +58,8 @@ class Filter { long generateObjects(Instance inst); }; +#define MAX_SEARCH_LIST_SIZE 10 + long searchWithFilter(Instance inst, Filter &filter); long searchWithObject(Instance inst, SearchObject &searchObject, int ante); diff --git a/src/functions.hpp b/src/functions.hpp index f9599bd..42bf693 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -231,6 +231,42 @@ inline Item Instance::nextSpectral(std::string source, int ante, return randchoice(RandomType::Spectral + source + anteStr, SPECTRALS); } +inline Item Instance::nextJokerOnly(std::string source, int ante) { + std::string anteStr = anteToString(ante); + + // Get rarity + Item rarity; + double rarityPoll = random(RandomType::Joker_Rarity + anteStr + source); + if (rarityPoll > 0.95) + rarity = Item::Rare; + else if (rarityPoll > 0.7) + rarity = Item::Uncommon; + else + rarity = Item::Common; + + // Get next joker + Item joker; + if (rarity == Item::Legendary) { + if (params.version > 10099) { + joker = randchoice(RandomType::Joker_Legendary, LEGENDARY_JOKERS); + } else { + joker = randchoice(RandomType::Joker_Legendary + source + anteStr, + LEGENDARY_JOKERS); + } + } else if (rarity == Item::Rare) { + joker = randchoice(RandomType::Joker_Rare + source + anteStr, + RARE_JOKERS); + } else if (rarity == Item::Uncommon) { + joker = randchoice(RandomType::Joker_Uncommon + source + anteStr, + UNCOMMON_JOKERS); + } else if (rarity == Item::Common) { + joker = randchoice(RandomType::Joker_Common + source + anteStr, + COMMON_JOKERS); + } + + return joker; +} + inline JokerData Instance::nextJoker(std::string source, int ante, bool hasStickers) { std::string anteStr = anteToString(ante); diff --git a/src/instance.hpp b/src/instance.hpp index 4489a81..4d2ae89 100644 --- a/src/instance.hpp +++ b/src/instance.hpp @@ -116,6 +116,7 @@ struct Instance { Item nextPlanet(std::string source, int ante, bool soulable); Item nextSpectral(std::string source, int ante, bool soulable); JokerData nextJoker(std::string source, int ante, bool hasStickers); + Item nextJokerOnly(std::string source, int ante); ShopInstance getShopInstance(); ShopItem nextShopItem(int ante); Item nextPack(int ante); diff --git a/src/main.cpp b/src/main.cpp index b0e78ea..8beac4d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "tracy/Tracy.hpp" Filter globalFilter; @@ -246,12 +247,14 @@ void benchmark_blank() { << 100000000 / ((end - start) / 1000.0) << "\n"; } +#define TEMP_TEST_SIZE 10000000 + void benchmark_custom() { //long total = 0; long start = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); - Search search(filter_custom, "IMMOLATE", 12, 100000000); + Search search(filter_custom, "IMMOLATE", 12, TEMP_TEST_SIZE); search.highScore = 10; // No output search.printDelay = 100000000000; search.search(); @@ -261,22 +264,25 @@ void benchmark_custom() { std::cout << "----CUSTOM FILTER----\n"; std::cout << "Total time: " << end - start << "ms\n"; std::cout << "Seeds per second: " << std::fixed << std::setprecision(0) - << 100000000 / ((end - start) / 1000.0) << "\n"; + << TEMP_TEST_SIZE / ((end - start) / 1000.0) << "\n"; } void setup_custom_filter() { - globalFilter.maxAnte = 1; + globalFilter.maxAnte = 2; globalFilter.searchList = std::vector(); - globalFilter.searchList.push_back({Item::Blueprint, SearchableType::Joker, 40, 1, 1}); + globalFilter.searchList.push_back({Item::Blueprint, SearchableType::Joker, 5, 1, 1}); + //globalFilter.searchList.push_back({Item::Telescope, SearchableType::Voucher, 1, 1, 1}); + //globalFilter.searchList.push_back({Item::Observatory, SearchableType::Voucher, 1, 2, 1}); + //globalFilter.instanceModList.push_back({Item::Observatory, 2, 2}); } int main() { setup_custom_filter(); benchmark_blank(); - benchmark_single(); + //benchmark_single(); benchmark_quick(); benchmark_custom(); - benchmark_quick_lucky(); - benchmark(); + //benchmark_quick_lucky(); + //benchmark(); return 1; } \ No newline at end of file diff --git a/src/util.hpp b/src/util.hpp index 4fbbe4e..8435d44 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "tracy/Tracy.hpp" const uint64_t MAX_UINT64 = 18446744073709551615ull;