-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
145 lines (128 loc) · 5.1 KB
/
Copy pathmain.cpp
File metadata and controls
145 lines (128 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// main.cpp
// Standalone CLI / test harness for the engine-agnostic dungeon layout generator.
//
// Modes:
// dungeon ascii [seed] print one layout as ASCII (default seed 1)
// dungeon dump [seed] print the canonical layout dump (for external diffing)
// dungeon determinism [seed] generate twice, compare dumps, print identical / first diff
// dungeon validate <count> [base] validate `count` distinct seeds (base .. base+count-1),
// print "<passed>/<count> passed" + aggregate stats
//
// Exit code is 0 on success, non-zero on any failure (so it can gate CI / scripts).
#include "dungeon.hpp"
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <string>
using namespace dungeon;
static Config baseConfig() {
return Config{}; // documented defaults: 64x40, rooms[8..12], size[5..10], seed 0, loops 2
}
static std::uint64_t parseU64(const char* s, std::uint64_t fallback) {
if (!s) return fallback;
return std::strtoull(s, nullptr, 10);
}
static int usage() {
std::cout <<
"usage:\n"
" dungeon ascii [seed]\n"
" dungeon dump [seed]\n"
" dungeon determinism [seed]\n"
" dungeon validate <count> [base]\n";
return 2;
}
static void printConfig(const Config& c) {
std::cout << "config: grid " << c.width << "x" << c.height
<< " rooms[" << c.minRooms << ".." << c.maxRooms << "]"
<< " size[" << c.minRoomSize << ".." << c.maxRoomSize << "]"
<< " loopEdges " << c.extraLoopEdges << "\n";
}
int main(int argc, char** argv) {
if (argc < 2) return usage();
std::string mode = argv[1];
if (mode == "ascii") {
Config c = baseConfig();
c.seed = parseU64(argc > 2 ? argv[2] : nullptr, 1);
Layout L = generate(c);
printConfig(c);
std::cout << "seed: " << c.seed
<< " rooms: " << L.rooms.size()
<< " connections: " << L.connections.size() << "\n";
std::cout << "legend: # wall . floor + corridor / door S start\n";
std::cout << asciiArt(L);
return 0;
}
if (mode == "dump") {
Config c = baseConfig();
c.seed = parseU64(argc > 2 ? argv[2] : nullptr, 1);
std::cout << dump(generate(c));
return 0;
}
if (mode == "determinism") {
Config c = baseConfig();
c.seed = parseU64(argc > 2 ? argv[2] : nullptr, 1);
std::string d1 = dump(generate(c));
std::string d2 = dump(generate(c));
printConfig(c);
if (d1 == d2) {
std::cout << "DETERMINISM seed=" << c.seed
<< ": identical (" << d1.size() << " bytes, two independent generations)\n";
return 0;
}
std::cout << "DETERMINISM seed=" << c.seed << ": MISMATCH\n";
std::size_t i = 0;
while (i < d1.size() && i < d2.size() && d1[i] == d2[i]) ++i;
std::cout << "first difference at byte " << i << "\n";
return 1;
}
if (mode == "validate") {
if (argc < 3) return usage();
long count = std::strtol(argv[2], nullptr, 10);
std::uint64_t base = parseU64(argc > 3 ? argv[3] : nullptr, 1);
if (count <= 0) { std::cout << "count must be positive\n"; return 2; }
Config c = baseConfig();
printConfig(c);
std::cout << "validating " << count << " distinct seeds: "
<< base << " .. " << (base + std::uint64_t(count) - 1) << "\n";
long passed = 0;
int failuresShown = 0;
int minRooms = INT_MAX, maxRooms = 0;
long totalRooms = 0;
for (long i = 0; i < count; ++i) {
std::uint64_t seed = base + std::uint64_t(i);
Config cs = c;
cs.seed = seed;
try {
Layout L = generate(cs);
ValidationResult vr = validate(L);
int rc = static_cast<int>(L.rooms.size());
minRooms = std::min(minRooms, rc);
maxRooms = std::max(maxRooms, rc);
totalRooms += rc;
if (vr.ok) {
++passed;
} else if (failuresShown < 20) {
std::cout << " FAIL seed=" << seed << ": " << vr.reason << "\n";
++failuresShown;
}
} catch (const std::exception& e) {
if (failuresShown < 20) {
std::cout << " CRASH seed=" << seed << ": " << e.what() << "\n";
++failuresShown;
}
} catch (...) {
if (failuresShown < 20) {
std::cout << " CRASH seed=" << seed << ": unknown exception\n";
++failuresShown;
}
}
}
if (passed == count && count > 0) {
std::cout << "room-count range across seeds: " << minRooms << ".." << maxRooms
<< " (avg " << (double(totalRooms) / double(count)) << ")\n";
}
std::cout << passed << "/" << count << " passed\n";
return passed == count ? 0 : 1;
}
return usage();
}