Implementation successfully got out of the header files
This commit is contained in:
parent
adcc4961a6
commit
e86ba08846
9 changed files with 348 additions and 215 deletions
|
@ -1,9 +1,5 @@
|
||||||
#pragma once
|
#include "global.hpp"
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
using std::string;
|
|
||||||
using std::to_string;
|
using std::to_string;
|
||||||
|
|
||||||
#define YELLOW "\033[33m"
|
#define YELLOW "\033[33m"
|
|
@ -1,17 +1,21 @@
|
||||||
#pragma once
|
#include "global.hpp"
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
using std::cout;
|
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
// Table of NxM saying which position can hold which color
|
// Table of NxM saying which position can hold which color
|
||||||
vector<vector<bool>> possible;
|
vector<vector<bool>> possible;
|
||||||
|
std::default_random_engine random_engine;
|
||||||
public:
|
public:
|
||||||
int N, M;
|
int N, M;
|
||||||
Game(int p_N, int p_M) : N(p_N), M(p_M) {
|
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));
|
||||||
|
|
||||||
|
unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||||
|
random_engine = std::default_random_engine(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Learning functions
|
// Learning functions
|
||||||
|
@ -64,7 +68,10 @@ public:
|
||||||
for(int col = 0; col < M; col++)
|
for(int col = 0; col < M; col++)
|
||||||
for(int n = 0; n < N; n++)
|
for(int n = 0; n < N; n++)
|
||||||
if(possible[n][col])
|
if(possible[n][col])
|
||||||
r[col].push_back(n);
|
r[n].push_back(col);
|
||||||
|
|
||||||
|
for(int n = 0; n < N; n++)
|
||||||
|
std::shuffle(r[n].begin(), r[n].end(), random_engine);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -1,9 +1,7 @@
|
||||||
#pragma once
|
#include "global.hpp"
|
||||||
#include <vector>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
vector<int> generate(int N, int M) {
|
vector<int> generate(int N, int M) {
|
||||||
srand((unsigned)time(0));
|
srand((unsigned)time(0));
|
22
global.hpp
Normal file
22
global.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
using std::string;
|
||||||
|
using std::cout;
|
||||||
|
using std::cin;
|
||||||
|
|
||||||
|
|
||||||
|
// Game generating
|
||||||
|
string get_input(string arg, vector<string> args, string prompt_text, string default_arg);
|
||||||
|
vector<int> generate(int N, int M);
|
||||||
|
|
||||||
|
// Formatting
|
||||||
|
string format_response(vector<int> response);
|
||||||
|
string format_guess(vector<int> guess);
|
||||||
|
string format_guess_history(vector<int> sequence, vector<int> guess);
|
||||||
|
string format_lost_sequence(vector<int> sequence);
|
||||||
|
|
||||||
|
// Validating
|
||||||
|
vector<int> validate(vector<int> sequence, vector<int> guess);
|
|
@ -1,11 +1,5 @@
|
||||||
#include <iostream>
|
#include "global.hpp"
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
using std::string;
|
|
||||||
using std::cout;
|
|
||||||
using std::cin;
|
|
||||||
|
|
||||||
string get_param(string arg, vector<string> args) {
|
string get_param(string arg, vector<string> args) {
|
||||||
for(int i = 0; i < args.size(); i += 2) {
|
for(int i = 0; i < args.size(); i += 2) {
|
8
main.cpp
8
main.cpp
|
@ -1,10 +1,6 @@
|
||||||
|
#include "global.hpp"
|
||||||
#include "solver.hpp"
|
#include "solver.hpp"
|
||||||
#include "gen.hpp"
|
|
||||||
#include "validate.hpp"
|
|
||||||
#include "format.hpp"
|
|
||||||
#include "input.hpp"
|
|
||||||
|
|
||||||
using std::cin;
|
|
||||||
using std::getline;
|
using std::getline;
|
||||||
|
|
||||||
// To avoid typos
|
// To avoid typos
|
||||||
|
@ -57,7 +53,7 @@ int main(int argc, char* argv[]) {
|
||||||
vector<int> guess(N), response;
|
vector<int> guess(N), response;
|
||||||
cout << "Guess " << history.size() << " : ";
|
cout << "Guess " << history.size() << " : ";
|
||||||
|
|
||||||
// Bot playing
|
// Bot playin
|
||||||
if(player == BOT) {
|
if(player == BOT) {
|
||||||
guess = bot.guess();
|
guess = bot.guess();
|
||||||
cout << format_guess(guess);
|
cout << format_guess(guess);
|
||||||
|
|
258
solver.cpp
Normal file
258
solver.cpp
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
#include "solver.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
Game::Game(int p_N, int p_M) : N(p_N), M(p_M) {
|
||||||
|
possible = vector<vector<bool>>(N, vector<bool>(M, 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<vector<int>> Game::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;
|
||||||
|
}
|
||||||
|
int Game::final_color(int n) {
|
||||||
|
int final_col, count = 0;
|
||||||
|
for(int col = 0; col < M; col++)
|
||||||
|
if(possible[n][col]) {
|
||||||
|
final_col = col;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count == 1)
|
||||||
|
return final_col;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
vector<vector<int>> Game::list_all_possibilities() {
|
||||||
|
auto r = vector<vector<int>>(N, vector<int>(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;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
void Game::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(possible[n][col])
|
||||||
|
possible_count++;
|
||||||
|
if(possible_count == 0 && positions_of_colors[col].size() > 0)
|
||||||
|
empty_color(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Game::here(vector<int> 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<int> guess) {
|
||||||
|
for(int n = 0; n < N; n++)
|
||||||
|
if(guess[n] > -1)
|
||||||
|
cannot_be(n, guess[n]);
|
||||||
|
}
|
||||||
|
void Game::empty(vector<int> guess) {
|
||||||
|
for(int col : guess)
|
||||||
|
if(col > -1)
|
||||||
|
empty_color(col);
|
||||||
|
}
|
||||||
|
void Game::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())
|
||||||
|
empty_color(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// For remembering guesses with their responses
|
||||||
|
Historic_guess::Historic_guess(vector<int> p_guess, vector<int> p_response) {
|
||||||
|
guess = p_guess;
|
||||||
|
response = p_response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solver
|
||||||
|
|
||||||
|
Solver::Solver(int p_N, int p_M) : N(p_N), M(p_M), known({p_N, p_M}) {}
|
||||||
|
|
||||||
|
// Check, if it could have been this
|
||||||
|
bool Solver::all_are_consistent(vector<int> supposed_sequence) {
|
||||||
|
for(auto hist : history) {
|
||||||
|
auto response = validate(supposed_sequence, hist.guess);
|
||||||
|
if(response[0] != hist.response[0] || response[1] != hist.response[1])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try all remaining sequences
|
||||||
|
vector<int> Solver::brute_force(vector<vector<int>> *possibilities, vector<int> *chosen, int index) {
|
||||||
|
vector<int> r = vector<int>(N, -1);
|
||||||
|
if(index == N) {
|
||||||
|
if(all_are_consistent(*chosen))
|
||||||
|
r = *chosen;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
for(int col : (*possibilities)[index]) {
|
||||||
|
chosen->push_back(col);
|
||||||
|
r = brute_force(possibilities, chosen, index+1);
|
||||||
|
if(r[0] != -1)
|
||||||
|
return r;
|
||||||
|
chosen->pop_back();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guessing
|
||||||
|
vector<int> Solver::guess() {
|
||||||
|
auto possibilities = known.list_all_possibilities();
|
||||||
|
auto chosen = vector<int>(0);
|
||||||
|
return brute_force(&possibilities, &chosen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints what the solver deduced
|
||||||
|
void Solver::print() {
|
||||||
|
known.print();
|
||||||
|
auto possibilities = known.list_all_possibilities();
|
||||||
|
auto chosen = vector<int>(0);
|
||||||
|
auto v = brute_force(&possibilities, &chosen, 0);
|
||||||
|
cout << "Bruteforce chosen ";
|
||||||
|
for(int col : v)
|
||||||
|
cout << col << " ";
|
||||||
|
cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean guess and response from info we know
|
||||||
|
Historic_guess Solver::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Here there be learning
|
||||||
|
bool Solver::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) {
|
||||||
|
known.empty(guess);
|
||||||
|
something_to_learn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// None at the right spot
|
||||||
|
else if(response[1] == 0)
|
||||||
|
known.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) {
|
||||||
|
known.here(guess);
|
||||||
|
something_to_learn = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
known.if_not_here_then_nowhere(guess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nonzero / nonzero
|
||||||
|
else {
|
||||||
|
// Only colors that can be on these positions are left
|
||||||
|
if(response[1] == possible_count)
|
||||||
|
known.here(guess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All guessed colors are in the sequence
|
||||||
|
if(response[0] + response[1] == N)
|
||||||
|
known.all_are_here(guess);
|
||||||
|
|
||||||
|
return something_to_learn;
|
||||||
|
}
|
||||||
|
void Solver::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--;
|
||||||
|
}
|
||||||
|
}
|
234
solver.hpp
234
solver.hpp
|
@ -1,195 +1,59 @@
|
||||||
#pragma once
|
#include "global.hpp"
|
||||||
#include "gamestate.hpp"
|
#include <algorithm>
|
||||||
#include "validate.hpp"
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
|
struct Game {
|
||||||
|
private:
|
||||||
|
vector<vector<bool>> possible;
|
||||||
|
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);
|
||||||
|
void print();
|
||||||
|
vector<vector<int>> list_all_possibilities();
|
||||||
|
vector<vector<int>> get_positions_of_colors(vector<int> 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
|
||||||
|
void if_not_here_then_nowhere(vector<int> guess);
|
||||||
|
void here(vector<int> guess);
|
||||||
|
void not_here(vector<int> guess);
|
||||||
|
void empty(vector<int> guess);
|
||||||
|
void all_are_here(vector<int> guess);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// For remembering guesses with their responses
|
||||||
|
struct Historic_guess {
|
||||||
|
vector<int> guess, response;
|
||||||
|
Historic_guess(vector<int> p_guess, vector<int> p_response);
|
||||||
|
};
|
||||||
|
|
||||||
class Solver {
|
class Solver {
|
||||||
Game known;
|
Game known;
|
||||||
int N, M;
|
int N, M;
|
||||||
vector<Historic_guess> history = {};
|
vector<Historic_guess> history = {};
|
||||||
public:
|
public:
|
||||||
Solver(int p_N, int p_M) : N(p_N), M(p_M), known({p_N, p_M}) {}
|
Solver(int N, int M);
|
||||||
|
|
||||||
// Guessing
|
vector<int> guess();
|
||||||
vector<int> guess() {
|
void print();
|
||||||
auto possibilities = known.list_all_possibilities();
|
void learn(vector<int> guess, vector<int> response);
|
||||||
auto chosen = vector<int>(0);
|
|
||||||
return brute_force(&possibilities, &chosen, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility functions
|
private:
|
||||||
// Prints what the solver deduced
|
Historic_guess clean(Historic_guess hist);
|
||||||
void print() {
|
bool extract_info(Historic_guess hist);
|
||||||
known.print();
|
|
||||||
auto possibilities = known.list_all_possibilities();
|
|
||||||
auto chosen = vector<int>(0);
|
|
||||||
auto v = brute_force(&possibilities, &chosen, 0);
|
|
||||||
cout << "Bruteforce chosen ";
|
|
||||||
for(int col : v)
|
|
||||||
cout << col << " ";
|
|
||||||
cout << std::endl;
|
|
||||||
}
|
|
||||||
// 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
|
bool all_are_consistent(vector<int> supposed_sequence);
|
||||||
for(int n = 0; n < N; n++) {
|
vector<int> brute_force(vector<vector<int>> *possibilities, vector<int> *chosen, int index);
|
||||||
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;
|
|
||||||
}
|
|
||||||
// Check, if it could have been this
|
|
||||||
bool is_consistent(vector<int> supposed_sequence, Historic_guess hist) {
|
|
||||||
auto response = validate(supposed_sequence, hist.guess);
|
|
||||||
return response[0] == hist.response[0] &&
|
|
||||||
response[1] == hist.response[1];
|
|
||||||
}
|
|
||||||
bool all_are_consistent(vector<int> supposed_sequence) {
|
|
||||||
for(auto hist : history)
|
|
||||||
if(!is_consistent(supposed_sequence, hist))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try all remaining sequences
|
|
||||||
vector<int> brute_force(vector<vector<int>> *possibilities, vector<int> *chosen, int index) {
|
|
||||||
vector<int> r = vector<int>(N, -1);
|
|
||||||
if(index == N) {
|
|
||||||
if(all_are_consistent(*chosen))
|
|
||||||
r = *chosen;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
for(int col : (*possibilities)[index]) {
|
|
||||||
chosen->push_back(col);
|
|
||||||
r = brute_force(possibilities, chosen, index+1);
|
|
||||||
if(r[0] != -1)
|
|
||||||
return r;
|
|
||||||
chosen->pop_back();
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
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--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#pragma once
|
#include "global.hpp"
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
vector<int> validate(vector<int> sequence, vector<int> guess) {
|
vector<int> validate(vector<int> sequence, vector<int> guess) {
|
||||||
int N = sequence.size();
|
int N = sequence.size();
|
Loading…
Reference in a new issue