@@ -49,12 +49,12 @@ void wait() {
4949#endif
5050
5151struct Entry {
52- std::string name;
52+ std::string name = " " ;
5353 int prob = 0 ;
5454};
5555
5656struct TC {
57- std::string name;
57+ std::string name = " " ;
5858 int group = 0 ;
5959 int level = 0 ;
6060 int picks = 0 ;
@@ -76,11 +76,11 @@ struct AtomicTC {
7676};
7777
7878struct Drop {
79- std::string name;
80- int magic;
81- int rare;
82- int set;
83- int unique;
79+ std::string name = " " ;
80+ int magic = 0 ;
81+ int rare = 0 ;
82+ int set = 0 ;
83+ int unique = 0 ;
8484
8585 bool operator ==(const Drop& other) const {
8686 return name == other.name && magic == other.magic && rare == other.rare && set == other.set && unique == other.unique ;
@@ -100,15 +100,18 @@ namespace std {
100100 };
101101}
102102
103+ struct ThreadStorage {
104+ std::unordered_map<Drop, long > totaldrops;
105+ long totalsims = 0 ;
106+ long totalpicks = 0 ;
107+ };
108+
103109std::unordered_map<std::string, AtomicTC> atomic;
104110std::unordered_map<std::string, TC> treasureClasses;
105111
106112long playermod = 1 ;
107113int finditem = 0 ;
108114
109- std::random_device rd;
110- std::mt19937 gen (rd());
111-
112115// Helper function to split string by tab delimiter, keeping empty strings between tabs
113116std::vector<std::string> splitByChar (const std::string& str, char delimiter) {
114117 std::vector<std::string> tokens;
@@ -126,7 +129,7 @@ std::vector<std::string> splitByChar(const std::string& str, char delimiter) {
126129 return tokens;
127130}
128131
129- void pickAtomic (std::string tcname, int magic, int rare, int set, int unique, std::vector<Drop>& drops) {
132+ void pickAtomic (std::mt19937& gen, std:: string tcname, int magic, int rare, int set, int unique, std::vector<Drop>& drops) {
130133 if (atomic.find (tcname) == atomic.end ()) {
131134 #ifdef DEBUG
132135 std::cout << " Added " << tcname << std::endl;
@@ -180,13 +183,13 @@ long calcNodrop(long e, long nd, long d) {
180183 return (long )(_d / (pow ((_nd + _d) / nd, _e) - 1 ));
181184}
182185
183- void pick (std::string tcname, int magic, int rare, int set, int unique, std::vector<Drop>& drops, int depth = 0 ) {
186+ void pick (std::mt19937& gen, std:: string tcname, int magic, int rare, int set, int unique, std::vector<Drop>& drops, int depth = 0 ) {
184187 if (drops.size () >= 6 ) {
185188 return ;
186189 }
187190
188191 if (treasureClasses.find (tcname) == treasureClasses.end ()) {
189- pickAtomic (tcname, magic, rare, set, unique, drops);
192+ pickAtomic (gen, tcname, magic, rare, set, unique, drops);
190193 return ;
191194 }
192195
@@ -269,7 +272,7 @@ void pick(std::string tcname, int magic, int rare, int set, int unique, std::vec
269272 std::cout << item.name << " picked" << std::endl;
270273 wait ();
271274 #endif
272- pick (item.name , magic, rare, set, unique, drops, depth + 1 );
275+ pick (gen, item.name , magic, rare, set, unique, drops, depth + 1 );
273276 break ;
274277 }
275278
@@ -293,7 +296,7 @@ void pick(std::string tcname, int magic, int rare, int set, int unique, std::vec
293296 std::cout << tc.name << " picked" << std::endl;
294297 wait ();
295298 #endif
296- pick (item.name , magic, rare, set, unique, drops, depth + 1 );
299+ pick (gen, item.name , magic, rare, set, unique, drops, depth + 1 );
297300 picks--;
298301 }
299302 }
@@ -397,7 +400,6 @@ int main(int argc, char* argv[]) {
397400
398401 path = realpath (path) + DIRECTORY_SEPARATOR_STRING;
399402 std::string txtDir = realpath (path + " txt" ) + DIRECTORY_SEPARATOR_STRING;
400- std::string simulationsPath = realpath (path + " simulations" ) + DIRECTORY_SEPARATOR_STRING;
401403
402404 std::string tcname = argv[1 ];
403405
@@ -412,8 +414,6 @@ int main(int argc, char* argv[]) {
412414 finditem = atoi (argv[3 ]);
413415 }
414416
415- int dropcycles = 300000 ;
416-
417417 // Open the treasure class file at: txt/treasureclassex.txt
418418 FILE* tex = fopen ((txtDir + (BASETC ? " base/treasureclassex.txt" : " treasureclassex.txt" )).c_str (), " r" );
419419 if (!tex) {
@@ -527,11 +527,11 @@ int main(int argc, char* argv[]) {
527527 }
528528
529529 #ifdef DEBUG
530- int thread_count = 1 ;
530+ size_t thread_count = 1 ;
531531 #else
532532 // Get CPU count.
533- int thread_count = std::thread::hardware_concurrency (); // Use 2/3 of available threads to avoid overloading the system
534- thread_count = std::max (1 , thread_count - 6 );
533+ size_t thread_count = std::thread::hardware_concurrency (); // Use 2/3 of available threads to avoid overloading the system
534+ thread_count = std::max (size_t ( 1 ) , thread_count - 6 );
535535 #endif
536536
537537 if (thread_count < 1 ) {
@@ -544,110 +544,107 @@ int main(int argc, char* argv[]) {
544544 }
545545 }
546546
547- long mindropcount = 676 ;
547+ long mindropcount = 700 ;
548548
549549 if (argc >= 5 ) {
550550 mindropcount = atoi (argv[4 ]);
551551 }
552552
553553 mindropcount = std::max (1L , mindropcount);
554-
555554 mindropcount /= thread_count;
556555
557556 std::vector<std::thread> threads;
558- std::atomic<long > totalsims = 0 ;
559-
560557 std::unordered_map<Drop, long > dropsToFind;
558+ std::vector<ThreadStorage> threadStorage (thread_count);
561559 populate (tcname, 0 , 0 , 0 , 0 , dropsToFind);
562560
563- for (int i = 0 ; i < thread_count; i++) {
564- threads.emplace_back ([i, thread_count, &tcname, &dropsToFind, dropcycles, mindropcount, &simulationsPath, &totalsims]() {
565- long totalruns = 0 ;
566- long totalpicks = 0 ;
567-
568- std::unordered_map<Drop, long > totaldrops;
561+ for (size_t i = 0 ; i < thread_count; i++) {
562+ threads.emplace_back ([i, thread_count, &tcname, &dropsToFind, mindropcount, &threadStorage]() {
563+ std::random_device rd;
564+ std::mt19937 gen (rd ());
569565
570566 for (const auto & drop : dropsToFind) {
571- totaldrops[drop.first ] = 0 ;
567+ threadStorage[i]. totaldrops [drop.first ] = 0 ;
572568 }
573569
574- for (size_t seq = 0 ; true ; seq++) {
575- for (long j = 0 ; j < dropcycles; j++) {
576- #ifdef DEBUG
577- std::cout << " Cycle start" << std::endl;
578- wait ();
579- #endif
580- std::vector<Drop> rundrops;
581- pick (tcname, 0 , 0 , 0 , 0 , rundrops);
570+ bool allAboveMin = false ;
582571
583- for (const auto & drop : rundrops) {
584- totaldrops[drop]++;
585- totalpicks++;
586- }
572+ while (!allAboveMin) {
573+ std::vector<Drop> rundrops;
574+ pick (gen, tcname, 0 , 0 , 0 , 0 , rundrops);
587575
588- totalruns++;
576+ for (const auto & drop : rundrops) {
577+ threadStorage[i].totaldrops [drop]++;
578+ threadStorage[i].totalpicks ++;
589579 }
590580
581+ threadStorage[i].totalsims ++;
582+
591583 // Check if all items have at least mindropcount drops, and if so, break the loop to finish this thread's execution.
592- bool allAboveMin = true ;
593- for (const auto & drop : totaldrops) {
594- long dropsLeft = mindropcount - drop.second ;
584+ if (threadStorage[i].totalsims % 1000 == 0 ) {
585+ allAboveMin = true ;
595586
596- if (dropsLeft > 0 ) {
597- allAboveMin = false ;
598- break ;
599- }
600- }
587+ for (const auto & drop : threadStorage[i].totaldrops ) {
588+ long dropsLeft = mindropcount - drop.second ;
601589
602- if (allAboveMin) {
603- totalsims += totalruns;
604- break ;
605- }
606- }
607-
608- // Write results to file as json with name: results-{timestamp}_{i}.json
609- // Each thread has a separate file based on `i` to avoid race conditions or write conflicts.
610- std::string filename = (BASETC ? simulationsPath + " base/" : simulationsPath) + tcname + " [" + std::to_string (playermod) + " ][" + std::to_string (i) + " ].json" ;
611- std::ofstream out (filename);
612-
613- out << " {\n " ;
614- out << " \" tc\" : \" " << tcname << " \" ,\n " ;
615- out << " \" playermod\" : " << playermod << " ,\n " ;
616- out << " \" seq\" : " << i << " ,\n " ;
617- out << " \" runs\" : " << totalruns << " ,\n " ;
618- out << " \" picks\" : " << totalpicks << " ,\n " ;
619- out << " \" avgpicks\" : " << std::fixed << std::setprecision (6 ) << (double )totalpicks / totalruns << " ,\n " ;
620- out << " \" drops\" : [\n " ;
621- long count = 0 ;
622- for (const auto & drop : totaldrops) {
623- std::string escapedDrop = drop.first .name ;
624- // Escape backslashes and double quotes in the drop name
625- size_t pos = 0 ;
626- while ((pos = escapedDrop.find (' \\ ' , pos)) != std::string::npos) {
627- escapedDrop.insert (pos, " \\ " );
628- pos += 2 ; // Move past the escaped backslash
629- }
630- pos = 0 ;
631- while ((pos = escapedDrop.find (' \" ' , pos)) != std::string::npos) {
632- escapedDrop.insert (pos, " \\ " );
633- pos += 2 ; // Move past the escaped quote
634- }
635- out << " [\" " + escapedDrop + " \" , " << drop.second << " , " << drop.first .magic << " , " << drop.first .rare << " , " << drop.first .set << " , " << drop.first .unique << " ]" ;
636- if (++count < totaldrops.size ()) {
637- out << " ," ;
590+ if (dropsLeft > 0 ) {
591+ allAboveMin = false ;
592+ break ;
593+ }
594+ }
638595 }
639- out << " \n " ;
640596 }
641- out << " ]\n " ;
642- out << " }\n " ;
643597 });
644598 }
645599
646- for (int i = 0 ; i < thread_count; i++) {
600+ for (size_t i = 0 ; i < thread_count; i++) {
647601 threads[i].join ();
648602 }
649603
650- std::cout << " {\" total\" :" << totalsims.load () << " }" << std::endl;
604+ long finalSims = 0 ;
605+ long finalPicks = 0 ;
606+ std::unordered_map<Drop, long > finaldrops;
607+
608+ for (const auto &threaddrops : threadStorage) {
609+ for (const auto & drop : threaddrops.totaldrops ) {
610+ finaldrops[drop.first ] += drop.second ;
611+ }
612+ finalSims += threaddrops.totalsims ;
613+ finalPicks += threaddrops.totalpicks ;
614+ }
615+
616+ std::cout << " {\n " ;
617+ std::cout << " \" tc\" : \" " << tcname << " \" ,\n " ;
618+ std::cout << " \" playermod\" : " << playermod << " ,\n " ;
619+ std::cout << " \" runs\" : " << finalSims << " ,\n " ;
620+ std::cout << " \" picks\" : " << finalPicks << " ,\n " ;
621+ std::cout << " \" avgpicks\" : " << std::fixed << std::setprecision (6 ) << (double )finalPicks / finalSims << " ,\n " ;
622+ std::cout << " \" drops\" : [\n " ;
623+
624+ long count = 0 ;
625+
626+ for (const auto & drop : finaldrops) {
627+ std::string escapedDrop = drop.first .name ;
628+ // Escape backslashes and double quotes in the drop name
629+ size_t pos = 0 ;
630+ while ((pos = escapedDrop.find (' \\ ' , pos)) != std::string::npos) {
631+ escapedDrop.insert (pos, " \\ " );
632+ pos += 2 ; // Move past the escaped backslash
633+ }
634+ pos = 0 ;
635+ while ((pos = escapedDrop.find (' \" ' , pos)) != std::string::npos) {
636+ escapedDrop.insert (pos, " \\ " );
637+ pos += 2 ; // Move past the escaped quote
638+ }
639+ std::cout << " [\" " + escapedDrop + " \" , " << drop.second << " , " << drop.first .magic << " , " << drop.first .rare << " , " << drop.first .set << " , " << drop.first .unique << " ]" ;
640+ if (++count < finaldrops.size ()) {
641+ std::cout << " ," ;
642+ }
643+ std::cout << " \n " ;
644+ }
645+
646+ std::cout << " ]\n " ;
647+ std::cout << " }\n " ;
651648
652649 return 0 ;
653650}
0 commit comments