Skip to content

Commit c32da76

Browse files
Additional dropsim optimizations; removed temporary simulation files for simplicity and speed.
1 parent 0f5342d commit c32da76

3 files changed

Lines changed: 117 additions & 175 deletions

File tree

build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/bin/bash
2-
g++ dropsim.cpp -o dropsim -std=c++17 -O3
3-
g++ dropsim.cpp -o dropsimbase -D"BASETC=1" -std=c++17 -O3
2+
g++ dropsim.cpp -o dropsim -std=c++17 -O3 -pthread -march=native
3+
g++ dropsim.cpp -o dropsimbase -D"BASETC=1" -std=c++17 -O3 -pthread -march=native

dropsim.cpp

Lines changed: 91 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ void wait() {
4949
#endif
5050

5151
struct Entry {
52-
std::string name;
52+
std::string name = "";
5353
int prob = 0;
5454
};
5555

5656
struct 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

7878
struct 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+
103109
std::unordered_map<std::string, AtomicTC> atomic;
104110
std::unordered_map<std::string, TC> treasureClasses;
105111

106112
long playermod = 1;
107113
int 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
113116
std::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

Comments
 (0)