157 lines
3.8 KiB
C++
157 lines
3.8 KiB
C++
#pragma once
|
|
#include "gamestate.hpp"
|
|
|
|
class Solver {
|
|
Game known;
|
|
int N, M;
|
|
vector<Historic_guess> history = {};
|
|
public:
|
|
Solver(int p_N, int p_M) : N(p_N), M(p_M), known({p_N, p_M}) {}
|
|
|
|
// Guessing
|
|
vector<int> guess() {
|
|
// TODO
|
|
return {};
|
|
}
|
|
|
|
// Utility functions
|
|
// Prints what the solver deduced
|
|
void print() {
|
|
known.print();
|
|
}
|
|
// Clean guess and response from info we know
|
|
Historic_guess clean(Historic_guess hist) {
|
|
// The in-place colors we know
|
|
for(int n = 0; n < 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 < N; n++) {
|
|
if(hist.guess[n] == -1)
|
|
continue;
|
|
for(int i = 0; i < N; i++) {
|
|
if(i == n)
|
|
continue;
|
|
if(known.final_color(i) == hist.guess[n]) {
|
|
hist.guess[n] = -1;
|
|
hist.response[0] -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hist;
|
|
}
|
|
// For each color, get where it was guessed
|
|
vector<vector<int>> get_positions_of_colors(vector<int> guess) {
|
|
auto positions_of_colors = vector<vector<int>>(M, vector<int>(0));
|
|
for(int n = 0; n < 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<int> 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 < M; col++) {
|
|
int possible_count = 0;
|
|
for(int n : positions_of_colors[col])
|
|
if(known.can(n, col))
|
|
possible_count++;
|
|
if(possible_count == 0 && positions_of_colors[col].size() > 0)
|
|
known.empty_color(col);
|
|
}
|
|
}
|
|
void here(vector<int> guess) {
|
|
for(int n = 0; n < N; n++)
|
|
if(guess[n] > -1 && known.can(n, guess[n]))
|
|
known.must_be(n, guess[n]);
|
|
}
|
|
void not_here(vector<int> guess) {
|
|
for(int n = 0; n < N; n++)
|
|
if(guess[n] > -1)
|
|
known.cannot_be(n, guess[n]);
|
|
}
|
|
void empty(vector<int> guess) {
|
|
for(int col : guess)
|
|
if(col > -1)
|
|
known.empty_color(col);
|
|
}
|
|
void all_are_here(vector<int> guess) {
|
|
auto positions_of_colors = get_positions_of_colors(guess);
|
|
|
|
for(int col = 0; col < 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);
|
|
auto guess = cleaned.guess;
|
|
auto response = cleaned.response;
|
|
|
|
// Get number of colors, that can be on their positions
|
|
int possible_count = 0;
|
|
for(int n = 0; n < N; n++)
|
|
if(guess[n] > -1 && known.can(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] == N)
|
|
all_are_here(guess);
|
|
|
|
return something_to_learn;
|
|
}
|
|
void learn(vector<int> p_guess, vector<int> p_response) {
|
|
// Write to history
|
|
history.push_back({p_guess, p_response});
|
|
|
|
// Repeat multiple times, if new information turned out
|
|
for(auto _ : history)
|
|
// 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--;
|
|
}
|
|
}
|
|
};
|