11/* *
22 * Cross-platform C++17 drop simulator.
3- *
3+ *
44 * Compiles with:
55 * - Linux: g++ dropsim.cpp -o dropsim -std=c++17 -pthread
66 * - Windows: Visual Studio 2017+ (C++17 support required)
77 */
88
9- // Disable MSVC security warnings for fopen, strcspn, etc.
9+ // Disable MSVC security warnings for fopen, strcspn, etc.
1010#ifdef _MSC_VER
1111#define _CRT_SECURE_NO_WARNINGS
1212#endif
1313
14+ #if defined(_WIN32) || defined(_WIN64)
15+ #define DIRECTORY_SEPARATOR ' \\ '
16+ #define DIRECTORY_SEPARATOR_STRING " \\ "
17+ #else
18+ #define DIRECTORY_SEPARATOR ' /'
19+ #define DIRECTORY_SEPARATOR_STRING " /"
20+ #endif
21+
1422#include < unordered_map>
1523#include < iostream>
1624#include < cstdio>
2432#include < iomanip>
2533#include < fstream>
2634#include < filesystem>
35+ #include < cmath>
2736
2837struct Entry {
2938 std::string name;
@@ -75,13 +84,13 @@ std::vector<std::string> splitByChar(const std::string& str, char delimiter) {
7584 return tokens;
7685}
7786
78- void pickAtomic (std::string tcname, std::vector<std::string> & drops) {
87+ void pickAtomic (std::string tcname, std::vector<std::string>& drops) {
7988 if (atomic.find (tcname) == atomic.end ()) {
8089 drops.push_back (tcname);
8190 return ;
8291 }
8392
84- AtomicTC & atc = atomic[tcname];
93+ AtomicTC& atc = atomic[tcname];
8594
8695 if (atc.total == 0 ) {
8796 return ;
@@ -101,7 +110,7 @@ void pickAtomic(std::string tcname, std::vector<std::string> &drops) {
101110}
102111
103112long calcNodrop (long e, long nd, long d) {
104- double _e = (double ) e, _nd = (double ) nd, _d = (double ) d;
113+ double _e = (double )e, _nd = (double )nd, _d = (double )d;
105114 if (nd < 1 ) {
106115 return 0 ;
107116 }
@@ -113,7 +122,7 @@ long calcNodrop(long e, long nd, long d) {
113122 return (long )(_d / (pow ((_nd + _d) / nd, _e) - 1 ));
114123}
115124
116- void pick (std::string tcname, std::vector<std::string> & drops) {
125+ void pick (std::string tcname, std::vector<std::string>& drops) {
117126 if (drops.size () >= 6 ) {
118127 return ;
119128 }
@@ -123,7 +132,7 @@ void pick(std::string tcname, std::vector<std::string> &drops) {
123132 return ;
124133 }
125134
126- TC & tc = treasureClasses[tcname];
135+ TC& tc = treasureClasses[tcname];
127136
128137 if (tc.picks == 0 ) {
129138 return ;
@@ -145,7 +154,7 @@ void pick(std::string tcname, std::vector<std::string> &drops) {
145154 }
146155
147156 long picknum = dis (gen) - nodrop;
148-
157+
149158 if (picknum < 0 ) {
150159 continue ;
151160 }
@@ -156,7 +165,7 @@ void pick(std::string tcname, std::vector<std::string> &drops) {
156165 pick (item.name , drops);
157166 break ;
158167 }
159-
168+
160169 picknum -= item.prob ;
161170 }
162171 }
@@ -187,15 +196,17 @@ int main(int argc, char* argv[]) {
187196 return 1 ;
188197 }
189198
190- std::vector<std::string> pathParts = splitByChar (argv[0 ], ' / ' );
199+ std::vector<std::string> pathParts = splitByChar (argv[0 ], DIRECTORY_SEPARATOR );
191200 pathParts.pop_back ();
192201 std::string path = " " ;
193202
194203 for (const auto & part : pathParts) {
195- path += part + " / " ;
204+ path += part + DIRECTORY_SEPARATOR_STRING ;
196205 }
197206
198- path = realpath (path) + " /" ;
207+ path = realpath (path) + DIRECTORY_SEPARATOR_STRING;
208+ std::string txtDir = realpath (path + " txt" ) + DIRECTORY_SEPARATOR_STRING;
209+ std::string simulationsPath = realpath (path + " simulations" ) + DIRECTORY_SEPARATOR_STRING;
199210
200211 std::string tcname = argv[1 ];
201212 int dropcycles = 25000 ;
@@ -207,20 +218,20 @@ int main(int argc, char* argv[]) {
207218 playermod = std::max (1 , playermod);
208219 playermod = std::min (8 , playermod);
209220
210-
221+
211222 if (argc >= 4 ) {
212223 dropcycles = atoi (argv[3 ]);
213224 }
214-
225+
215226 dropcycles = std::max (1 , dropcycles);
216227 dropcycles = std::min (1000000 , dropcycles);
217-
228+
218229 std::cout << " TC: " << tcname << std::endl;
219230 std::cout << " Player mod: " << playermod << std::endl;
220231 std::cout << " Drop cycles per set: " << dropcycles << std::endl;
221232
222233 // Open the treasure class file at: txt/treasureclassex.txt
223- FILE* tex = fopen ((path + " txt/ treasureclassex.txt" ).c_str (), " r" );
234+ FILE* tex = fopen ((txtDir + " treasureclassex.txt" ).c_str (), " r" );
224235 if (!tex) {
225236 std::cout << " Error: Could not open treasure class file\n " ;
226237 return 1 ;
@@ -319,7 +330,7 @@ int main(int argc, char* argv[]) {
319330 std::string itemName = tokens[i];
320331 int itemProb = atoi (tokens[i + 1 ].c_str ());
321332
322- atomic[tcBaseName].items .push_back ({itemName, itemProb});
333+ atomic[tcBaseName].items .push_back ({ itemName, itemProb });
323334 atomic[tcBaseName].total += itemProb;
324335 }
325336 }
@@ -345,12 +356,12 @@ int main(int argc, char* argv[]) {
345356 }
346357
347358 std::cout << " Using " << thread_count << " threads\n " ;
348- std::cout << " Output files periodically written to: " << (path + " simulations/ " ) << std::endl;
359+ std::cout << " Output files periodically written to: " << simulationsPath << std::endl;
349360
350361 std::vector<std::thread> threads;
351362
352363 for (int i = 0 ; i < thread_count; i++) {
353- threads.emplace_back ([i, &tcname, dropcycles, &path ]() {
364+ threads.emplace_back ([i, &tcname, dropcycles, &simulationsPath ]() {
354365 long runs = 0 ;
355366 long picks = 0 ;
356367 std::unordered_map<std::string, long > drops;
@@ -361,22 +372,23 @@ int main(int argc, char* argv[]) {
361372 for (int j = 0 ; j < dropcycles; j++) {
362373 std::vector<std::string> rundrops;
363374 pick (tcname, rundrops);
364-
375+
365376 for (const auto & drop : rundrops) {
366377 drops[drop]++;
367378 picks++;
368379 }
369-
380+
370381 runs++;
371382 }
372383
373384 auto elapsed = std::chrono::steady_clock::now () - startTime;
374385 auto elapsedMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count ();
375386
376387 // Write results to file as json with name: results-{timestamp}_{i}.json
377- std::string filename = path + " simulations/" + tcname + " [" + std::to_string (playermod) + " ][" + std::to_string (i) + " ].json" ;
388+ // Each thread has a separate file based on `i` to avoid race conditions or write conflicts.
389+ std::string filename = simulationsPath + tcname + " [" + std::to_string (playermod) + " ][" + std::to_string (i) + " ].json" ;
378390 std::ofstream out (filename);
379-
391+
380392 out << " {\n " ;
381393 out << " \" tc\" : \" " << tcname << " \" ,\n " ;
382394 out << " \" runs\" : " << runs << " ,\n " ;
0 commit comments