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
#ifndef __MORPION_HPP__
#define __MORPION_HPP__
#include "game.hpp"
#include <random>
#include <array>
#include <iostream>
#include <memory>
namespace game
{
struct morpion_state
{
uint16_t cross_bitboard = 0; //bitboard with the played moves of the cross
uint16_t circle_bitboard = 0; //bitboard with the played moves of the circle
uint8_t total_moves = 0; //Total played moves (<= 9)
uint64_t possible_moves = 0x876543210; //List of possible moves left
bool first_player_win = false; //First player is always the cross
bool second_player_win = false; //Second player is always the circle
};
class morpion : public game<morpion_state>
{
public:
morpion();
morpion(const morpion& mor) = default;
morpion& operator=(const morpion& mor) = default;
bool end_of_game() const; //Is the game ended? (draw or won)
int value(std::uint8_t player) const; //Returns if the player win, loose or nothing
bool won(std::uint8_t player) const;
bool lost(std::uint8_t player) const;
bool draw(std::uint8_t player) const;
uint8_t current_player() const; //The player that has to play next (at the beginning, the first player)
std::uint16_t number_of_moves() const; //Number of moves that you can play
std::uint16_t number_moves_played() const; //Number of moves played until now
void play(std::uint16_t m); //Play the move m (updates the state). m is the position on the board of where you want to play
void undo(std::uint16_t m) {}
std::string player_to_string(std::uint8_t player) const; //String representation of a player
std::string move_to_string(std::uint16_t m) const; //String representation of a move (for example, A1)
std::string to_string() const; //String representation of the entire game
std::set<int> to_input_vector() const;
void from_input_vector(const std::set<int>& input);
morpion_state get_state(); //Return the state
void set_state(const morpion_state& state); //Replace the current state with the one passed as a parameter
std::shared_ptr<game<morpion_state>> do_copy() const;
std::uint64_t hash(std::uint16_t m) const;
std::uint64_t hash() const;
private:
inline void update_win(); //Check if someone won and update the state
inline bool has_won(uint16_t bitboard); //Check if the player whose bitboard was passed as a param has won
inline bool get(uint16_t bitboard, uint8_t i, uint8_t j) const; //Get a case of the board
inline void update_moves(); //Update the list of all possible moves
const uint8_t CROSS = 0;
const uint8_t CIRCLE = 1;
morpion_state state;
//WIN CONSTANTS
const uint16_t ROW0_MASK = 504;
const uint16_t ROW1_MASK = 455;
const uint16_t ROW2_MASK = 63;
const uint16_t COL0_MASK = 438;
const uint16_t COL1_MASK = 365;
const uint16_t COL2_MASK = 219;
const uint16_t DIA0_MASK = 238;
const uint16_t DIA1_MASK = 427;
const uint16_t ALL_ONES = 511;
static std::vector<std::vector<uint64_t>> cross_hash_values;
static std::vector<std::vector<uint64_t>> circle_hash_values;
};
std::ostream& operator<<(std::ostream& os, const morpion& mor);
}
#endif
#include "connect4.hpp"
#include "test_connect4.hpp"
#include <iostream>
#include <map>
using namespace std;
namespace game
{
test_connect4::test_connect4()
{
playout();
play();
}
void test_connect4::playout()
{
mt19937 mt;
connect4 c4;
cout << "playout" << endl;
for (int i = 0; i < 100; ++i)
{
uint8_t player = c4.current_player();
auto state = c4.get_state();
c4.playout(mt);
cout << "value: " << c4.value(player) << endl << c4 << endl;
c4.set_state(state);
string wait;
getline(cin, wait);
}
}
void test_connect4::play()
{
connect4 c4;
int player = 0;
cout << "play one game" << endl;
while (!c4.end_of_game())
{
cout << c4 << endl;
cout << c4.player_to_string(player) << " move: ";
map<string, int> m;
for (int i = 0; i < c4.number_of_moves(); ++i)
{
m[c4.move_to_string(i)] = i;
}
string move;
cin >> move;
c4.play(m[move]);
player = 1 - player;
}
cout << c4 << endl;
if (c4.value(0) == 1) cout << c4.player_to_string(0) << " won";
else if (c4.value(1) == 1) cout << c4.player_to_string(1) << " won";
else cout << "draw";
cout << endl;
}
}
#ifndef __TEST_CONNECT4_HPP__
#define __TEST_CONNECT4_HPP__
namespace game
{
class test_connect4
{
void playout();
void play();
public:
test_connect4();
};
}
#endif
#include "test_connect4.hpp"
#include "connect4.hpp"
#include "morpion.hpp"
#include "penguin.hpp"
#include "test_two_players_game.hpp"
#include "test_monte_carlo.hpp"
#include "test_fast_log.hpp"
#include "test_allocator.hpp"
#include "test_mcts_two_players.hpp"
#include "test_minmax.hpp"
#include "test_bits.hpp"
#include "learning.hpp"
#include <omp.h>
using namespace std;
int main(int argc, char *argv[])
{
// game::test_connect4();
// util::test_fast_log(100000000);
// mcts::test_allocator(10, 2);
// omp_set_num_threads(8);
// game::run_test_two_players_game(game::connect4());
//mcts::run_test_mcts_two_players(game::connect4());
//game::run_test_two_players_game(game::morpion());
//mcts::run_test_mcts_two_players(game::morpion());
game::run_test_two_players_game(game::penguin());
//mcts::run_test_mcts_two_players(game::penguin());
// minmax::test_minmax();
//util::test_bits(200000000);
//game::connect4 c4;
// util::learning::display_file(c4, "learning_examples.txt");
return 0;
}
#include "connect4_heuristic.hpp"
namespace minmax
{
double connect4_heuristic::value(const connect4& c4) const
{
const connect4_state& state = c4.get_state();
return 0;
}
}
#ifndef __CONNECT4_HEURISTIC_HPP__
#define __CONNECT4_HEURISTIC_HPP__
#include <connect4.hpp>
namespace minmax
{
class connect4_heuristic : public heuristic<connect4>
{
double value(const connect4& c4) const;
};
}
#endif
#ifndef __HEURISTIC_HPP__
#define __HEURISTIC_HPP__
namespace minmax
{
template <typename Game>
class heuristic
{
public:
virtual double value(const Game& game) const = 0;
};
template <typename Game>
class null_heuristic : public heuristic<Game>
{
double value(const Game& game) const;
};
template <typename Game>
double null_heuristic<Game>::value(const Game& game) const
{
return 0;
}
}
#endif
#ifndef __MINMAX_HPP__
#define __MINMAX_HPP__
#include <chrono>
#include <vector>
#include "game.hpp"
#include "heuristic.hpp"
#include <iostream>
#include <limits>
namespace minmax
{
struct cannot_prove : std::exception
{
const char* what() const noexcept { return "cannot prove the game theoritical value"; }
};
template <typename Game>
class minmax
{
protected:
Game& game;
std::chrono::milliseconds milliseconds;
const heuristic<Game>& h;
std::vector<uint16_t> principal_variation;
std::chrono::steady_clock::time_point start;
public:
minmax(Game& game, uint32_t milliseconds, const heuristic<Game>& h = null_heuristic<Game>())
: game(game), milliseconds(milliseconds), h(h)
{
}
int prove();
double solve();
uint16_t select_move();
private:
long prove(int depth);
double solve(int depth);
};
template <typename Game>
minmax<Game> make_minmax(Game& game, uint32_t milliseconds, const heuristic<Game>& h = null_heuristic<Game>())
{
return minmax<Game>(game, milliseconds, h);
}
template <typename Game>
double minmax<Game>::solve()
{
return 0;
}
template <typename Game>
double minmax<Game>::solve(int depth)
{
return 0;
}
template <typename Game>
uint16_t minmax<Game>::select_move()
{
return 0;
}
const long UNKNOWN = std::numeric_limits<long>::max();
template <typename Game>
int minmax<Game>::prove()
{
start = std::chrono::steady_clock::now();
uint16_t nb_moves = game.number_of_moves();
long value[nb_moves];
std::fill_n(value, nb_moves, UNKNOWN);
int depth = 3;
auto state = game.get_state();
try
{
int nb_proved_moves = 0, nb_draws = 0;
while (true)
{
for (uint16_t move = 0; move < nb_moves; ++move)
{
if (value[move] != UNKNOWN) continue;
game.play(move);
value[move] = prove(depth);
game.set_state(state);
if (value[move] == -1) return 1;
if (value[move] == 0) ++nb_draws;
if (value[move] != UNKNOWN) ++nb_proved_moves;
}
if (nb_proved_moves == nb_moves)
{
if (nb_draws != 0) return 0;
return -1;
}
++depth;
}
}
catch (cannot_prove fail)
{
game.set_state(state);
}
throw cannot_prove();
}
template <typename Game>
long minmax<Game>::prove(int depth)
{
if (game.end_of_game()) return game.value(game.current_player());
if (depth == 0) return UNKNOWN;
if ((depth & 3) && std::chrono::steady_clock::now() >= start + milliseconds) throw cannot_prove();
uint16_t nb_moves = game.number_of_moves();
auto state = game.get_state();
int nb_proved_moves = 0, nb_draws = 0;
for (uint16_t move = 0; move < nb_moves; ++move)
{
game.play(move);
long v = prove(depth - 1);
game.set_state(state);
if (v == -1) return 1;
if (v == 0) ++nb_draws;
if (v != UNKNOWN) ++nb_proved_moves;
}
if (nb_proved_moves == nb_moves)
{
if (nb_draws != 0) return 0;
return -1;
}
return UNKNOWN;
}
}
#endif
#include "minmax.hpp"
#include "test_minmax.hpp"
#include "connect4.hpp"
#include <iostream>
#include <iomanip>
#include <map>
using namespace std;
using namespace game;
namespace minmax
{
test_minmax::test_minmax()
{
play();
}
template <typename Game>
int test_minmax::select_move(Game& game)
{
cout << game.player_to_string(game.current_player()) << " move: ";
map<string, int> m;
for (int i = 0; i < game.number_of_moves(); ++i)
{
m[game.move_to_string(i)] = i;
}
string move;
getline(cin, move);
game.play(m[move]);
return m[move];
}
void test_minmax::play()
{
connect4 c4;
auto minimax = make_minmax(c4, 2000);
cout << "play one game" << endl;
cout << c4 << endl;
while (!c4.end_of_game())
{
cout << "try to prove? (y/n)" << endl;
string ans;
getline(cin, ans);
if (ans == "y")
{
try
{
int v = minimax.prove();
if (v == 1) cout << "won position" << endl;
if (v == -1) cout << "lost position" << endl;
if (v == 0) cout << "drawn position" << endl;
}
catch (exception fail)
{
cout << "unable to prove" << endl;
}
}
select_move(c4);
cout << c4 << endl;
}
if (c4.value(0) == 1) cout << c4.player_to_string(0) << " won";
else if (c4.value(1) == 1) cout << c4.player_to_string(1) << " won";
else cout << "draw";
cout << endl;
}
}
#ifndef __TEST_MINMAX_HPP__
#define __TEST_MINMAX_HPP__
namespace minmax
{
class test_minmax
{
void play();
template <typename Game>
int select_move(Game& game);
public:
test_minmax();
};
}
#endif
#!/usr/bin/env python3
#-*- encoding: utf-8 -*-
import drawState
import subprocess
import json
import os
if __name__ == "__main__":
programname = os.path.join(os.path.dirname(__file__), "../bin/theturk")
program = subprocess.Popen(programname, stdin = subprocess.PIPE, stdout = subprocess.PIPE, universal_newlines = True, bufsize = 1)
try:
while True:
#READ
readloop = True
comments = []
json_data = []
brackets_count = 0
while readloop:
line = program.stdout.readline()
#print(line)
if line.startswith("{"): #in json or entering json
brackets_count += 1
if brackets_count > 0: #We are in the middle of json data
json_data.append(line)
else:
comments.append(line)
if line.startswith("}"):
brackets_count -= 1
if line == "\n":
readloop = False
#PRINT STATE
print("Comments: {}".format(''.join(comments)))
state = json.loads(''.join(json_data))
drawState.drawBitboard(state["bitboards"]["onefish"],state["bitboards"]["twofish"],state["bitboards"]["threefish"])
print("Red penguins (Red score: {}, Total moves: {} [0..{}])".format(state["score"]["red"], state["nb_moves"]["red"], state["nb_moves"]["red"]-1))
for i in range(4):
drawState.drawPenguin(state["penguins"]["red"][i])
print("Blue penguins (Blue score: {}, Total moves: {} [0..{}])".format(state["score"]["blue"], state["nb_moves"]["blue"], state["nb_moves"]["blue"] -1))
for i in range(4):
drawState.drawPenguin(state["penguins"]["blue"][i])
#PLAY NEXT MOVE
if state["current_player"] == "Red":
move = input("Enter Red move: ")
else:
move = input("Enter Blue move: ")
program.stdin.write(move+"\n")
program.stdin.flush()
except KeyboardInterrupt:
print("\nMay the fish be with you.")
finally:
program.kill()