diff --git a/game.cpp b/game.cpp new file mode 100644 index 0000000..d588563 --- /dev/null +++ b/game.cpp @@ -0,0 +1,137 @@ +#include +#include +#include "global.hpp" + +Game::Game(int _N, int _M) : N(_N), M(_M) { + possible = vector>(N, vector(M, 1)); + empty_colors = vector(M, 0); + final = vector(N, -1); + + unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count(); + random_engine = std::default_random_engine(seed); +} + +// Getting known information +bool Game::can(int n, int col) { + return possible[n][col]; +} +vector> Game::get_positions_of_colors(vector guess) { + auto positions_of_colors = vector>(M, vector(0)); + for(int n = 0; n < N; n++) + if(guess[n] > -1) + positions_of_colors[guess[n]].push_back(n); + return positions_of_colors; +} +int Game::final_color(int n) { + if(final[n] > -1) + return final[n]; + int final_col, count = 0; + for(int col = 0; col < M; col++) + if(possible[n][col]) { + final_col = col; + count++; + } + + if(count == 1) { + final[n] = final_col; + return final_col; + } + return -1; +} +bool Game::is_empty(int col) { + if(empty_colors[col]) + return true; + + for(int n = 0; n < N; n++) + if(possible[n][col]) + return false; + empty_colors[col] = true; + return true; +} +vector> Game::list_all_possibilities() { + auto r = vector>(N, vector(0)); + for(int col = 0; col < M; col++) + for(int n = 0; n < N; n++) + if(possible[n][col]) + r[n].push_back(col); + + for(int n = 0; n < N; n++) + std::shuffle(r[n].begin(), r[n].end(), random_engine); + return r; +} +void Game::print() { + cout << " "; + for(int col = 0; col < M; col++) + cout << col; + cout << std::endl; + for(int i = 0; i < N; i++) { + cout << i; + for(auto col : possible[i]) + cout << col; + cout << std::endl;; + } + cout << std::endl; +} + +// Learning functions +void Game::cannot_be(int n, int col) { + possible[n][col] = false; +} +void Game::must_be(int n, int must_col) { + for(int col = 0; col < M; col++) + if(col != must_col) + possible[n][col] = 0; +} +void Game::empty_color(int col) { + for(int n = 0; n < N; n++) + possible[n][col] = 0; +} + +// Specific reactions +bool Game::if_not_here_then_nowhere(vector 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 + for(int col = 0; col < M; col++) { + int possible_count = 0; + for(int n : positions_of_colors[col]) + if(possible[n][col]) + possible_count++; + if(possible_count == 0 && positions_of_colors[col].size() > 0 && !is_empty(col)) { + empty_color(col); + learned_something = true; + } + } + + return learned_something; +} +void Game::here(vector guess) { + for(int n = 0; n < N; n++) + if(guess[n] > -1 && possible[n][guess[n]]) + must_be(n, guess[n]); +} +void Game::not_here(vector guess) { + for(int n = 0; n < N; n++) + if(guess[n] > -1) + cannot_be(n, guess[n]); +} +void Game::empty(vector guess) { + for(int col : guess) + if(col > -1) + empty_color(col); +} +void Game::all_are_here(vector guess) { + auto positions_of_colors = get_positions_of_colors(guess); + + for(int col = 0; col < M; col++) { + if(positions_of_colors[col].size() == 0) + empty_color(col); + } +} + +// For remembering guesses with their responses +Historic_guess::Historic_guess(vector _guess, Response _response) { + guess = _guess; + response = _response; +} diff --git a/global.hpp b/global.hpp index 1ba974a..10dcc53 100644 --- a/global.hpp +++ b/global.hpp @@ -2,6 +2,7 @@ #include #include #include +#include using std::vector; using std::string; @@ -27,3 +28,42 @@ string format_lost_sequence(vector sequence); // Validating Response validate(vector sequence, vector guess); + +// Game remembering +struct Game { +private: + vector> possible; + vector empty_colors; + vector final; + std::default_random_engine random_engine; +public: + int N, M; + Game(int _N, int _M); + + // Get known information + bool can(int n, int col); + int final_color(int n); + bool is_empty(int col); + void print(); + vector> list_all_possibilities(); + vector> get_positions_of_colors(vector guess); + + // Utility functions + void cannot_be(int n, int col); + void must_be(int n, int must_col); + void empty_color(int col); + + // Learning functions + bool if_not_here_then_nowhere(vector guess); + void here(vector guess); + void not_here(vector guess); + void empty(vector guess); + void all_are_here(vector guess); +}; + +// Guess-response remembering +struct Historic_guess { + vector guess; + Response response; + Historic_guess(vector _guess, Response _response); +}; diff --git a/solver.cpp b/solver.cpp index 7499145..c4a184c 100644 --- a/solver.cpp +++ b/solver.cpp @@ -1,144 +1,7 @@ #include "solver.hpp" -Game::Game(int p_N, int p_M) : N(p_N), M(p_M) { - possible = vector>(N, vector(M, 1)); - empty_colors = vector(M, 0); - final = vector(N, -1); - - unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count(); - random_engine = std::default_random_engine(seed); -} - -// Getting known information -bool Game::can(int n, int col) { - return possible[n][col]; -} -vector> Game::get_positions_of_colors(vector guess) { - auto positions_of_colors = vector>(M, vector(0)); - for(int n = 0; n < N; n++) - if(guess[n] > -1) - positions_of_colors[guess[n]].push_back(n); - return positions_of_colors; -} -int Game::final_color(int n) { - if(final[n] > -1) - return final[n]; - int final_col, count = 0; - for(int col = 0; col < M; col++) - if(possible[n][col]) { - final_col = col; - count++; - } - - if(count == 1) { - final[n] = final_col; - return final_col; - } - return -1; -} -bool Game::is_empty(int col) { - if(empty_colors[col]) - return true; - - for(int n = 0; n < N; n++) - if(possible[n][col]) - return false; - empty_colors[col] = true; - return true; -} -vector> Game::list_all_possibilities() { - auto r = vector>(N, vector(0)); - for(int col = 0; col < M; col++) - for(int n = 0; n < N; n++) - if(possible[n][col]) - r[n].push_back(col); - - for(int n = 0; n < N; n++) - std::shuffle(r[n].begin(), r[n].end(), random_engine); - return r; -} -void Game::print() { - cout << " "; - for(int col = 0; col < M; col++) - cout << col; - cout << std::endl; - for(int i = 0; i < N; i++) { - cout << i; - for(auto col : possible[i]) - cout << col; - cout << std::endl;; - } - cout << std::endl; -} - -// Learning functions -void Game::cannot_be(int n, int col) { - possible[n][col] = false; -} -void Game::must_be(int n, int must_col) { - for(int col = 0; col < M; col++) - if(col != must_col) - possible[n][col] = 0; -} -void Game::empty_color(int col) { - for(int n = 0; n < N; n++) - possible[n][col] = 0; -} - -// Specific reactions -bool Game::if_not_here_then_nowhere(vector 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 - for(int col = 0; col < M; col++) { - int possible_count = 0; - for(int n : positions_of_colors[col]) - if(possible[n][col]) - possible_count++; - if(possible_count == 0 && positions_of_colors[col].size() > 0 && !is_empty(col)) { - empty_color(col); - learned_something = true; - } - } - - return learned_something; -} -void Game::here(vector guess) { - for(int n = 0; n < N; n++) - if(guess[n] > -1 && possible[n][guess[n]]) - must_be(n, guess[n]); -} -void Game::not_here(vector guess) { - for(int n = 0; n < N; n++) - if(guess[n] > -1) - cannot_be(n, guess[n]); -} -void Game::empty(vector guess) { - for(int col : guess) - if(col > -1) - empty_color(col); -} -void Game::all_are_here(vector guess) { - auto positions_of_colors = get_positions_of_colors(guess); - - for(int col = 0; col < M; col++) { - if(positions_of_colors[col].size() == 0) - empty_color(col); - } -} - - -// For remembering guesses with their responses -Historic_guess::Historic_guess(vector _guess, Response _response) { - guess = _guess; - response = _response; -} - - -// Solver -Solver::Solver(int p_N, int p_M) : N(p_N), M(p_M), known({p_N, p_M}) {} +Solver::Solver(int _N, int _M) : N(_N), M(_M), known({_N, _M}) {} // Check, if it could have been this bool Solver::all_are_consistent(vector supposed_sequence) { @@ -313,16 +176,16 @@ vector Solver::extract_info(Historic_guess hist) { return {something_to_learn, learned_something}; } -void Solver::learn(vector _guess, Response _response) { +void Solver::learn(vector guess, Response response) { // All guessed colors are in the sequence - if(_response.somewhere + _response.correct == N) - known.all_are_here(_guess); + if(response.somewhere + response.correct == N) + known.all_are_here(guess); - if(_guess[0] == -1) + if(guess[0] == -1) return; // Write to history - history.push_back({_guess, _response}); + history.push_back({guess, response}); // Repeat multiple times, if new information turned out bool learned_something = true; diff --git a/solver.hpp b/solver.hpp index f422e66..15f4f87 100644 --- a/solver.hpp +++ b/solver.hpp @@ -1,53 +1,13 @@ #pragma once #include "global.hpp" -#include -#include -#include -struct Game { -private: - vector> possible; - vector empty_colors; - vector final; - std::default_random_engine random_engine; -public: - int N, M; - Game(int p_N, int p_M); - - // Get known information - bool can(int n, int col); - int final_color(int n); - bool is_empty(int col); - void print(); - vector> list_all_possibilities(); - vector> get_positions_of_colors(vector guess); - - // Utility functions - void cannot_be(int n, int col); - void must_be(int n, int must_col); - void empty_color(int col); - - // Learning functions - bool if_not_here_then_nowhere(vector guess); - void here(vector guess); - void not_here(vector guess); - void empty(vector guess); - void all_are_here(vector guess); -}; - -// For remembering guesses with their responses -struct Historic_guess { - vector guess; - Response response; - Historic_guess(vector _guess, Response _response); -}; // For deciding the best guess struct Weighed_guess { int weight; vector guess; - Weighed_guess(int pw, vector pg) : weight(pw), guess(pg) {} + Weighed_guess(int _w, vector _g) : weight(_w), guess(_g) {} Weighed_guess() {} };