#pragma once #include "gamestate.hpp" class Solver { Game known; vector history = {}; vector sequence; public: Solver(int p_N, int p_M) : known({p_N, p_M}) { sequence = vector(p_N, -1); } // Guessing vector guess() { // TODO return {}; } // Utility functions Historic_guess clean(Historic_guess hist) { // The correct colors we know for(int n = 0; n < known.N; n++) { if(known.final_color(n) == hist.guess[n]) { hist.guess[n] = -1; hist.response[1] -= 1; } } // The out-of-place colors we know for(int n = 0; n < known.N; n++) { if(hist.guess[n] == -1) continue; for(int i = 0; i < known.N; i++) { if(i == n) continue; if(known.final_color(i) == hist.guess[n]) { hist.guess[n] = -1; hist.response[0] -= 1; } } } return hist; } vector> get_positions_of_colors(vector guess) { auto positions_of_colors = vector>(known.M, vector(0)); for(int n = 0; n < known.N; n++) if(guess[n] > -1) positions_of_colors[guess[n]].push_back(n); return positions_of_colors; } // Specific reactions void if_not_here_then_nowhere(vector guess) { auto positions_of_colors = get_positions_of_colors(guess); // If color isn't here, it can't be in the sequence for(int col = 0; col < known.M; col++) { int possible_count = 0; for(int n : positions_of_colors[col]) if(known.possible[n][col]) possible_count++; if(possible_count == 0 && positions_of_colors[col].size() > 0) known.empty_color(col); } } void here(vector guess) { for(int n = 0; n < known.N; n++) if(guess[n] > -1 && known.possible[n][guess[n]]) for(int col = 0; col < known.M; col++) { if(col != guess[n]) known.possible[n][col] = 0; } } void not_here(vector guess) { for(int n = 0; n < known.N; n++) if(guess[n] > -1) known.cannot_be(n, guess[n]); } void empty(vector guess) { for(int col : guess) if(col > -1) known.empty_color(col); } void all_are_here(vector guess) { auto positions_of_colors = get_positions_of_colors(guess); for(int col = 0; col < known.M; col++) { if(!positions_of_colors[col].size()) known.empty_color(col); } } bool extract_info(Historic_guess hist) { bool something_to_learn = true; // A bit of cleaning auto cleaned = clean(hist); vector guess = cleaned.guess; vector response = cleaned.response; // Get number of colors, that can be on their positions int possible_count = 0; for(int n = 0; n < known.N; n++) if(known.possible[n][guess[n]]) possible_count++; // None of these colors are there if(response[0] == 0 && response[1] == 0) { empty(guess); something_to_learn = false; } // None at the right spot else if(response[1] == 0) not_here(guess); // At least only on the right spot else if(response[0] == 0) { // Only colors that can be on these positions are left if(response[1] == possible_count) { here(guess); something_to_learn = false; } else if_not_here_then_nowhere(guess); } // Nonzero / nonzero else { // Only colors that can be on these positions are left if(response[1] == possible_count) here(guess); } // All guessed colors are in the sequence if(response[0] + response[1] == known.N) all_are_here(guess); return something_to_learn; } void learn(vector p_guess, vector p_response) { // Learn something new bool something_to_learn = extract_info({p_guess, p_response}); // Learn from previous guesses for(int i = 0; i < history.size(); i++) if(!extract_info(history[i])) { // If there is nothing left to learn from the guess history.erase(history.begin()+i); i--; } // Write to history if(something_to_learn) history.push_back({p_guess, p_response}); } void print() { known.print(); } };