logik/solver.hpp

146 lines
3.4 KiB
C++

#pragma once
#include "gamestate.hpp"
class Solver {
Game known;
vector<Historic_guess> history = {};
vector<int> sequence;
public:
Solver(int p_N, int p_M) : known({p_N, p_M}) {
sequence = vector<int>(p_N, -1);
}
// Guessing
vector<int> guess() {
// TODO
return {};
}
// Clear what we already know
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;
}
// Specific reactions
void if_not_here_then_nowhere(vector<int> guess) {
// Get all positions of these colors
auto positions_of_colors = vector<vector<int>>(known.M, vector<int>(0));
for(int n = 0; n < known.N; n++)
if(guess[n] > -1)
positions_of_colors[guess[n]].push_back(n);
// 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<int> guess) {
for(int n = 0; n < known.N; n++)
if(guess[n] > -1)
for(int col = 0; col < known.M; col++) {
if(col != guess[n])
known.possible[n][col] = 0;
}
}
void not_here(vector<int> guess) {
for(int n = 0; n < known.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);
}
bool extract_info(Historic_guess hist) {
bool something_to_learn = true;
// A bit of cleaning
auto cleaned = clean(hist);
vector<int> guess = cleaned.guess;
vector<int> 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);
}
return something_to_learn;
}
void learn(vector<int> p_guess, vector<int> 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();
}
};