-
Notifications
You must be signed in to change notification settings - Fork 0
/
algos.hpp
147 lines (117 loc) · 5.22 KB
/
algos.hpp
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
146
147
// Copyright (c) Michael M. Magruder (https://github.com/mikemag)
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
#pragma once
#include <cmath>
#include "preset_initial_guesses.h"
// Multiple algorithms for solving Mastermind
//
// There are many strategies for selecting the next "best" guess when playing Mastermind, and the types here capture
// some common ones. Most of them rely on splitting the remaining possible guesses into groups or subsets based on their
// scores vs each other.
//
// References:
// [1] D.E. Knuth. The computer as Master Mind. Journal of Recreational Mathematics, 9(1):1–6, 1976.
// https://www.cs.uni.edu/~wallingf/teaching/cs3530/resources/knuth-mastermind.pdf
//
// [2] Geoffroy Ville, An Optimal Mastermind (4,7) Strategy and More Results in the Expected Case, March
// 2013, arXiv:1305.1010 [cs.GT].
//
// [3] Barteld Kooi, Yet another mastermind Strategy. International Computer Games Association Journal,
// 28(1):13–20, 2005. https://www.researchgate.net/publication/30485793_Yet_another_Mastermind_strategy
namespace Algos {
struct Knuth {
using MaxSubsetSizeT = int32_t;
constexpr static const char* name = "Knuth";
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateSubsetSize(SubsetSizeT& s) {
s++;
}
using RankingAccumulatorType = uint32_t;
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateRanking(RankingAccumulatorType& rankingAccumulator, SubsetSizeT& s,
uint32_t possibleSolutionsCount) {
if (s > rankingAccumulator) rankingAccumulator = s;
}
CUDA_HOST_AND_DEVICE static uint32_t computeRank(const RankingAccumulatorType rankingAccumulator,
const uint32_t possibleSolutionsCount) {
return possibleSolutionsCount - rankingAccumulator;
}
template <uint8_t PIN_COUNT, uint8_t COLOR_COUNT>
constexpr static uint32_t presetInitialGuess() {
return presetInitialGuessKnuth<PIN_COUNT, COLOR_COUNT>();
}
};
struct MostParts {
using MaxSubsetSizeT = int8_t;
constexpr static const char* name = "Most Parts";
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateSubsetSize(SubsetSizeT& s) {
s = 1;
}
using RankingAccumulatorType = uint32_t;
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateRanking(RankingAccumulatorType& rankingAccumulator, SubsetSizeT& s,
uint32_t possibleSolutionsCount) {
rankingAccumulator++;
}
CUDA_HOST_AND_DEVICE static uint32_t computeRank(RankingAccumulatorType rankingAccumulator,
uint32_t possibleSolutionsCount) {
return rankingAccumulator;
}
template <uint8_t PIN_COUNT, uint8_t COLOR_COUNT>
constexpr static uint32_t presetInitialGuess() {
return presetInitialGuessMostParts<PIN_COUNT, COLOR_COUNT>();
}
};
struct ExpectedSize {
using MaxSubsetSizeT = int32_t;
constexpr static const char* name = "Expected Size";
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateSubsetSize(SubsetSizeT& s) {
s++;
}
using RankingAccumulatorType = float;
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateRanking(RankingAccumulatorType& rankingAccumulator, SubsetSizeT& s,
uint32_t possibleSolutionsCount) {
rankingAccumulator += ((float)s * (float)s) / possibleSolutionsCount;
}
CUDA_HOST_AND_DEVICE static uint32_t computeRank(RankingAccumulatorType rankingAccumulator,
uint32_t possibleSolutionsCount) {
#pragma nv_diagnostic push
#pragma nv_diag_suppress 68
// This is a bit broken, and needs to be to match the semantics in the paper.
return (uint32_t)round(rankingAccumulator * 1'000'000.0) * -1; // 9 digits of precision
#pragma nv_diagnostic pop
}
template <uint8_t PIN_COUNT, uint8_t COLOR_COUNT>
constexpr static uint32_t presetInitialGuess() {
return presetInitialGuessExpectedSize<PIN_COUNT, COLOR_COUNT>();
}
};
struct Entropy {
using MaxSubsetSizeT = int32_t;
constexpr static const char* name = "Entropy";
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateSubsetSize(SubsetSizeT& s) {
s++;
}
using RankingAccumulatorType = float;
template <typename SubsetSizeT>
CUDA_HOST_AND_DEVICE static void accumulateRanking(RankingAccumulatorType& rankingAccumulator, SubsetSizeT& s,
uint32_t possibleSolutionsCount) {
float pi = (float)s / possibleSolutionsCount;
rankingAccumulator -= pi * log(pi);
}
CUDA_HOST_AND_DEVICE static uint32_t computeRank(RankingAccumulatorType rankingAccumulator,
uint32_t possibleSolutionsCount) {
return round(rankingAccumulator * 1'000'000'000.0); // 9 digits of precision
}
template <uint8_t PIN_COUNT, uint8_t COLOR_COUNT>
constexpr static uint32_t presetInitialGuess() {
return presetInitialGuessEntropy<PIN_COUNT, COLOR_COUNT>();
}
};
} // namespace Algos