Game state implemented in separate .cpp file
This commit is contained in:
parent
a9b8f34c2d
commit
02f72064cd
4 changed files with 184 additions and 184 deletions
137
game.cpp
Normal file
137
game.cpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include "global.hpp"
|
||||||
|
|
||||||
|
Game::Game(int _N, int _M) : N(_N), M(_M) {
|
||||||
|
possible = vector<vector<bool>>(N, vector<bool>(M, 1));
|
||||||
|
empty_colors = vector<bool>(M, 0);
|
||||||
|
final = vector<int>(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<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) {
|
||||||
|
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<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;;
|
||||||
|
}
|
||||||
|
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<int> 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<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() == 0)
|
||||||
|
empty_color(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For remembering guesses with their responses
|
||||||
|
Historic_guess::Historic_guess(vector<int> _guess, Response _response) {
|
||||||
|
guess = _guess;
|
||||||
|
response = _response;
|
||||||
|
}
|
40
global.hpp
40
global.hpp
|
@ -2,6 +2,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
@ -27,3 +28,42 @@ string format_lost_sequence(vector<int> sequence);
|
||||||
|
|
||||||
// Validating
|
// Validating
|
||||||
Response validate(vector<int> sequence, vector<int> guess);
|
Response validate(vector<int> sequence, vector<int> guess);
|
||||||
|
|
||||||
|
// Game remembering
|
||||||
|
struct Game {
|
||||||
|
private:
|
||||||
|
vector<vector<bool>> possible;
|
||||||
|
vector<bool> empty_colors;
|
||||||
|
vector<int> 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<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
|
||||||
|
bool 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Guess-response remembering
|
||||||
|
struct Historic_guess {
|
||||||
|
vector<int> guess;
|
||||||
|
Response response;
|
||||||
|
Historic_guess(vector<int> _guess, Response _response);
|
||||||
|
};
|
||||||
|
|
149
solver.cpp
149
solver.cpp
|
@ -1,144 +1,7 @@
|
||||||
#include "solver.hpp"
|
#include "solver.hpp"
|
||||||
|
|
||||||
|
|
||||||
Game::Game(int p_N, int p_M) : N(p_N), M(p_M) {
|
Solver::Solver(int _N, int _M) : N(_N), M(_M), known({_N, _M}) {}
|
||||||
possible = vector<vector<bool>>(N, vector<bool>(M, 1));
|
|
||||||
empty_colors = vector<bool>(M, 0);
|
|
||||||
final = vector<int>(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<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) {
|
|
||||||
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<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;;
|
|
||||||
}
|
|
||||||
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<int> 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<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() == 0)
|
|
||||||
empty_color(col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// For remembering guesses with their responses
|
|
||||||
Historic_guess::Historic_guess(vector<int> _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}) {}
|
|
||||||
|
|
||||||
// Check, if it could have been this
|
// Check, if it could have been this
|
||||||
bool Solver::all_are_consistent(vector<int> supposed_sequence) {
|
bool Solver::all_are_consistent(vector<int> supposed_sequence) {
|
||||||
|
@ -313,16 +176,16 @@ vector<bool> Solver::extract_info(Historic_guess hist) {
|
||||||
|
|
||||||
return {something_to_learn, learned_something};
|
return {something_to_learn, learned_something};
|
||||||
}
|
}
|
||||||
void Solver::learn(vector<int> _guess, Response _response) {
|
void Solver::learn(vector<int> guess, Response response) {
|
||||||
// All guessed colors are in the sequence
|
// All guessed colors are in the sequence
|
||||||
if(_response.somewhere + _response.correct == N)
|
if(response.somewhere + response.correct == N)
|
||||||
known.all_are_here(_guess);
|
known.all_are_here(guess);
|
||||||
|
|
||||||
if(_guess[0] == -1)
|
if(guess[0] == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Write to history
|
// Write to history
|
||||||
history.push_back({_guess, _response});
|
history.push_back({guess, response});
|
||||||
|
|
||||||
// Repeat multiple times, if new information turned out
|
// Repeat multiple times, if new information turned out
|
||||||
bool learned_something = true;
|
bool learned_something = true;
|
||||||
|
|
42
solver.hpp
42
solver.hpp
|
@ -1,53 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "global.hpp"
|
#include "global.hpp"
|
||||||
#include <algorithm>
|
|
||||||
#include <chrono>
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
|
|
||||||
struct Game {
|
|
||||||
private:
|
|
||||||
vector<vector<bool>> possible;
|
|
||||||
vector<bool> empty_colors;
|
|
||||||
vector<int> 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<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
|
|
||||||
bool 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 response;
|
|
||||||
Historic_guess(vector<int> _guess, Response _response);
|
|
||||||
};
|
|
||||||
|
|
||||||
// For deciding the best guess
|
// For deciding the best guess
|
||||||
struct Weighed_guess {
|
struct Weighed_guess {
|
||||||
int weight;
|
int weight;
|
||||||
vector<int> guess;
|
vector<int> guess;
|
||||||
Weighed_guess(int pw, vector<int> pg) : weight(pw), guess(pg) {}
|
Weighed_guess(int _w, vector<int> _g) : weight(_w), guess(_g) {}
|
||||||
Weighed_guess() {}
|
Weighed_guess() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue