Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • francesco-bariatti/pingouins
  • Samuel.Felton/pingouins
  • Lucas.Clement/pingouins
3 results
Show changes
Commits on Source (10)
...@@ -20,3 +20,5 @@ GUI/GUI.iml ...@@ -20,3 +20,5 @@ GUI/GUI.iml
*.blg *.blg
*.nav *.nav
*.snm *.snm
*.layout
*.cbp
ai_vs_ai=1
ai_think_time=5000
ai_vs_ai_game_count=100
heuristic_ai_1=movement_freedom
heuristic_ai_2=default
send_game_to_gui=1
#include "config.hpp"
#include <iostream>
#include <fstream>
#include <algorithm>
#include "movement_freedom_heuristic.hpp"
namespace game {
config::config(std::string& filename) : ai_vs_ai(false), think_time(5000), game_count(100), heuristic_ai_1(nullptr), heuristic_ai_2(nullptr)
{
std::ifstream file;
std::string line;
file.open(filename);
if(file.is_open()){
while(std::getline(file,line)) {
line.erase(std::remove_if(line.begin(),line.end(),[](char c) {return std::isspace(c);}),
line.end());
size_t indexEqual = line.find_first_of('=');
const std::string& lvalue = line.substr(0,indexEqual);
const std::string& rvalue = line.substr(indexEqual+1);
handle_line(lvalue,rvalue);
}
file.close();
}
if(heuristic_ai_1 == nullptr) {
std::cout << "H1";
heuristic_ai_1 = new mcts::penguin_heuristic();
}
if(heuristic_ai_2 == nullptr) {
heuristic_ai_2 = new mcts::penguin_heuristic();
}
}
void config::handle_line(const std::string& option_name, const std::string& option_value)
{
if(option_name == "ai_vs_ai") {
set_game_mode(option_value);
} else if(option_name == "ai_think_time") {
set_think_time(option_value);
} else if(option_name == "ai_vs_ai_game_count") {
set_game_count(option_value);
} else if (option_name == "heuristic_ai_1") {
set_heuristic(option_value,1);
} else if (option_name == "heuristic_ai_2") {
set_heuristic(option_value,2);
} else if(option_name == "send_game_to_gui"){
set_send_game(option_value);
} else {
std::cerr << "Unknown option : " << option_name << std::endl;
}
}
void config::set_game_mode(const std::string& value)
{
int v = std::stoi(value);
ai_vs_ai = v;
}
void config::set_think_time(const std::string& value)
{
int v = std::stoi(value);
think_time = v;
}
void config::set_game_count(const std::string& value)
{
int v = std::stoi(value);
game_count = v;
}
void config::set_heuristic(const std::string& value, short player)
{
mcts::penguin_heuristic** h = player == 1 ? &heuristic_ai_1 : &heuristic_ai_2;
if(value == "left_up") {
*h = new mcts::go_left_up_heuristic();
}
if(value == "movement_freedom") {
*h = new mcts::movement_freedom_heuristic();
}
if(value == "default") {
*h = new mcts::penguin_heuristic();
} else {
std::cerr << "Unknown heuristic : " << value << std::endl;
}
}
void config::set_send_game(const std::string& value)
{
int v = std::stoi(value);
send_game_to_gui = v;
}
}
#ifndef __CONFIG_HPP__
#define __CONFIG_HPP__
#include <string>
#include "penguin_heuristic.hpp"
#include "penguin.hpp"
#define DEFAULT_FILENAME "AI.conf"
namespace game {
class config {
public:
const bool is_ai_vs_ai() {return ai_vs_ai;};
const bool should_send_game_to_gui(){return send_game_to_gui;};
const unsigned int get_think_time() { return think_time; };
const unsigned int get_game_count() { return game_count; };
const mcts::penguin_heuristic* get_heuristic(short player) {return player == 1 ? heuristic_ai_1 : heuristic_ai_2; };
~config() {delete heuristic_ai_1; delete heuristic_ai_2;}
static config& get_config()
{
static std::string s(DEFAULT_FILENAME);
static config c(s);
return c;
};
config(config const&) = delete;
void operator=(config const&) = delete;
private:
config(std::string& filename);
void handle_line(const std::string& option_name, const std::string& option_value);
void set_game_mode(const std::string& value);
void set_think_time(const std::string& value);
void set_game_count(const std::string& value);
void set_heuristic(const std::string& value, short player);
void set_send_game(const std::string& value);
bool ai_vs_ai, send_game_to_gui;
unsigned int think_time;
unsigned int game_count;
mcts::penguin_heuristic* heuristic_ai_1;
mcts::penguin_heuristic* heuristic_ai_2;
};
}
#endif
...@@ -358,6 +358,24 @@ namespace game ...@@ -358,6 +358,24 @@ namespace game
state.current_player_red = true; state.current_player_red = true;
} }
} }
const tile_content penguin::get_tile(std::uint8_t tile_index) const
{
for(int k = 0; k < 4; k++) {
if(PENGUIN_POS(state.peng_blue[k]) == tile_index)
return BLUE_PENGUIN;
if(PENGUIN_POS(state.peng_red[k]) == tile_index)
return RED_PENGUIN;
}
if(((state.one_fish >> (tile_index)) & 1) > 0)
return ONE_FISH;
if(((state.two_fish >> (tile_index)) & 1) > 0)
return TWO_FISH;
if(((state.three_fish >> tile_index) & 1) > 0)
return THREE_FISH;
return OBSTACLE;
}
string penguin::player_to_string(uint8_t player) const string penguin::player_to_string(uint8_t player) const
{ {
......
...@@ -32,6 +32,8 @@ namespace game ...@@ -32,6 +32,8 @@ namespace game
bool canPlay_red = true; bool canPlay_red = true;
bool canPlay_blue = true; bool canPlay_blue = true;
}; };
//Describes the possible content of a peguin game tile
enum tile_content {RED_PENGUIN,BLUE_PENGUIN,ONE_FISH,TWO_FISH,THREE_FISH,OBSTACLE};
// Useful macros to get values out of penguins // Useful macros to get values out of penguins
#define PENGUIN_POS(penguin) ((penguin) & 63) #define PENGUIN_POS(penguin) ((penguin) & 63)
...@@ -69,6 +71,12 @@ namespace game ...@@ -69,6 +71,12 @@ namespace game
std::shared_ptr<game<penguin_state>> do_copy() const; std::shared_ptr<game<penguin_state>> do_copy() const;
std::uint64_t hash(std::uint16_t m) const; std::uint64_t hash(std::uint16_t m) const;
std::uint64_t hash() const; std::uint64_t hash() const;
/**
Returns the content of a tile
i : the line, between 0 and 7
j : the column, between 0 and 7 if i is pair else between 0 and 8
*/
const tile_content get_tile(std::uint8_t tile_index) const;
private: private:
penguin_state state; penguin_state state;
......
...@@ -23,20 +23,22 @@ ...@@ -23,20 +23,22 @@
#include "test_mcts_two_players.hpp" #include "test_mcts_two_players.hpp"
#include "test_bits.hpp" #include "test_bits.hpp"
#include "learning.hpp" #include "learning.hpp"
#include "penguin_heuristic.hpp"
#include "config.hpp"
#include <omp.h> #include <omp.h>
using namespace std; using namespace std;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// util::test_fast_log(100000000);
// mcts::test_allocator(10, 2); // mcts::test_allocator(10, 2);
// omp_set_num_threads(8); // omp_set_num_threads(8);
game::config& c = game::config::get_config();
//game::run_test_two_players_game(game::penguin()); const mcts::penguin_heuristic& h1 = *(c.get_heuristic(1));
mcts::run_test_mcts_two_players(game::penguin()); const mcts::penguin_heuristic& h2 = *(c.get_heuristic(2));
mcts::run_test_mcts_two_players(game::penguin(),h1,h2);
//util::test_bits(200000000);
return 0; return 0;
} }
#ifndef __MCTS_SETTINGS_HPP__ #ifndef __MCTS_SETTINGS_HPP__
#define __MCTS_SETTINGS_HPP__ #define __MCTS_SETTINGS_HPP__
// Allocated memory for the mcts. If not enough the program may crash // Allocated memory for the mcts. If not enough the program may crash
#define MCTS_ALLOCATOR_SIZE 1000000U #define MCTS_ALLOCATOR_SIZE 100000000U
// Reflection time for every turn of the mcts (in ms) // Reflection time for every turn of the mcts (in ms)
#define MCTS_TURN_TIME 5000 #define MCTS_TURN_TIME 5000
......
#ifndef __HEURISTIC_HPP__
#define __HEURISTIC_HPP__
namespace mcts
{
template <typename Game>
class heuristic
{
public:
virtual float get_value(const Game& game, uint8_t move) const = 0;
virtual int get_count(const Game& game, uint8_t move) const = 0;
virtual ~heuristic(){};
};
template <typename Game>
class zero_knowledge : public heuristic<Game>
{
public:
float get_value(const Game& game, uint8_t move) const
{
return 0.f;
}
int get_count(const Game& game, uint8_t move) const
{
return 1;
}
};
}
#endif
...@@ -9,60 +9,68 @@ ...@@ -9,60 +9,68 @@
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include "openings.hpp" #include "openings.hpp"
#include "heuristic.hpp"
namespace mcts namespace mcts
{ {
template <typename Game> template <typename Game>
class mcts_two_players : public mcts<Game> class mcts_two_players : public mcts<Game>
{ {
allocator alloc_; allocator alloc_;
const util::fast_log fast_log_; const util::fast_log fast_log_;
const float C_; const float C_;
const unsigned int nb_visits_before_expansion_; const unsigned int nb_visits_before_expansion_;
const heuristic<Game>& heuristic_;
const bool new_version_; const bool new_version_;
inline node* select(const std::shared_ptr<Game>& game, std::mt19937& generator, node* parent); inline node* select(const std::shared_ptr<Game>& game, std::mt19937& generator, node* parent);
inline void expand(const std::shared_ptr<Game>& game, node* n); inline void expand(const std::shared_ptr<Game>& game, node* n);
void think(const std::shared_ptr<Game>& game); void think(const std::shared_ptr<Game>& game);
public: public:
mcts_two_players(Game& game, uint32_t milliseconds, float C, unsigned int nb_visits_before_expansion = 8, bool new_version = true); mcts_two_players(Game& game, uint32_t milliseconds, float C, unsigned int nb_visits_before_expansion = 8,
const heuristic<Game>& heuristic = zero_knowledge<Game>(), bool new_version = true);
void reset(); void reset();
void init_with_openings(const openings& o); void init_with_openings(const openings& o);
inline uint16_t select_move(); inline uint16_t select_move();
void last_move(uint16_t move); void last_move(uint16_t move);
void last_moves(uint16_t computer, uint16_t other); void last_moves(uint16_t computer, uint16_t other);
}; };
template <typename Game> template <typename Game>
mcts_two_players<Game> make_mcts_two_players(Game& game, uint32_t milliseconds, float C, unsigned int nb_visits_before_expansion = 8, bool new_version = true) mcts_two_players<Game> make_mcts_two_players(Game& game, uint32_t milliseconds, float C, unsigned int nb_visits_before_expansion = 8,
{ const heuristic<Game>& heuristic = zero_knowledge<Game>(),
return mcts_two_players<Game>(game, milliseconds, C, nb_visits_before_expansion, new_version); bool new_version = true)
} {
return mcts_two_players<Game>(game, milliseconds, C, nb_visits_before_expansion, heuristic, new_version);
}
template <typename Game> template <typename Game>
mcts_two_players<Game>::mcts_two_players(Game& game, uint32_t milliseconds, float C, unsigned int nb_visits_before_expansion, bool new_version) mcts_two_players<Game>::mcts_two_players(Game& game, uint32_t milliseconds, float C, unsigned int nb_visits_before_expansion,
: mcts<Game>(game, milliseconds), C_(C), nb_visits_before_expansion_(nb_visits_before_expansion), new_version_(new_version) const heuristic<Game>& heuristic,
{ bool new_version)
: mcts<Game>(game, milliseconds), C_(C), nb_visits_before_expansion_(nb_visits_before_expansion),
heuristic_(heuristic), new_version_(new_version)
{
this->generators.assign(util::omp_util::get_num_threads(), std::mt19937()); this->generators.assign(util::omp_util::get_num_threads(), std::mt19937());
this->root = alloc_.allocate(1); this->root = alloc_.allocate(1);
} }
template <typename Game> template <typename Game>
void mcts_two_players<Game>::reset() void mcts_two_players<Game>::reset()
{ {
alloc_.clear(); alloc_.clear();
this->root = alloc_.allocate(1); this->root = alloc_.allocate(1);
} }
template <typename Game> template <typename Game>
void mcts_two_players<Game>::init_with_openings(const openings& o) void mcts_two_players<Game>::init_with_openings(const openings& o)
{ {
o.copy_to(this->root, alloc_); o.copy_to(this->root, alloc_);
} }
template <typename Game> template <typename Game>
node* mcts_two_players<Game>::select(const std::shared_ptr<Game>& game, std::mt19937& generator, node* parent) node* mcts_two_players<Game>::select(const std::shared_ptr<Game>& game, std::mt19937& generator, node* parent)
{ {
using namespace std; using namespace std;
const unsigned int N = parent->get_statistics().count; const unsigned int N = parent->get_statistics().count;
const float log_of_N = fast_log_.log(N); const float log_of_N = fast_log_.log(N);
...@@ -76,63 +84,63 @@ namespace mcts ...@@ -76,63 +84,63 @@ namespace mcts
unsigned int count; unsigned int count;
float v; float v;
for (uint16_t i = 0; i < nb_children; ++i) for (uint16_t i = 0; i < nb_children; ++i)
{ {
node* child = children + k; node* child = children + k;
count = child->get_statistics().count; count = child->get_statistics().count;
v = -child->get_statistics().value + C_ * sqrt(log_of_N / count); v = -child->get_statistics().value + C_ * sqrt(log_of_N / count);
if (v > best_value_so_far) if (v > best_value_so_far)
{ {
best_value_so_far = v; best_value_so_far = v;
best_child_so_far = child; best_child_so_far = child;
best_move_so_far = k; best_move_so_far = k;
} }
++k; ++k;
if (k == nb_children) k = 0; if (k == nb_children) k = 0;
} }
if (best_child_so_far->is_proven()) if (best_child_so_far->is_proven())
{ {
if (best_child_so_far->is_lost()) parent->set_won(); if (best_child_so_far->is_lost()) parent->set_won();
else else
{ {
bool all_won = true; bool all_won = true;
for (uint16_t i = 0; i < nb_children; ++i) for (uint16_t i = 0; i < nb_children; ++i)
{ {
node* child = children + i; node* child = children + i;
if (!child->is_won()) if (!child->is_won())
{ {
all_won = false; all_won = false;
break; break;
} }
} }
if (all_won) parent->set_lost(); if (all_won) parent->set_lost();
} }
} }
game->play(best_move_so_far); game->play(best_move_so_far);
return best_child_so_far; return best_child_so_far;
} }
template <typename Game> template <typename Game>
void mcts_two_players<Game>::expand(const std::shared_ptr<Game>& game, node* n) void mcts_two_players<Game>::expand(const std::shared_ptr<Game>& game, node* n)
{ {
unsigned int count = n->get_statistics().count; unsigned int count = n->get_statistics().count;
if (count >= nb_visits_before_expansion_ && !n->test_and_set()) if (count >= nb_visits_before_expansion_ && !n->test_and_set())
{ {
unsigned int nb_children = game->number_of_moves(); unsigned int nb_children = game->number_of_moves();
node* children = alloc_.allocate(nb_children); node* children = alloc_.allocate(nb_children);
for (unsigned int i = 0; i < nb_children; ++i) for (unsigned int i = 0; i < nb_children; ++i)
{ {
node* child = children + i; node* child = children + i;
child->get_statistics_ref().count = 1; child->get_statistics_ref().count = heuristic_.get_count(*game, i);
child->get_statistics_ref().value = 0; child->get_statistics_ref().value = heuristic_.get_value(*game, i);
} }
n->set_children(children); n->set_children(children);
n->set_number_of_children(nb_children); n->set_number_of_children(nb_children);
} }
} }
template <typename Game> template <typename Game>
void mcts_two_players<Game>::think(const std::shared_ptr<Game>& game) void mcts_two_players<Game>::think(const std::shared_ptr<Game>& game)
{ {
using namespace std; using namespace std;
const chrono::steady_clock::time_point start = chrono::steady_clock::now(); const chrono::steady_clock::time_point start = chrono::steady_clock::now();
chrono::steady_clock::time_point now; chrono::steady_clock::time_point now;
...@@ -142,72 +150,72 @@ namespace mcts ...@@ -142,72 +150,72 @@ namespace mcts
vector<uint16_t> moves(200); vector<uint16_t> moves(200);
unsigned int nb_iter = 0; unsigned int nb_iter = 0;
do do
{ {
int size = 1; int size = 1;
node* current = this->root; node* current = this->root;
visited[0] = current; visited[0] = current;
while (!game->end_of_game() && !current->is_leaf() && !current->is_proven()) while (!game->end_of_game() && !current->is_leaf() && !current->is_proven())
{ {
current = select(game, generator, current); current = select(game, generator, current);
visited[size++] = current; visited[size++] = current;
} }
int game_value = 0; int game_value = 0;
if (current->is_proven()) if (current->is_proven())
{ {
if (current->is_won()) game_value = 1; if (current->is_won()) game_value = 1;
else else
{ {
game_value = -1; game_value = -1;
} }
} }
else if (game->end_of_game()) else if (game->end_of_game())
{ {
int v = game->value_for_current_player(); int v = game->value_for_current_player();
if (v > 0) if (v > 0)
{ {
game_value = 1; game_value = 1;
if (new_version_) current->set_won(); if (new_version_) current->set_won();
} }
else if (v < 0) else if (v < 0)
{ {
game_value = -1; game_value = -1;
if (new_version_) if (new_version_)
{ {
current->set_lost(); current->set_lost();
if (size > 1) visited[size - 2]->set_won(); if (size > 1) visited[size - 2]->set_won();
} }
} }
} }
else else
{ {
uint8_t player = game->current_player(); uint8_t player = game->current_player();
expand(game, current); expand(game, current);
game->playout(generator); game->playout(generator);
int v = game->value(player); int v = game->value(player);
if (v > 0) game_value = 1; if (v > 0) game_value = 1;
else if (v < 0) game_value = -1; else if (v < 0) game_value = -1;
} }
for (int i = size - 1; i >= 0; --i) for (int i = size - 1; i >= 0; --i)
{ {
visited[i]->update(game_value); visited[i]->update(game_value);
game_value = -game_value; game_value = -game_value;
} }
game->set_state(state); game->set_state(state);
++nb_iter; ++nb_iter;
if ((nb_iter & 0x3F) == 0) now = chrono::steady_clock::now(); if ((nb_iter & 0x3F) == 0) now = chrono::steady_clock::now();
} }
while ((nb_iter & 0x3F) != 0 || now < start + this->milliseconds); while ((nb_iter & 0x3F) != 0 || now < start + this->milliseconds);
} }
template <typename Game> template <typename Game>
uint16_t mcts_two_players<Game>::select_move() uint16_t mcts_two_players<Game>::select_move()
{ {
using namespace std; using namespace std;
if (!this->root->is_proven()) if (!this->root->is_proven())
{ {
#pragma omp parallel #pragma omp parallel
think(game::copy(this->game)); think(game::copy(this->game));
} }
// std::ofstream ofs ("graph.gv", ofstream::out); // std::ofstream ofs ("graph.gv", ofstream::out);
// util::display_node::node_to_dot(ofs, this->root, 1000, 50); // util::display_node::node_to_dot(ofs, this->root, 1000, 50);
util::display_node::node_to_ascii(cout, this->root, 1); util::display_node::node_to_ascii(cout, this->root, 1);
...@@ -222,52 +230,52 @@ namespace mcts ...@@ -222,52 +230,52 @@ namespace mcts
node* children = this->root->get_children(); node* children = this->root->get_children();
unsigned int c; unsigned int c;
for (uint16_t i = 0; i < nb_children; ++i) for (uint16_t i = 0; i < nb_children; ++i)
{ {
node *child = children + k; node *child = children + k;
if (child->is_lost()) if (child->is_lost())
{ {
best_move_so_far = k; best_move_so_far = k;
break; break;
} }
c = children[k].get_statistics().count; c = children[k].get_statistics().count;
if (c > best_count_so_far) if (c > best_count_so_far)
{ {
best_count_so_far = c; best_count_so_far = c;
best_move_so_far = k; best_move_so_far = k;
} }
++k; ++k;
if (k == nb_children) k = 0; if (k == nb_children) k = 0;
} }
return best_move_so_far; return best_move_so_far;
} }
template <typename Game> template <typename Game>
void mcts_two_players<Game>::last_moves(uint16_t computer, uint16_t other) void mcts_two_players<Game>::last_moves(uint16_t computer, uint16_t other)
{ {
if (this->root->is_leaf() || this->root->get_children()[computer].is_leaf()) if (this->root->is_leaf() || this->root->get_children()[computer].is_leaf())
{ {
alloc_.clear(); alloc_.clear();
this->root = alloc_.allocate(1); this->root = alloc_.allocate(1);
} }
else else
{ {
this->root = alloc_.move(&this->root->get_children()[computer].get_children()[other]); this->root = alloc_.move(&this->root->get_children()[computer].get_children()[other]);
} }
} }
template <typename Game> template <typename Game>
void mcts_two_players<Game>::last_move(uint16_t move) void mcts_two_players<Game>::last_move(uint16_t move)
{ {
if (this->root->is_leaf()) if (this->root->is_leaf())
{ {
alloc_.clear(); alloc_.clear();
this->root = alloc_.allocate(1); this->root = alloc_.allocate(1);
} }
else else
{ {
this->root = alloc_.move(&this->root->get_children()[move], 20); this->root = alloc_.move(&this->root->get_children()[move], 20);
} }
} }
} }
......
#include <iostream>
#include "penguin_heuristic.hpp"
#include "movement_freedom_heuristic.hpp"
#include "penguin.hpp"
#define MAX_NB_MOVES 60
using namespace std;
namespace mcts
{
float movement_freedom_heuristic::get_value(const game::penguin& game, uint8_t move) const
{
std::shared_ptr<game::penguin> played = game::copy(game);
//TEST SOLUTION 1
played->play(move);
game::penguin_state state = played->get_state();
uint32_t* penguins = state.peng_blue;
if(!state.current_player_red) {
penguins = state.peng_red;
}
uint32_t nb_moves = 0;
for(int i=0; i< 4; i++) {
nb_moves += PENGUIN_TOT_MOVES(penguins[i]);
}
float res = 2.0f*(float)nb_moves / (float)MAX_NB_MOVES - 1.0f;
return res;
//TEST SOLUTION 2
/*
played->play(move);
uint32_t nb_moves = played->number_of_moves();
float res = 2.0f*(float)nb_moves / (float)MAX_NB_MOVES - 1.0f;
return res;
*/
//TEST SOLUTION 3
/*
played->play(move);
game::penguin_state state = played->get_state();
uint32_t nb_moves = state.nb_moves_blue;
if(!state.current_player_red) {
nb_moves = state.nb_moves_red;
}
float res = 2.0f*(float)nb_moves / (float)MAX_NB_MOVES - 1.0f;
return res;
*/
}
int movement_freedom_heuristic::get_count(const game::penguin& game, uint8_t move) const
{
return 100000000;
}
}
#ifndef __MOVEMENT_FREEDOM_HEURISTIC_HPP__
#define __MOVEMENT_FREEDOM_HEURISTIC_HPP__
#include "penguin.hpp"
#include "penguin_heuristic.hpp"
namespace mcts
{
class movement_freedom_heuristic : public penguin_heuristic
{
public:
float get_value(const game::penguin& game, uint8_t move) const;
int get_count(const game::penguin& game, uint8_t move) const;
};
};
#endif
#include "penguin_heuristic.hpp"
#include "penguin.hpp"
using namespace std;
namespace mcts
{
float penguin_heuristic::get_value(const game::penguin& game, uint8_t move) const
{
return 0.f;
}
int penguin_heuristic::get_count(const game::penguin& game, uint8_t move) const
{
return 1;
}
float go_left_up_heuristic::get_value(const game::penguin& game, uint8_t move) const
{
std::shared_ptr<game::penguin> played = game::copy(game);
played->play(move);
game::penguin_state state = played->get_state();
uint32_t* penguins = state.peng_blue;
if(!state.current_player_red) {
penguins = state.peng_red;
}
uint32_t sPos = 0;
for(int i=0; i< 4; i++) {
sPos+=PENGUIN_POS(penguins[i]);
}
double res = (double) (-(-118.0 + sPos) / 118.0);
return res;
}
int go_left_up_heuristic::get_count(const game::penguin& game, uint8_t move) const
{
return 100000000;
}
}
#ifndef __PENGUIN_HEURISTIC_HPP__
#define __PENGUIN_HEURISTIC_HPP__
#include "penguin.hpp"
#include "heuristic.hpp"
namespace mcts
{
class penguin_heuristic : public heuristic<game::penguin>
{
public:
virtual float get_value(const game::penguin& game, uint8_t move) const;
virtual int get_count(const game::penguin& game, uint8_t move) const;
};
class go_left_up_heuristic : public penguin_heuristic
{
public:
float get_value(const game::penguin& game, uint8_t move) const;
int get_count(const game::penguin& game, uint8_t move) const;
};
};
#endif
...@@ -10,67 +10,75 @@ ...@@ -10,67 +10,75 @@
#include <iomanip> #include <iomanip>
#include <set> #include <set>
#include <fstream> #include <fstream>
#include "heuristic.hpp"
#include "config.hpp"
namespace mcts namespace mcts
{ {
template <typename Game> template <typename Game>
class test_mcts_two_players class test_mcts_two_players
{ {
openings openings_; openings openings_;
void play(Game g); void play(Game g, const heuristic<Game>& h);
void self_play(Game g); void self_play(Game g);
void self_play(Game g, int n, bool with_openings = false); void self_play(Game g, const heuristic<Game>& h1 = zero_knowledge<Game>(), const heuristic<Game>& h2 = zero_knowledge<Game>());
void self_play_learn_openings(Game g, int n); void self_play_learn_openings(Game g, int n);
void test_openings(Game g, int nb_learning, int nb_testing); void test_openings(Game g, int nb_learning, int nb_testing);
int select_move(Game& game); int select_move(Game& game);
public: public:
test_mcts_two_players(const Game& g); test_mcts_two_players(const Game& g, const heuristic<Game>& h1 = zero_knowledge<Game>(), const heuristic<Game>& h2 = zero_knowledge<Game>());
}; };
template <typename Game> template <typename Game>
test_mcts_two_players<Game>::test_mcts_two_players(const Game& g) : openings_(g) test_mcts_two_players<Game>::test_mcts_two_players(const Game& g, const heuristic<Game>& h, const heuristic<Game>& h2) : openings_(g)
{ {
//self_play(g, 1000); game::config& config = game::config::get_config();
play(g); if(config.is_ai_vs_ai())
//test_openings(g, 10000, 1000); {
} self_play(g, h,h2);
}
else
{
play(g, h);
}
}
template <typename Game> template <typename Game>
void run_test_mcts_two_players(const Game& g) void run_test_mcts_two_players(const Game& g, const heuristic<Game>& h = zero_knowledge<Game>(),const heuristic<Game>& h2 = zero_knowledge<Game>())
{ {
test_mcts_two_players<Game>{g}; test_mcts_two_players<Game> {g, h, h2};
} }
template <typename Game> template <typename Game>
void test_mcts_two_players<Game>::test_openings(Game g, int nb_learning, int nb_testing) void test_mcts_two_players<Game>::test_openings(Game g, int nb_learning, int nb_testing)
{ {
// self_play(g, nb_testing); //self_play(g, nb_testing);
self_play_learn_openings(g, nb_learning); self_play_learn_openings(g, nb_learning);
self_play(g, nb_testing, true); self_play(g, nb_testing, true);
} }
template <typename Game> template <typename Game>
int test_mcts_two_players<Game>::select_move(Game& game) int test_mcts_two_players<Game>::select_move(Game& game)
{ {
std::cout << game.player_to_string(game.current_player()) << " move: "; std::cout << game.player_to_string(game.current_player()) << " move: ";
std::map<std::string, int> m; std::map<std::string, int> m;
for (int i = 0; i < game.number_of_moves(); ++i) for (int i = 0; i < game.number_of_moves(); ++i)
{ {
m[game.move_to_string(i)] = i; m[game.move_to_string(i)] = i;
} }
std::string move; std::string move;
getline(std::cin, move); getline(std::cin, move);
game.play(m[move]); game.play(m[move]);
return m[move]; return m[move];
} }
template <typename Game> template <typename Game>
void test_mcts_two_players<Game>::play(Game g) void test_mcts_two_players<Game>::play(Game g, const heuristic<Game>& h)
{ {
// ProfilerStart("theturk.prof"); // ProfilerStart("theturk.prof");
auto the_turk = make_mcts_two_players(g, MCTS_TURN_TIME, 0.4, 8); auto the_turk = make_mcts_two_players(g, MCTS_TURN_TIME, 0.4, 8, h);
std::cout << "play one game" << std::endl; std::cout << "play one game" << std::endl;
std::cout << "who's first? (h)uman/(c)omputer "; std::cout << "who's first? (h)uman/(c)omputer ";
std::string ans; std::string ans;
...@@ -78,41 +86,41 @@ namespace mcts ...@@ -78,41 +86,41 @@ namespace mcts
std::cout << g.to_string() << std::endl; std::cout << g.to_string() << std::endl;
int human_last_move = -1, computer_last_move = -1; int human_last_move = -1, computer_last_move = -1;
while (!g.end_of_game()) while (!g.end_of_game())
{ {
if ((ans == "h" && g.current_player() == 0) || (ans == "c" && g.current_player() == 1)) if ((ans == "h" && g.current_player() == 0) || (ans == "c" && g.current_player() == 1))
{ {
human_last_move = select_move(g); human_last_move = select_move(g);
} }
else else
{ {
if (human_last_move != -1 && computer_last_move != -1) if (human_last_move != -1 && computer_last_move != -1)
{ {
the_turk.last_moves(computer_last_move, human_last_move); the_turk.last_moves(computer_last_move, human_last_move);
} }
uint16_t move = the_turk.select_move(); uint16_t move = the_turk.select_move();
computer_last_move = move; computer_last_move = move;
std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl; std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl;
g.play(move); g.play(move);
} }
std::cout << g << std::endl; std::cout << g << std::endl;
} }
if (g.won(0)) std::cout << g.player_to_string(0) << " won"; if (g.won(0)) std::cout << g.player_to_string(0) << " won";
else if (g.won(1)) std::cout << g.player_to_string(1) << " won"; else if (g.won(1)) std::cout << g.player_to_string(1) << " won";
else std::cout << "draw"; else std::cout << "draw";
std::cout << std::endl; std::cout << std::endl;
// ProfilerStop(); // ProfilerStop();
} }
template <typename Game> template <typename Game>
void test_mcts_two_players<Game>::self_play_learn_openings(Game g, int n) void test_mcts_two_players<Game>::self_play_learn_openings(Game g, int n)
{ {
std::vector<uint16_t> moves(200); std::vector<uint16_t> moves(200);
auto state = g.get_state(); auto state = g.get_state();
auto the_turk_1 = make_mcts_two_players(g, 1000, 0.6, 2); auto the_turk_1 = make_mcts_two_players(g, 1000, 0.6, 2);
auto the_turk_2 = make_mcts_two_players(g, 1000, 0.6, 2); auto the_turk_2 = make_mcts_two_players(g, 1000, 0.6, 2);
std::map<std::set<int>, std::pair<std::uint32_t, double>> learning_examples; std::map<std::set<int>, std::pair<std::uint32_t, double>> learning_examples;
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
std::cout << i << std::endl; std::cout << i << std::endl;
std::cout << openings_ << std::endl << std::endl; std::cout << openings_ << std::endl << std::endl;
moves.clear(); moves.clear();
...@@ -124,144 +132,148 @@ namespace mcts ...@@ -124,144 +132,148 @@ namespace mcts
int the_turk_1_last_move = -1, the_turk_2_last_move = -1; int the_turk_1_last_move = -1, the_turk_2_last_move = -1;
int k = 0; int k = 0;
while (!g.end_of_game()) while (!g.end_of_game())
{ {
if (k == 1) the_turk_2.last_move(the_turk_1_last_move); if (k == 1) the_turk_2.last_move(the_turk_1_last_move);
if (k % 2 == 0) if (k % 2 == 0)
{ {
if (the_turk_2_last_move != -1) if (the_turk_2_last_move != -1)
{ {
the_turk_1.last_moves(the_turk_1_last_move, the_turk_2_last_move); the_turk_1.last_moves(the_turk_1_last_move, the_turk_2_last_move);
} }
std::uint16_t move = the_turk_1.select_move(); std::uint16_t move = the_turk_1.select_move();
moves.push_back(move); moves.push_back(move);
the_turk_1_last_move = move; the_turk_1_last_move = move;
g.play(move); g.play(move);
} }
else else
{ {
if (the_turk_2_last_move != -1) if (the_turk_2_last_move != -1)
{ {
the_turk_2.last_moves(the_turk_2_last_move, the_turk_1_last_move); the_turk_2.last_moves(the_turk_2_last_move, the_turk_1_last_move);
} }
std::uint16_t move = the_turk_2.select_move(); std::uint16_t move = the_turk_2.select_move();
moves.push_back(move); moves.push_back(move);
the_turk_2_last_move = move; the_turk_2_last_move = move;
g.play(move); g.play(move);
} }
++k; ++k;
} }
std::cout << g.to_string() << std::endl; std::cout << g.to_string() << std::endl;
int v = g.value(0); int v = g.value(0);
std::cout << "value for first player " << v << std::endl; std::cout << "value for first player " << v << std::endl;
g.set_state(state); g.set_state(state);
openings_.update(g, moves, v); openings_.update(g, moves, v);
g.set_state(state); g.set_state(state);
for (std::uint16_t m : moves) for (std::uint16_t m : moves)
{ {
g.play(m); g.play(m);
v = -v; v = -v;
std::set<int> input_vector = std::move(g.to_input_vector()); std::set<int> input_vector = std::move(g.to_input_vector());
auto it = learning_examples.find(input_vector); auto it = learning_examples.find(input_vector);
if (it == learning_examples.end()) if (it == learning_examples.end())
{ {
learning_examples[input_vector] = std::make_pair(1, v); learning_examples[input_vector] = std::make_pair(1, v);
} }
else else
{ {
it->second.second = (it->second.second * it->second.first + v) / (it->second.first + 1); it->second.second = (it->second.second * it->second.first + v) / (it->second.first + 1);
it->second.first += 1; it->second.first += 1;
} }
} }
} }
std::cout << "number of learning examples: " << learning_examples.size() << std::endl; std::cout << "number of learning examples: " << learning_examples.size() << std::endl;
std::ofstream output("learning_examples.txt"); std::ofstream output("learning_examples.txt");
for (const auto& example : learning_examples) for (const auto& example : learning_examples)
{ {
output << example.second.second; output << example.second.second;
for (int index : example.first) for (int index : example.first)
{ {
output << " " << index << ":" << 1; output << " " << index << ":" << 1;
} }
output << std::endl; output << std::endl;
} }
output.close(); output.close();
} }
template <typename Game> template <typename Game>
void test_mcts_two_players<Game>::self_play(Game g, int n, bool with_openings) void test_mcts_two_players<Game>::self_play(Game g, const heuristic<Game>& h1, const heuristic<Game>& h2)
{ {
game::config& c = game::config::get_config();
auto state = g.get_state(); auto state = g.get_state();
auto the_turk_v1 = make_mcts_two_players(g, 1000, 0.6, 2); auto the_turk_v1 = make_mcts_two_players(g, c.get_think_time(), 0.6, 2, h1);
auto the_turk_v2 = make_mcts_two_players(g, 1000, 0.6, 2); auto the_turk_v2 = make_mcts_two_players(g, c.get_think_time(), 0.6, 2, h2);
int nb_win_v1 = 0, nb_win_v2 = 0, nb_draw = 0; int nb_win_v1 = 0, nb_win_v2 = 0, nb_draw = 0;
for (int i = 0; i < n; ++i) for (unsigned int i = 0; i < c.get_game_count(); ++i)
{ {
std::cout << i << std::endl; std::cout << i << std::endl;
g.set_state(state); g.set_state(state);
the_turk_v1.reset(); the_turk_v1.reset();
the_turk_v2.reset(); the_turk_v2.reset();
if (with_openings) the_turk_v2.init_with_openings(openings_);
int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1; int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
int k = 0; int k = 0;
while (!g.end_of_game()) while (!g.end_of_game())
{ {
if (with_openings && k == 1 && i % 2 == 0) the_turk_v2.last_move(the_turk_v1_last_move);
++k;
++k;
// cout << c4 << endl; // cout << c4 << endl;
if ((i % 2 == 0 && g.current_player() == 0) || (i % 2 == 1 && g.current_player() == 1)) if ((i % 2 == 0 && g.current_player() == 0) || (i % 2 == 1 && g.current_player() == 1))
{ {
if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1) if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
{ {
the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move); the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
} }
std::uint16_t move = the_turk_v1.select_move(); std::uint16_t move = the_turk_v1.select_move();
the_turk_v1_last_move = move; the_turk_v1_last_move = move;
g.play(move); g.play(move);
} }
else else
{ {
if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1) if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
{ {
the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move); the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
} }
std::uint16_t move = the_turk_v2.select_move(); std::uint16_t move = the_turk_v2.select_move();
the_turk_v2_last_move = move; the_turk_v2_last_move = move;
play(move); g.play(move);
} }
} if(c.should_send_game_to_gui())
std::cout << g;
}
if (g.won(0)) if (g.won(0))
{ {
if (i % 2 == 0) if (i % 2 == 0)
{ {
/*cout << "v1 won" << endl;*/ ++nb_win_v1; /*cout << "v1 won" << endl;*/ ++nb_win_v1;
} }
else else
{ {
/*cout << "v2 won" << endl;*/ ++nb_win_v2; /*cout << "v2 won" << endl;*/ ++nb_win_v2;
} }
} }
else if (g.won(1)) else if (g.won(1))
{ {
if (i % 2 == 0) if (i % 2 == 0)
{ {
/*cout << "v2 won" << endl;*/ ++nb_win_v2; /*cout << "v2 won" << endl;*/ ++nb_win_v2;
} }
else else
{ {
/*cout << "v1 won" << endl;*/ ++nb_win_v1; /*cout << "v1 won" << endl;*/ ++nb_win_v1;
} }
} }
else else
{ {
/*cout << "draw" << endl;*/ ++nb_draw; /*cout << "draw" << endl;*/ ++nb_draw;
} }
std::cout << std::setw(10) << "v1 nb wins: " << nb_win_v1 << " v2 nb wins: " << nb_win_v2 << " nb draws: " << nb_draw << std::endl; std::cout << std::setw(10) << "v1 nb wins: " << nb_win_v1 << " v2 nb wins: " << nb_win_v2 << " nb draws: " << nb_draw << std::endl;
} }
} }
template <typename Game> template <typename Game>
void test_mcts_two_players<Game>::self_play(Game g) void test_mcts_two_players<Game>::self_play(Game g)
{ {
auto the_turk_v1 = make_mcts_two_players(g, 1000, 1.2, 2); auto the_turk_v1 = make_mcts_two_players(g, 1000, 1.2, 2);
auto the_turk_v2 = make_mcts_two_players(g, 1000, 1.2, 2); auto the_turk_v2 = make_mcts_two_players(g, 1000, 1.2, 2);
std::cout << "play one game" << std::endl; std::cout << "play one game" << std::endl;
...@@ -271,36 +283,36 @@ namespace mcts ...@@ -271,36 +283,36 @@ namespace mcts
std::cout << g << std::endl; std::cout << g << std::endl;
int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1; int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
while (!g.end_of_game()) while (!g.end_of_game())
{ {
if ((ans == "v1" && g.current_player() == 0) || (ans == "v2" && g.current_player() == 1)) if ((ans == "v1" && g.current_player() == 0) || (ans == "v2" && g.current_player() == 1))
{ {
if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1) if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
{ {
the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move); the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
} }
std::uint16_t move = the_turk_v1.select_move(); std::uint16_t move = the_turk_v1.select_move();
the_turk_v1_last_move = move; the_turk_v1_last_move = move;
std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl; std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl;
g.play(move); g.play(move);
} }
else else
{ {
if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1) if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
{ {
the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move); the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
} }
std::uint16_t move = the_turk_v2.select_move(); std::uint16_t move = the_turk_v2.select_move();
the_turk_v2_last_move = move; the_turk_v2_last_move = move;
std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl; std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl;
g.play(move); g.play(move);
} }
std::cout << g << std::endl; std::cout << g << std::endl;
} }
if (g.won(0)) std::cout << g.player_to_string(0) << " won"; if (g.won(0)) std::cout << g.player_to_string(0) << " won";
else if (g.won(1)) std::cout << g.player_to_string(1) << " won"; else if (g.won(1)) std::cout << g.player_to_string(1) << " won";
else std::cout << "draw"; else std::cout << "draw";
std::cout << std::endl; std::cout << std::endl;
} }
} }
......
...@@ -35,7 +35,7 @@ AIInclude=-I $(AISRC)/game -I $(AISRC)/util -I $(AISRC)/monte_carlo -I $(AISRC)/ ...@@ -35,7 +35,7 @@ AIInclude=-I $(AISRC)/game -I $(AISRC)/util -I $(AISRC)/monte_carlo -I $(AISRC)/
# Cpp source files # Cpp source files
AISourceFile = omp_util.cpp fast_log.cpp display_node.cpp penguin.cpp test_two_players_game.cpp monte_carlo.cpp \ AISourceFile = omp_util.cpp fast_log.cpp display_node.cpp penguin.cpp test_two_players_game.cpp monte_carlo.cpp \
test_fast_log.cpp statistics.cpp node.cpp allocator.cpp test_allocator.cpp openings.cpp mcts_two_players.cpp \ test_fast_log.cpp statistics.cpp node.cpp allocator.cpp test_allocator.cpp openings.cpp mcts_two_players.cpp \
test_mcts_two_players.cpp bits.cpp test_bits.cpp main.cpp test_mcts_two_players.cpp bits.cpp test_bits.cpp penguin_heuristic.cpp movement_freedom_heuristic.cpp main.cpp config.cpp
# Directories in which make will search for files # Directories in which make will search for files
vpath %.cpp $(AISRC)/game $(AISRC)/main $(AISRC)/util $(AISRC)/monte_carlo $(AISRC)/mcts $(AISRC)/gdl vpath %.cpp $(AISRC)/game $(AISRC)/main $(AISRC)/util $(AISRC)/monte_carlo $(AISRC)/mcts $(AISRC)/gdl
# Flags passed to the compiler # Flags passed to the compiler
......