Skip to content

Commit 8580dc5

Browse files
Add files via upload
1 parent 5bc5c8a commit 8580dc5

File tree

1 file changed

+90
-36
lines changed

1 file changed

+90
-36
lines changed

MasterMindTurbo.cpp

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include <iostream>
1+
#include <iostream>
22
#include <vector>
33
#include <array>
44
#include <memory>
@@ -78,37 +78,74 @@ void create_mark_map() {
7878
mark_to_idx[n][0] = imark0_val;
7979
}
8080

81-
// Fast, integer-only scoring function
81+
// Fast, integer-only scoring function (optimized version)
8282
inline uFast score(code_t guess, code_t secret) {
8383
if (guess.v == secret.v) return imark0_val;
84-
std::array<uFast, n> g_digits, s_digits;
85-
guess.unpack(g_digits);
86-
secret.unpack(s_digits);
8784

85+
uFast g_val = guess.v, s_val = secret.v;
8886
uFast black = 0;
89-
std::array<uFast, c> g_counts{}, s_counts{};
9087

88+
uFast g_counts[c] = { 0 };
89+
uFast s_counts[c] = { 0 };
90+
91+
// Single pass through positions without intermediate arrays
9192
for (uFast i = 0; i < n; ++i) {
92-
if (g_digits[i] == s_digits[i]) {
93+
uFast g_digit = g_val % c;
94+
uFast s_digit = s_val % c;
95+
96+
if (g_digit == s_digit) {
9397
black++;
9498
}
9599
else {
96-
g_counts[g_digits[i]]++;
97-
s_counts[s_digits[i]]++;
100+
g_counts[g_digit]++;
101+
s_counts[s_digit]++;
98102
}
103+
g_val /= c;
104+
s_val /= c;
99105
}
106+
100107
uFast white = 0;
101-
for (uFast i = 0; i < c; ++i) white += std::min(g_counts[i], s_counts[i]);
108+
for (uFast i = 0; i < c; ++i) {
109+
white += std::min(g_counts[i], s_counts[i]);
110+
}
111+
102112
return mark_to_idx[black][white];
103113
}
104114

115+
// --- Custom Hash Table for Unique Partition Filtering ---
116+
constexpr uFast HT_SIZE = 2048; // Power of two >= s, keeps load factor low
117+
alignas(64) uFast ht_key[HT_SIZE];
118+
alignas(64) uFast ht_val[HT_SIZE]; // Stores the compact index (1 to k)
119+
120+
// Returns the 1-based compact index for a given key.
121+
// If the key is new, it increments *k_ptr and assigns the new index.
122+
inline uFast find_or_add_signature(uFast key, uFast* k_ptr) {
123+
// Fast multiplicative hash using a golden-ratio-based constant
124+
uFast idx = (key * 0x9e3779b97f4a7c15ULL) & (HT_SIZE - 1);
125+
126+
while (true) {
127+
if (ht_key[idx] == key) { // Found existing key
128+
return ht_val[idx];
129+
}
130+
if (ht_key[idx] == 0) { // Found empty slot, this is a new key
131+
ht_key[idx] = key;
132+
(*k_ptr)++;
133+
ht_val[idx] = *k_ptr;
134+
return *k_ptr;
135+
}
136+
// Collision: move to the next slot (linear probing)
137+
idx = (idx + 1) & (HT_SIZE - 1);
138+
}
139+
}
140+
141+
105142
int main() {
106143
uFast i, j, k, l, m, p, iv, iv2, o, o2;
107144

108145
const uFast imark0 = imark0_val; // Use the calculated value locally
109146
create_mark_map();
110147

111-
// Heap-allocated storage (from previous step)
148+
// Heap-allocated storage
112149
const uFast S_DIM = s + 1, IMARK0_DIM = imark0 + 1;
113150
auto MapConsistent_ptr = std::make_unique<uFast[]>((maxdepth + 1) * S_DIM * IMARK0_DIM);
114151
auto MapConsistent = [&](uFast d1, uFast d2, uFast d3) -> uFast& { return MapConsistent_ptr[d1 * S_DIM * IMARK0_DIM + d2 * IMARK0_DIM + d3]; };
@@ -117,12 +154,13 @@ int main() {
117154
typedef uFast(iValid_)[s + 1]; iValid_* iValid = new iValid_[maxdepth + 1];
118155

119156
alignas(64) static uint16_t Mark[s + 1][s + 1];
120-
157+
121158
auto RowSum = std::make_unique<uFast[]>(1'000'000);
122159
typedef uFast(list_)[1'000'000]; list_* list = new list_[maxdepth + 1];
123160

124161
uFast ubPure[maxdepth + 1] = { 0 }, g[maxdepth + 1] = { 0 }, r[maxdepth + 1] = { 0 }, GuessSum[s + 1] = { 0 };
125-
uFast guess, sign, lvl = 1, x = 0, x0 = 0, gMin = 0;
162+
uFast guess, sign, lvl = 1, x = 0, x0 = 0;
163+
uFast gMin = -1; // Initialize to max value for unsigned
126164
std::array<uFast, s + 1> MPScore;
127165
static std::array<uFast, imark0 + 1> mult;
128166
for (i = 0; i < imark0; i++) mult[i + 1] = uFast(round(pow(16.0, double(i))));
@@ -144,6 +182,8 @@ int main() {
144182
}
145183
auto mark_end_time = std::chrono::high_resolution_clock::now();
146184
std::cout << "Mark table computed in " << std::chrono::duration<double>(mark_end_time - mark_start_time).count() << " seconds.\n";
185+
186+
// --- Interactive Input ---
147187
std::vector<uFast> initial_guesses, initial_signs;
148188
uFast input_count = 1;
149189
std::cout << "\n";
@@ -178,7 +218,7 @@ int main() {
178218
std::cout << "\n" << kk << " possible solutions!\n\n" << "Calculating...\n\n";
179219
if (kk == 1) {
180220
RowSum[1] = 1;
181-
list[1][1] = Valids[iValid[1][1]].to_decimal() * 100 + 40;
221+
list[1][1] = Valids[iValid[1][1]].to_decimal() * 100 + iMark[imark0];
182222
goto finished;
183223
}
184224

@@ -190,6 +230,7 @@ int main() {
190230
}
191231

192232
GetNext:
233+
// --- Partition Calculation (Original, Fast Version) ---
193234
memset(&MapConsistent(lvl, 0, 0), 0, sizeof(uFast) * S_DIM * IMARK0_DIM);
194235
uFast q[s + 1] = { 0 };
195236
k = lvl - 1;
@@ -198,50 +239,63 @@ int main() {
198239
iv2 = iValid[lvl][2];
199240
for (i = 1; i <= s; i++) {
200241
o = Mark[i][iv]; o2 = Mark[i][iv2];
201-
MapConsistent(lvl, i, o)++; //vectorized for speed
242+
MapConsistent(lvl, i, o)++;
202243
MapConsistent(lvl, i, o2)++;
203-
q[i] += ((o * mult[o]) + (o2 * mult[o2]));
244+
q[i] += (mult[o] + mult[o2]); // Simplified from original for clarity
204245
}
205246
for (j = 3; j <= l; j++) {
206247
iv = iValid[lvl][j];
207248
for (i = 1; i <= s; i++) {
208249
o = Mark[i][iv];
209250
MapConsistent(lvl, i, o)++;
210-
q[i] += (o * mult[o]);
251+
q[i] += mult[o];
211252
}
212253
}
254+
255+
// --- High-performance filtering using a custom hash table ---
256+
std::fill_n(ht_key, HT_SIZE, 0);
213257
k = 0;
214258
for (i = 1; i <= s; i++) {
215-
k++; iFiltered[lvl][k] = i;
216-
q[k] = q[i];
217-
for (m = 1; m < k; m++) if (q[m] == q[k]) {
218-
k--;
219-
break;
259+
uFast unique_idx = find_or_add_signature(q[i], &k);
260+
if (unique_idx == k) { // True only for the first time this signature is seen
261+
iFiltered[lvl][k] = i;
220262
}
221263
}
264+
265+
// --- Compaction and Scoring ---
222266
for (i = 1; i <= k; i++) {
223267
MPScore[i] = 0;
268+
uFast original_idx = iFiltered[lvl][i];
224269
for (j = 1; j <= imark0; j++) {
225-
MapConsistent(lvl, i, j) = MapConsistent(lvl, iFiltered[lvl][i], j);
226-
MPScore[i] += MapConsistent(lvl, i, j) != 0;
270+
uFast count = MapConsistent(lvl, original_idx, j);
271+
MapConsistent(lvl, i, j) = count;
272+
if (count != 0) {
273+
MPScore[i]++;
274+
}
227275
}
228-
q[i] = MPScore[i];
276+
q[i] = MPScore[i]; // Reuse q[] to hold the score
229277
}
230-
// concurrency::parallel_buffered_sort from ppl.h is non-standard. std::sort is faster for small sizes.
278+
231279
std::sort(&MPScore[1], &MPScore[k + 1]);
232280

233-
//l = (k > 133) ? k - 16 : 0.88 * k; //correct formula for all combinations
234-
l = (k > 119) ? k - 8 : 0.88 * k;// works with (4,6)
281+
// --- Heuristic Pruning ---
282+
l = (k > 119) ? k - 8 : 0.88 * k;
235283

236284
m = 0;
237285
for (i = 1; i <= k; i++) {
238286
if (q[i] >= MPScore[l]) {
239287
m++;
240-
iFiltered[lvl][m] = iFiltered[lvl][i];
241-
for (j = 1; j <= imark0; j++) MapConsistent(lvl, m, j) = MapConsistent(lvl, i, j);
288+
// This compaction is now safe because iFiltered[lvl][i] holds the original index
289+
uFast original_idx = iFiltered[lvl][i];
290+
iFiltered[lvl][m] = original_idx;
291+
for (j = 1; j <= imark0; j++) {
292+
MapConsistent(lvl, m, j) = MapConsistent(lvl, i, j);
293+
}
242294
}
243295
}
244296
ubPure[lvl] = m;
297+
298+
// --- Main DFS Loop ---
245299
while (lvl) {
246300
for (guess = g[lvl]; guess <= ubPure[lvl]; guess++) {
247301
for (sign = r[lvl]; sign <= imark0; sign++) {
@@ -279,24 +333,24 @@ int main() {
279333
goto GetNext;
280334
}
281335
if ((g[lvl] != 1) && (ubPure[lvl] == g[lvl])) {
282-
gMin = -1;
336+
gMin = -1; // Max uFast value
283337
l = lvl - 1;
284338
p = MapConsistent(l, g[l], r[l]);
285339
x0 = x - (ubPure[lvl] * p);
286340
for (i = 1; i <= ubPure[lvl]; i++) {
287-
int sum = 0;
288-
int baseOffset = x0 + (i - 1) * p;
341+
uFast sum = 0;
342+
uFast baseOffset = x0 + (i - 1) * p;
289343
for (j = 1; j <= p; j++) sum += RowSum[baseOffset + j];
290344
GuessSum[i] = sum;
291345
if (sum < gMin) {
292346
gMin = sum;
293347
k = i;
294348
}
295349
}
296-
int sourceBase = x0 + (k - 1) * p;
350+
uFast sourceBase = x0 + (k - 1) * p;
297351
for (i = 1; i <= p; i++) {
298-
int destIndex = x0 + i;
299-
int sourceIndex = sourceBase + i;
352+
uFast destIndex = x0 + i;
353+
uFast sourceIndex = sourceBase + i;
300354
RowSum[destIndex] = RowSum[sourceIndex];
301355
for (j = 1; j < maxdepth; j++) list[j][destIndex] = list[j][sourceIndex];
302356
}

0 commit comments

Comments
 (0)