Commit 9fcd01bc authored by Vivien Kraus's avatar Vivien Kraus

Merge branch '33-separate-mcts-simulation-from-expansion' into 'develop'

Resolve "Separate MCTS simulation from expansion"

Closes #33

See merge request gugurumbe/tarot!31
parents 45d4e675 6168376a
Pipeline #104888 passed with stages
in 4 minutes and 39 seconds
......@@ -38,3 +38,4 @@ include %reldir%/cairo/Makefile.am
include %reldir%/gtk/Makefile.am
include %reldir%/tree/Makefile.am
include %reldir%/mcts/Makefile.am
include %reldir%/simulation/Makefile.am
......@@ -1935,8 +1935,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
game_n_players (&(iterator->handle))
&& game_get_discard_according_to (&(iterator->handle),
game_get_dealt (&
(iterator->
handle)),
(iterator->handle)),
&cards) == 0)
|| game_get_discard (&(iterator->handle), &cards) == 0)
{
......
......@@ -33,6 +33,7 @@
#include <tarot/cli.h>
#include <tarot/xml.h>
#include <tarot/layout.h>
#include <tarot/simulation.h>
#include <tarot/mcts.h>
#ifdef __cplusplus
......
......@@ -31,6 +31,7 @@ lib_LTLIBRARIES += %reldir%/libtarot.la
%reldir%/cli/libtarot-cli.la \
%reldir%/xml/libtarot-xml.la \
%reldir%/layout/libtarot-layout.la \
%reldir%/simulation/libtarot-simulation.la \
%reldir%/mcts/libtarot-mcts.la \
lib-library/libgnulibrary.la
......
......@@ -65,10 +65,8 @@ extern "C"
struct yarrow256_ctx *rng);
static int mcts_expand (TarotMcts * mcts, TarotMctsTreeIterator * node,
TarotGameEvent * event, TarotPlayer myself);
/* local_event is just an allocated event */
static int mcts_simulate (struct yarrow256_ctx *rng, TarotGame * game,
TarotGameEvent * local_event, size_t n_players,
int *score);
size_t n_players, int *score);
static void mcts_backpropagate (TarotMcts * mcts,
TarotMctsTreeIterator node,
size_t n_players, const int *score);
......
......@@ -21,6 +21,7 @@
#include <config.h>
#include <tarot/mcts_private.h>
#include <tarot/mcts_tree_private.h>
#include <tarot/simulation.h>
/* #define DEBUG_MCTS */
......@@ -187,8 +188,7 @@ one_iteration (TarotMcts * mcts, size_t n_simulations,
}
/* SIMULATE */
assert (tarot_game_n_players (game) <= 5);
if (mcts_simulate (rng, game, next, tarot_game_n_players (game), score) !=
0)
if (mcts_simulate (rng, game, tarot_game_n_players (game), score) != 0)
{
/* Simulation gives a petit sec arriving at the deal phase */
DEBUG (stderr, "%s:%d: Could not simulate\n", __FILE__, __LINE__);
......@@ -279,11 +279,16 @@ search_best_select (const TarotMcts * mcts, TarotMctsTreeIterator node,
int right_ok = (right != TREE_NULL);
size_t this_n_simulations = n_simulations;
const TarotMctsNode *node_data = tarot_mcts_tree_get (mcts->tree, node);
double value = compute_score (node_data, n_simulations);
if (value > *best_value)
double value;
if (node_data->event != NULL
&& tarot_game_event_type (node_data->event) != TAROT_DOG_EVENT)
{
*best_value = value;
*best = node;
value = compute_score (node_data, n_simulations);
if (value > *best_value)
{
*best_value = value;
*best = node;
}
}
this_n_simulations = node_data->n_simulations;
if (left_ok)
......@@ -730,8 +735,6 @@ mcts_next_move (const TarotGame * game, TarotGameEvent * event,
return ret;
}
static inline int
mcts_expand (TarotMcts * mcts, TarotMctsTreeIterator * node,
TarotGameEvent * event, TarotPlayer next_player)
......@@ -781,28 +784,13 @@ mcts_expand (TarotMcts * mcts, TarotMctsTreeIterator * node,
}
static inline int
mcts_simulate (struct yarrow256_ctx *rng, TarotGame * game,
TarotGameEvent * event, size_t n_players, int *score)
mcts_simulate (struct yarrow256_ctx *rng, TarotGame * game, size_t n_players,
int *score)
{
TarotPlayer p;
while (tarot_game_step (game) != TAROT_END)
if (tarot_simulate (rng, game) != 0)
{
if (mcts_next_move (game, event, rng) != 0)
{
DEBUG (stderr,
"%s:%d: could not simulate, because could not select the next move\n",
__FILE__, __LINE__);
return 1;
}
if (tarot_game_add_event (game, event) != 0)
{
DEBUG (stderr,
"%s:%d: could not simulate, because could not add the selected event in: %s\n",
__FILE__, __LINE__, tarot_game_save_to_xml (game));
assert (tarot_game_event_type (event) == TAROT_DEAL_EVENT
|| tarot_game_event_type (event) == TAROT_DEAL_ALL_EVENT);
return 1;
}
assert (0);
}
for (p = 0; p < n_players; p++)
{
......
# Makefile.am
#
# Copyright (C) 2018 Vivien Kraus <vivien@planete-kraus.eu>
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
include %reldir%/libtarot-simulation.am
AM_CPPFLAGS += -I $(srcdir)/%reldir% -I %reldir%
# libtarot-simulation.am
#
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu>
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
noinst_LTLIBRARIES += %reldir%/libtarot-simulation.la
tarotinclude_HEADERS += %reldir%/tarot/simulation.h
%canon_reldir%_libtarot_simulation_la_SOURCES = \
%reldir%/simulation.c \
%reldir%/tarot/simulation.h
%canon_reldir%_libtarot_simulation_la_CFLAGS = \
$(AM_CFLAGS) $(NETTLE_CFLAGS)
%canon_reldir%_libtarot_simulation_la_LDFLAGS = \
-no-undefined $(AM_LDADD) $(NETTLE_LIBS)
INDENTED += $(%canon_reldir%_libtarot_simulation_la_SOURCES)
ENUM_HEADER_FILES += %reldir%/tarot/simulation.h
INTROSPECTED_SOURCES += %reldir%/simulation.c
/**
* file simulation.c
*
* Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu>
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <tarot/simulation.h>
#include <nettle/yarrow.h>
#include <tarot/game.h>
#include <assert.h>
#include <stdlib.h>
static int
select_next_move_deal (size_t n_players, TarotGameEvent * event,
struct yarrow256_ctx *rng)
{
char deal_seed[16];
size_t sz = sizeof (deal_seed);
yarrow256_random (rng, sz, (void *) deal_seed);
return tarot_game_event_set_deal_all_random (event, n_players, sz,
(void *) deal_seed);
}
static void
select_next_move_bid (TarotGameEvent * event, TarotBid mini,
struct yarrow256_ctx *rng)
{
unsigned char random_byte;
double random_value;
yarrow256_random (rng, 1, &random_byte);
random_value = random_byte / 256.0;
if (random_value <= 0.5)
{
if (tarot_game_event_set_bid (event, TAROT_PASS) != 0)
{
assert (0);
}
}
else
{
/* Outbid */
if (tarot_game_event_set_bid (event, mini) != 0)
{
assert (0);
}
}
}
static void
select_next_move_decl (TarotGameEvent * event, int allowed,
struct yarrow256_ctx *rng)
{
(void) allowed;
(void) rng;
if (tarot_game_event_set_decl (event, 0) != 0)
{
assert (0);
}
}
static void
select_next_move_call (TarotGameEvent * event, TarotNumber mini_face,
struct yarrow256_ctx *rng)
{
TarotNumber face;
static TarotSuit suits[4] =
{ TAROT_HEARTS, TAROT_CLUBS, TAROT_DIAMONDS, TAROT_SPADES };
TarotSuit suit;
TarotCard call;
unsigned int random_value;
if (mini_face == TAROT_KING)
{
face = TAROT_KING;
}
else
{
yarrow256_random (rng, sizeof (random_value), (void *) &random_value);
face = mini_face + random_value % (TAROT_KING - mini_face + 1);
}
yarrow256_random (rng, sizeof (random_value), (void *) &random_value);
suit = suits[random_value % 4];
if (tarot_of (face, suit, &call) != 0)
{
assert (0);
}
if (tarot_game_event_set_call (event, call) != 0)
{
assert (0);
}
}
static void
select_next_move_dog (TarotGameEvent * event, const TarotGame * imputed)
{
TarotCardArray *dog = tarot_card_array_alloc ();
if (dog == NULL
|| !tarot_game_can_autoreveal (imputed, dog)
|| tarot_game_event_set_dog (event, dog) != 0)
{
abort ();
}
tarot_card_array_free (dog);
}
static void
shuffle (TarotCardArray * set, struct yarrow256_ctx *rng)
{
size_t random_value;
size_t i, n = tarot_card_array_size (set);
for (i = 1; i < n; i++)
{
size_t j;
TarotCard hold;
yarrow256_random (rng, sizeof (random_value), (void *) &random_value);
j = random_value % (i + 1);
hold = tarot_card_array_get (set, i);
tarot_card_array_set (set, i, tarot_card_array_get (set, j));
tarot_card_array_set (set, j, hold);
}
}
static void
sample (TarotCardArray * set, size_t n, struct yarrow256_ctx *rng,
size_t * n_selected, int *selected)
{
size_t i, n_samplable = tarot_card_array_size (set);
shuffle (set, rng);
for (i = 0; i < n_samplable; i++)
{
if (*n_selected < n)
{
TarotCard c = tarot_card_array_get (set, i);
if (selected[c] == 0)
{
selected[c] = 1;
*n_selected = *n_selected + 1;
}
}
}
}
static void
select_next_move_discard (TarotGameEvent * event, size_t n,
TarotCardArray * prio, TarotCardArray * additional,
struct yarrow256_ctx *rng)
{
int selected[78];
TarotCardArray *discard = tarot_card_array_alloc ();
size_t n_selected, i;
if (discard == NULL || tarot_card_array_resize (discard, n) != 0)
{
abort ();
}
for (i = 0; i < 78; i++)
{
selected[i] = 0;
}
n_selected = 0;
sample (prio, n, rng, &n_selected, selected);
if (n_selected < n)
{
sample (additional, n - n_selected, rng, &n_selected, selected);
}
assert (n_selected == n);
n_selected = 0;
for (i = 0; i < 78; i++)
{
if (selected[i])
{
tarot_card_array_set (discard, n_selected++, i);
}
}
assert (n_selected == n);
if (tarot_game_event_set_discard (event, discard) != 0)
{
abort ();
}
tarot_card_array_free (discard);
}
static void
select_next_move_card (TarotGameEvent * event,
const TarotCardArray * playable,
struct yarrow256_ctx *rng)
{
size_t i, n_playable = tarot_card_array_size (playable);
size_t random_value;
yarrow256_random (rng, sizeof (random_value), (void *) &random_value);
i = random_value % n_playable;
if (tarot_game_event_set_card (event, tarot_card_array_get (playable, i)) !=
0)
{
abort ();
}
}
static inline int
mcts_next_move (const TarotGame * game, TarotGameEvent * event,
struct yarrow256_ctx *rng)
{
TarotBid mini_bid;
int decl_allowed;
TarotPlayer next;
TarotNumber mini_face;
TarotCardArray *prio = tarot_card_array_alloc ();
TarotCardArray *additional = tarot_card_array_alloc ();
TarotCardArray *playable = tarot_card_array_alloc ();
size_t n_cards;
int ret = 0;
if (prio == NULL || additional == NULL || playable == NULL
|| tarot_card_array_resize (prio, 78) != 0
|| tarot_card_array_resize (additional, 78) != 0
|| tarot_card_array_resize (playable, 78) != 0)
{
/* FIXME: Use stack-allocated vectors and tweak the card arrays */
abort ();
}
switch (tarot_game_step (game))
{
case TAROT_SETUP:
/* Since we have at least one event in the past, and we cannot
have two consecutive setup events, then this is not
possible */
assert (0);
break;
case TAROT_DEAL:
select_next_move_deal (tarot_game_n_players (game), event, rng);
if (!tarot_game_check_event (game, event))
{
/* Petit sec */
ret = 1;
}
break;
case TAROT_BIDS:
if (tarot_game_hint_bid (game, &next, &mini_bid) != 0)
{
assert (0);
}
select_next_move_bid (event, mini_bid, rng);
break;
case TAROT_DECLS:
if (tarot_game_hint_decl (game, &next, &decl_allowed) != 0)
{
assert (0);
}
select_next_move_decl (event, decl_allowed, rng);
break;
case TAROT_CALL:
if (tarot_game_hint_call (game, &next, &mini_face) != 0)
{
assert (0);
}
select_next_move_call (event, mini_face, rng);
break;
case TAROT_DOG:
select_next_move_dog (event, game);
break;
case TAROT_DISCARD:
if (tarot_game_hint_discard (game, &next, &n_cards, prio, additional) !=
0)
{
abort ();
}
select_next_move_discard (event, n_cards, prio, additional, rng);
break;
case TAROT_TRICKS:
if (tarot_game_hint_card (game, &next, playable) != 0)
{
abort ();
}
select_next_move_card (event, playable, rng);
break;
case TAROT_END:
/* We don't select a move if we're at end */
assert (0);
break;
}
tarot_card_array_free (prio);
tarot_card_array_free (additional);
tarot_card_array_free (playable);
return ret;
}
int
tarot_simulate (struct yarrow256_ctx *prng, TarotGame * game)
{
int error = 0;
TarotGameEvent *event = tarot_game_event_alloc ();
if (event == NULL)
{
return 1;
}
while (tarot_game_step (game) != TAROT_END)
{
error = mcts_next_move (game, event, prng);
if (error != 0)
{
tarot_game_event_free (event);
return error;
}
if (tarot_game_add_event (game, event) != 0)
{
abort ();
}
}
tarot_game_event_free (event);
return error;
}
/* Local Variables: */
/* mode: c */
/* End: */
/**
* file simulation.h
*
* Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu>
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef H_TAROT_SIMULATION_INCLUDED
#define H_TAROT_SIMULATION_INCLUDED
#include <stddef.h>
#include <tarot/player.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
struct yarrow256_ctx;
struct TarotGame;
int tarot_simulate (struct yarrow256_ctx *prng, struct TarotGame *game);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* not H_TAROT_SIMULATION_INCLUDED */
/* Local Variables: */
/* mode: c */
/* End: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment