Solver optimizations - only repeat history learning, if something changed and game queries are now constant if repeated
This commit is contained in:
parent
b280ddde19
commit
3d359cef83
2 changed files with 66 additions and 17 deletions
76
solver.cpp
76
solver.cpp
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
Game::Game(int p_N, int p_M) : N(p_N), M(p_M) {
|
Game::Game(int p_N, int p_M) : N(p_N), M(p_M) {
|
||||||
possible = vector<vector<bool>>(N, vector<bool>(M, 1));
|
possible = vector<vector<bool>>(N, vector<bool>(M, 1));
|
||||||
|
empty_colors = vector<bool>(M, 0);
|
||||||
|
final = vector<int>(N, -1);
|
||||||
|
|
||||||
unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
|
unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||||
random_engine = std::default_random_engine(seed);
|
random_engine = std::default_random_engine(seed);
|
||||||
|
@ -20,6 +22,8 @@ vector<vector<int>> Game::get_positions_of_colors(vector<int> guess) {
|
||||||
return positions_of_colors;
|
return positions_of_colors;
|
||||||
}
|
}
|
||||||
int Game::final_color(int n) {
|
int Game::final_color(int n) {
|
||||||
|
if(final[n] > -1)
|
||||||
|
return final[n];
|
||||||
int final_col, count = 0;
|
int final_col, count = 0;
|
||||||
for(int col = 0; col < M; col++)
|
for(int col = 0; col < M; col++)
|
||||||
if(possible[n][col]) {
|
if(possible[n][col]) {
|
||||||
|
@ -27,14 +31,20 @@ int Game::final_color(int n) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count == 1)
|
if(count == 1) {
|
||||||
|
final[n] = final_col;
|
||||||
return final_col;
|
return final_col;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
bool Game::is_empty(int col) {
|
bool Game::is_empty(int col) {
|
||||||
|
if(empty_colors[col])
|
||||||
|
return true;
|
||||||
|
|
||||||
for(int n = 0; n < N; n++)
|
for(int n = 0; n < N; n++)
|
||||||
if(possible[n][col])
|
if(possible[n][col])
|
||||||
return false;
|
return false;
|
||||||
|
empty_colors[col] = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
vector<vector<int>> Game::list_all_possibilities() {
|
vector<vector<int>> Game::list_all_possibilities() {
|
||||||
|
@ -77,8 +87,9 @@ void Game::empty_color(int col) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specific reactions
|
// Specific reactions
|
||||||
void Game::if_not_here_then_nowhere(vector<int> guess) {
|
bool Game::if_not_here_then_nowhere(vector<int> guess) {
|
||||||
auto positions_of_colors = get_positions_of_colors(guess);
|
auto positions_of_colors = get_positions_of_colors(guess);
|
||||||
|
bool learned_something = false;
|
||||||
|
|
||||||
// If color isn't here, it can't be in the sequence
|
// If color isn't here, it can't be in the sequence
|
||||||
for(int col = 0; col < M; col++) {
|
for(int col = 0; col < M; col++) {
|
||||||
|
@ -86,9 +97,13 @@ void Game::if_not_here_then_nowhere(vector<int> guess) {
|
||||||
for(int n : positions_of_colors[col])
|
for(int n : positions_of_colors[col])
|
||||||
if(possible[n][col])
|
if(possible[n][col])
|
||||||
possible_count++;
|
possible_count++;
|
||||||
if(possible_count == 0 && positions_of_colors[col].size() > 0)
|
if(possible_count == 0 && positions_of_colors[col].size() > 0 && !is_empty(col)) {
|
||||||
empty_color(col);
|
empty_color(col);
|
||||||
|
learned_something = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return learned_something;
|
||||||
}
|
}
|
||||||
void Game::here(vector<int> guess) {
|
void Game::here(vector<int> guess) {
|
||||||
for(int n = 0; n < N; n++)
|
for(int n = 0; n < N; n++)
|
||||||
|
@ -152,9 +167,15 @@ vector<int> Solver::brute_force(vector<vector<int>> *possibilities, vector<int>
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
// Now featuring: minimax pick
|
||||||
|
vector<int> Solver::minimax(vector<vector<int>> *possibilities, vector<int> *chosen, int index) {
|
||||||
|
// TODO
|
||||||
|
return vector<int>(N, -1);
|
||||||
|
}
|
||||||
|
|
||||||
// Guessing
|
// Guessing
|
||||||
vector<int> Solver::guess() {
|
vector<int> Solver::guess() {
|
||||||
|
// TODO make it smart
|
||||||
auto possibilities = known.list_all_possibilities();
|
auto possibilities = known.list_all_possibilities();
|
||||||
auto chosen = vector<int>(0);
|
auto chosen = vector<int>(0);
|
||||||
return brute_force(&possibilities, &chosen, 0);
|
return brute_force(&possibilities, &chosen, 0);
|
||||||
|
@ -172,7 +193,7 @@ Historic_guess Solver::clean(Historic_guess hist) {
|
||||||
// Clean empty colors
|
// Clean empty colors
|
||||||
for(int n = 0; n < N; n++)
|
for(int n = 0; n < N; n++)
|
||||||
if(known.is_empty(hist.guess[n]))
|
if(known.is_empty(hist.guess[n]))
|
||||||
hist.guess[n] = -2;
|
hist.guess[n] = -1;
|
||||||
|
|
||||||
// The in-place colors we know
|
// The in-place colors we know
|
||||||
for(int n = 0; n < N; n++) {
|
for(int n = 0; n < N; n++) {
|
||||||
|
@ -206,14 +227,22 @@ Historic_guess Solver::clean(Historic_guess hist) {
|
||||||
|
|
||||||
|
|
||||||
// Here there be learning
|
// Here there be learning
|
||||||
bool Solver::extract_info(Historic_guess hist) {
|
vector<bool> Solver::extract_info(Historic_guess hist) {
|
||||||
bool something_to_learn = true;
|
bool something_to_learn = true, learned_something = false;
|
||||||
|
|
||||||
// A bit of cleaning
|
// A bit of cleaning
|
||||||
auto cleaned = clean(hist);
|
auto cleaned = clean(hist);
|
||||||
auto guess = cleaned.guess;
|
auto guess = cleaned.guess;
|
||||||
auto response = cleaned.response;
|
auto response = cleaned.response;
|
||||||
|
|
||||||
|
bool something = false;
|
||||||
|
for(int n = 0; n < N; n++)
|
||||||
|
if(guess[n] > -1)
|
||||||
|
something = true;
|
||||||
|
|
||||||
|
if(!something)
|
||||||
|
return {false, false};
|
||||||
|
|
||||||
// Get number of colors, that can be on their positions
|
// Get number of colors, that can be on their positions
|
||||||
int possible_count = 0;
|
int possible_count = 0;
|
||||||
for(int n = 0; n < N; n++)
|
for(int n = 0; n < N; n++)
|
||||||
|
@ -224,11 +253,16 @@ bool Solver::extract_info(Historic_guess hist) {
|
||||||
if(hist.response[0] == 0 && hist.response[1] == 0) {
|
if(hist.response[0] == 0 && hist.response[1] == 0) {
|
||||||
known.empty(hist.guess);
|
known.empty(hist.guess);
|
||||||
something_to_learn = false;
|
something_to_learn = false;
|
||||||
|
learned_something = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// None at the right spot
|
// None at the right spot
|
||||||
else if(response[1] == 0)
|
else if(response[1] == 0) {
|
||||||
known.not_here(guess);
|
if(possible_count > 0) {
|
||||||
|
known.not_here(guess);
|
||||||
|
learned_something = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// At least only on the right spot
|
// At least only on the right spot
|
||||||
else if(response[0] == 0) {
|
else if(response[0] == 0) {
|
||||||
|
@ -236,21 +270,25 @@ bool Solver::extract_info(Historic_guess hist) {
|
||||||
if(response[1] == possible_count) {
|
if(response[1] == possible_count) {
|
||||||
known.here(guess);
|
known.here(guess);
|
||||||
something_to_learn = false;
|
something_to_learn = false;
|
||||||
|
learned_something = true;
|
||||||
}
|
}
|
||||||
// TODO tady
|
|
||||||
else if(hist.response[0] == 0){
|
else if(hist.response[0] == 0){
|
||||||
known.if_not_here_then_nowhere(hist.guess);
|
if(known.if_not_here_then_nowhere(hist.guess)) {
|
||||||
|
learned_something = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nonzero / nonzero
|
// Nonzero / nonzero
|
||||||
else {
|
else {
|
||||||
// Only colors that can be on these positions are left
|
// Only colors that can be on these positions are left
|
||||||
if(response[1] == possible_count)
|
if(response[1] == possible_count) {
|
||||||
known.here(guess);
|
known.here(guess);
|
||||||
|
learned_something = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return something_to_learn;
|
return {something_to_learn, learned_something};
|
||||||
}
|
}
|
||||||
void Solver::learn(vector<int> p_guess, vector<int> p_response) {
|
void Solver::learn(vector<int> p_guess, vector<int> p_response) {
|
||||||
// All guessed colors are in the sequence
|
// All guessed colors are in the sequence
|
||||||
|
@ -264,12 +302,20 @@ void Solver::learn(vector<int> p_guess, vector<int> p_response) {
|
||||||
history.push_back({p_guess, p_response});
|
history.push_back({p_guess, p_response});
|
||||||
|
|
||||||
// Repeat multiple times, if new information turned out
|
// Repeat multiple times, if new information turned out
|
||||||
for(auto _ : history)
|
bool learned_something = true;
|
||||||
|
while(learned_something) {
|
||||||
|
learned_something = false;
|
||||||
|
|
||||||
// Learn from previous guesses
|
// Learn from previous guesses
|
||||||
for(int i = 0; i < history.size(); i++)
|
for(int i = 0; i < history.size(); i++) {
|
||||||
if(!extract_info(history[i])) {
|
auto info = extract_info(history[i]);
|
||||||
|
if(!info[0]) {
|
||||||
// If there is nothing left to learn from the guess
|
// If there is nothing left to learn from the guess
|
||||||
history.erase(history.begin()+i);
|
history.erase(history.begin()+i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
|
if(info[1])
|
||||||
|
learned_something = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
struct Game {
|
struct Game {
|
||||||
private:
|
private:
|
||||||
vector<vector<bool>> possible;
|
vector<vector<bool>> possible;
|
||||||
|
vector<bool> empty_colors;
|
||||||
|
vector<int> final;
|
||||||
std::default_random_engine random_engine;
|
std::default_random_engine random_engine;
|
||||||
public:
|
public:
|
||||||
int N, M;
|
int N, M;
|
||||||
|
@ -27,7 +29,7 @@ public:
|
||||||
void empty_color(int col);
|
void empty_color(int col);
|
||||||
|
|
||||||
// Learning functions
|
// Learning functions
|
||||||
void if_not_here_then_nowhere(vector<int> guess);
|
bool if_not_here_then_nowhere(vector<int> guess);
|
||||||
void here(vector<int> guess);
|
void here(vector<int> guess);
|
||||||
void not_here(vector<int> guess);
|
void not_here(vector<int> guess);
|
||||||
void empty(vector<int> guess);
|
void empty(vector<int> guess);
|
||||||
|
@ -54,8 +56,9 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Historic_guess clean(Historic_guess hist);
|
Historic_guess clean(Historic_guess hist);
|
||||||
bool extract_info(Historic_guess hist);
|
vector<bool> extract_info(Historic_guess hist);
|
||||||
|
|
||||||
bool all_are_consistent(vector<int> supposed_sequence);
|
bool all_are_consistent(vector<int> supposed_sequence);
|
||||||
vector<int> brute_force(vector<vector<int>> *possibilities, vector<int> *chosen, int index);
|
vector<int> brute_force(vector<vector<int>> *possibilities, vector<int> *chosen, int index);
|
||||||
|
vector<int> minimax(vector<vector<int>> *possibilities, vector<int> *chosen, int index);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue