Commit ad0fdcf8 authored by Vivien Kraus's avatar Vivien Kraus
Browse files

Resolve "Set up the Monte Carlo Tree Search"

parent c206afd1
......@@ -756,6 +756,12 @@ cards.
[[file:tarot-figures/example.png]]
** Invoking tarot-render
#+texinfo: @include invoke-tarot-render-body.texi
* Generating a game with Monte Carlo Tree Search
The program =tarot-generate= generates a game in which all players
play with Monte Carlo Tree Search.
** Invoking tarot-generate
#+texinfo: @include invoke-tarot-generate-body.texi
* The libtarot API
In this section, we are going to describe the entrypoints of the
libtarot API.
......@@ -1321,8 +1327,9 @@ error code if /player/ has no bid yet.
Tarot.Player who;
open_row ();
for (who = 0; who < n_players; who++) {
Tarot.Bid bid;
bool has_bid = (game.get_bid (who, out bid) == 0);
Tarot.Bid bid = Tarot.Bid.DOUBLE_KEEP + 1;
bool has_bid = (game.get_n_bids () > who
&& game.get_bid (who, out bid) == 0);
if (who != 0) {
inter_cell ();
}
......@@ -1873,36 +1880,6 @@ on success, or an error code.
We use =autogen= to process the program options. There are only two of
them, since tarot is mainly an interactive program.
#+BEGIN_SRC conf :eval no :tangle ../src/tarot-opts.def
Autogen Definitions options;
prog-name = tarot;
prog-title = "The Amazing Rules Of TAROT";
long-opts;
gnu-usage; /* GNU style preferred to default */
config-header = "config.h";
include = "int tarot_run ();";
main = {
main-type = main;
main-text = "res = tarot_run ();";
};
flag = {
name = brief;
descrip = "Do not print the greeting";
disable = not;
doc = 'Do not print the greeting when starting the program.';
};
flag = {
name = batch;
value = b;
descrip = "Do not display the user interface";
disable = not;
doc = "Do not display the user interface. Prompt commands from the standard input.";
};
#+END_SRC
Bringing the pieces together, we get:
#+BEGIN_SRC C -i :noweb no-export :tangle ../src/main.c
/* *INDENT-ON* */
......
......@@ -24,41 +24,28 @@ dist_tarotfigures_DATA = \
%canon_reldir%_tarot_TEXINFOS = \
%reldir%/fdl.texi \
%reldir%/invoke-tarot-body.texi \
%reldir%/invoke-tarot-render-body.texi
%reldir%/invoke-tarot-render-body.texi \
%reldir%/invoke-tarot-generate-body.texi
EXTRA_DIST += \
%reldir%/tarot-figures/example.eps \
%reldir%/invoke-tarot-body.texi \
%reldir%/invoke-tarot-render-body.texi \
%reldir%/invoke-tarot.texi \
%reldir%/invoke-tarot-render.texi
%reldir%/invoke-tarot-generate-body.texi
MAINTAINERCLEANFILES += \
$(srcdir)/%reldir%/tarot-figures/example.png \
$(srcdir)/%reldir%/tarot-figures/example.eps \
$(srcdir)/%reldir%/invoke-tarot.texi \
$(srcdir)/%reldir%/invoke-tarot-render.texi \
$(srcdir)/%reldir%/invoke-tarot-body.texi \
$(srcdir)/%reldir%/invoke-tarot-render-body.texi
$(srcdir)/%reldir%/invoke-tarot-body.texi: %reldir%/invoke-tarot.texi
$(AM_V_GEN) tail -n +3 \
$(srcdir)/%reldir%/invoke-tarot.texi \
> $(srcdir)/%reldir%/invoke-tarot-body.texi
$(srcdir)/%reldir%/invoke-tarot-render-body.texi: %reldir%/invoke-tarot-render.texi
$(AM_V_GEN) tail -n +3 \
$(srcdir)/%reldir%/invoke-tarot-render.texi \
> $(srcdir)/%reldir%/invoke-tarot-render-body.texi
$(srcdir)/%reldir%/invoke-tarot-render-body.texi \
$(srcdir)/%reldir%/invoke-tarot-generate-body.texi
$(srcdir)/%reldir%/tarot.info: %reldir%/tarot-figures/example.png
$(srcdir)/%reldir%/tarot.xml: %reldir%/tarot-figures/example.png
$(srcdir)/%reldir%/tarot-figures/example.png: games/example.xml.png
$(MKDIR_P) $(srcdir)/%reldir%/tarot-figures
@$(MKDIR_P) $(srcdir)/%reldir%/tarot-figures
$(AM_V_GEN) cp $(srcdir)/games/example.xml.png $(srcdir)/%reldir%/tarot-figures/example.png
$(srcdir)/%reldir%/tarot-figures/example.eps: %reldir%/tarot-figures/example.png
$(AM_V_GEN) $(CONVERT) $(srcdir)/%reldir%/tarot-figures/example.png $(srcdir)/%reldir%/tarot-figures/example.eps
$(srcdir)/%reldir%/tarot.texi: %reldir%/invoke-tarot-body.texi
$(srcdir)/%reldir%/tarot.texi: %reldir%/invoke-tarot-render-body.texi
......@@ -36,3 +36,5 @@ include %reldir%/xml/Makefile.am
include %reldir%/layout/Makefile.am
include %reldir%/cairo/Makefile.am
include %reldir%/gtk/Makefile.am
include %reldir%/tree/Makefile.am
include %reldir%/mcts/Makefile.am
......@@ -52,8 +52,10 @@ $(srcdir)/%reldir%/tarot-render-opts.c: %reldir%/tarot-render-opts.def
$(srcdir)/%reldir%/tarot-render.man: %reldir%/tarot-render-opts.def
$(AM_V_GEN) cd $(srcdir)/%reldir% && $(AUTOGEN) --writable -Tagman-cmd.tpl -btarot tarot-render-opts.def \
&& mv tarot-render.1 tarot-render.man
$(srcdir)/doc/invoke-tarot-render.texi: %reldir%/tarot-render-opts.def
$(srcdir)/doc/invoke-tarot-render-body.texi: %reldir%/tarot-render-opts.def
$(AM_V_GEN) cd $(srcdir)/doc && $(AUTOGEN) --writable -Tagtexi-cmd.tpl $(abs_top_srcdir)/%reldir%/tarot-render-opts.def
@tail -n +3 $(srcdir)/doc/invoke-tarot-render.texi > $(srcdir)/doc/invoke-tarot-render-body.texi
@rm -f $(srcdir)/doc/invoke-tarot-render.texi
$(srcdir)/%reldir%/tarot_render.c: %reldir%/tarot_render.vala \
src/tarot-@LIBTOOL_CURRENT@.0.vapi \
%reldir%/cardpainter-@LIBTOOL_CURRENT@.0.vapi
......@@ -71,14 +73,11 @@ EXTRA_DIST += \
%reldir%/tarot-render-opts.c \
%reldir%/tarot-render-opts.h \
%reldir%/tarot-render-main.c \
%reldir%/tarot-render.man \
doc/invoke-tarot-render.texi
%reldir%/tarot-render.man
MAINTAINERCLEANFILES += \
$(srcdir)/%reldir%/tarot_render.c \
$(srcdir)/%reldir%/tarot-render.man \
$(srcdir)/doc/invoke-tarot-render.texi \
$(srcdir)/%reldir%/invoke-tarot-render.texi \
$(srcdir)/%reldir%/tarot-render-opts.c \
$(srcdir)/%reldir%/tarot-render-opts.h
......
......@@ -177,7 +177,7 @@ call_add (TarotCall * call, TarotPlayer taker, TarotCard c)
static int
call_owned_by (TarotCall * call, TarotPlayer owner, TarotCard c)
{
if (!_call_get_has_started (call))
if (!_call_get_has_started (call) || !call_card_known (call))
{
return 0;
}
......
......@@ -91,6 +91,10 @@ extern "C"
static int doscard_check_discard (const TarotDoscard * doscard,
TarotPlayer player,
const TarotHand * discard);
/* The dog is not done, but we know its cards since we had a full
deal. */
static int doscard_can_autoreveal (const TarotDoscard * doscard,
TarotHand * dog);
static int doscard_reveal_dog (TarotDoscard * doscard,
const TarotHand * dog);
static int doscard_set_partial_discard (TarotDoscard * doscard,
......
......@@ -162,8 +162,6 @@ doscard_start (TarotDoscard * doscard)
_doscard_set_has_started (doscard, 1);
_doscard_set_dog_done (doscard, 0);
_doscard_set_discard_done (doscard, 0);
hand_set (&(doscard->dog), NULL, 0);
hand_set (&(doscard->discard), NULL, 0);
}
return error;
}
......@@ -267,6 +265,17 @@ doscard_check_discard (const TarotDoscard * doscard, TarotPlayer player,
&& (hand_size (discard) == doscard_size (doscard)));
}
static inline int
doscard_can_autoreveal (const TarotDoscard * doscard, TarotHand * dog)
{
if (doscard_expects_dog (doscard)
&& hand_size (&(doscard->dog)) == doscard_size (doscard))
{
return (hand_copy (dog, &(doscard->dog)) == 0);
}
return 0;
}
static inline int
doscard_reveal_dog (TarotDoscard * doscard, const TarotHand * dog)
{
......@@ -329,7 +338,8 @@ doscard_set_discard (TarotDoscard * doscard, const TarotHand * discard)
static inline int
doscard_add_unplayed_card (TarotDoscard * doscard, TarotCard card)
{
if (_doscard_get_discard_done (doscard))
if (_doscard_get_discard_done (doscard)
|| _doscard_get_contract (doscard) >= TAROT_STRAIGHT_KEEP)
{
/* The unplayed card is for the discard */
if (hand_insert (&(doscard->discard), card) != 0)
......
......@@ -142,7 +142,8 @@ push_event (TarotGameEvent *** events, size_t * n_events,
if (*n_events >= *n_allocated)
{
size_t new_n_allocated = *n_allocated * 2;
TarotGameEvent **new_events = realloc (*events, new_n_allocated);
TarotGameEvent **new_events =
realloc (*events, new_n_allocated * sizeof (TarotGameEvent *));
if (new_events == NULL)
{
return 1;
......@@ -150,6 +151,7 @@ push_event (TarotGameEvent *** events, size_t * n_events,
*events = new_events;
*n_allocated = new_n_allocated;
}
assert (*n_events < *n_allocated);
(*events)[(*n_events)++] = event;
return 0;
}
......@@ -190,6 +192,7 @@ tarot_game_save_to_xml (const TarotGame * game)
TarotGameEvent *next;
if (alloc_events (&events, &n_events, &n_allocated) != 0)
{
tarot_game_iterator_free (iterator);
return NULL;
}
while ((next = tarot_game_iterator_next_value (iterator)) != NULL)
......@@ -197,11 +200,13 @@ tarot_game_save_to_xml (const TarotGame * game)
if (push_event (&events, &n_events, &n_allocated, next) != 0)
{
free_events (events, n_events);
tarot_game_iterator_free (iterator);
return NULL;
}
}
ret = tarot_xml_save (events, n_events);
free_events (events, n_events);
tarot_game_iterator_free (iterator);
return ret;
}
......@@ -315,7 +320,7 @@ tarot_game_get_deal_of (const TarotGame * game, TarotPlayer who,
}
memcpy (array->data, buffer, n * sizeof (TarotCard));
}
return 1;
return 0;
}
int
......@@ -495,7 +500,7 @@ tarot_game_get_discard_according_to (const TarotGame * game, TarotPlayer whom,
{
TarotGameHandle h;
TarotHand dest;
size_t n;
size_t n = 0;
TarotCard buffer[6];
dest.n_max = 6;
dest.n = &n;
......@@ -796,6 +801,30 @@ tarot_game_add_event (TarotGame * game, const TarotGameEvent * event)
return game_add_event (&h, event);
}
int
tarot_game_can_autoreveal (const TarotGame * game, TarotCardArray * cards)
{
TarotGameHandle h;
TarotHand dest;
size_t n;
TarotCard buffer[6];
dest.n_max = 6;
dest.n = &n;
dest.buffer = buffer;
tarot_game_u_generalize ((TarotGame *) game, &h);
if (game_can_autoreveal (&h, &dest))
{
assert (n <= 6);
if (card_array_resize (cards, n) != 0)
{
return 0;
}
memcpy (cards->data, buffer, n * sizeof (TarotCard));
return 1;
}
return 0;
}
int
tarot_game_base_score (const TarotGame * game)
{
......
......@@ -287,6 +287,13 @@ extern "C"
int *cannot_undertrump);
int tarot_game_add_event (TarotGame * game, const TarotGameEvent * event);
/**
* tarot_game_can_autoreveal:
* Returns: (type boolean):
*/
int tarot_game_can_autoreveal (const TarotGame * game,
TarotCardArray * dog);
/* WARNING: This function may succeed but lead to a state where a
player has no playable card!! Don't use this directly, rather
use tarot_counter_and_game_impute. */
......
......@@ -221,6 +221,8 @@ extern "C"
int *cannot_undertrump);
static int game_add_event (TarotGameHandle * game,
const TarotGameEvent * event);
static int game_can_autoreveal (const TarotGameHandle * game,
TarotHand * dog);
static int game_base_score (const TarotGameHandle * game);
static int game_get_score (const TarotGameHandle * game, TarotPlayer i,
size_t n, int *dest);
......
......@@ -290,6 +290,7 @@ game_step_advance (TarotGameHandle * game)
if (bids_discard_allowed (&(game->bids)))
{
game_set_step (game, TAROT_DOG);
return game_step_advance (game);
}
else
{
......@@ -320,6 +321,7 @@ game_step_advance (TarotGameHandle * game)
if (bids_discard_allowed (&(game->bids)))
{
game_set_step (game, TAROT_DOG);
return game_step_advance (game);
}
else
{
......@@ -489,7 +491,11 @@ game_get_cards (const TarotGameHandle * game, TarotPlayer who,
int error = hands_known (&(game->hands), who) == 0;
if (error == 0)
{
return hand_copy (dest, &(game->hands.hands[who]));
if (hand_copy (dest, &(game->hands.hands[who])) != 0)
{
return 1;
}
return 0;
}
return error;
}
......@@ -587,6 +593,7 @@ static inline int
game_get_bid (const TarotGameHandle * game, TarotPlayer player,
TarotBid * bid)
{
assert (game_get_n_bids (game) > player);
*bid = game->bids.bids[player];
return (!*(game->bids.has_started) || player >= *(game->bids.n_bids));
}
......@@ -977,12 +984,12 @@ game_hint_card (const TarotGameHandle * game,
&(game->tricks.tricks[tricks_current (&(game->tricks))]);
if (trick_has_lead_suit (current_trick))
{
TarotSuit lead_suit = trick_lead_suit (current_trick);
TarotNumber max_trump = trick_max_trump (current_trick);
assert (max_trump <= 21);
error =
hand_hint_card_with_lead (next_hand,
trick_lead_suit
(current_trick),
trick_max_trump
(current_trick), playable);
hand_hint_card_with_lead (next_hand, lead_suit, max_trump,
playable);
}
else if (game->with_call && tricks_current (&(game->tricks)) == 0)
{
......@@ -1261,11 +1268,20 @@ static inline int
game_add_deal_all (TarotGameHandle * game, const TarotPlayer * owners)
{
int error = (game_check_deal_all (game, owners) == 0);
TarotCard i;
if (error == 0)
{
game_set_dealt (game, game->n_players);
error = error || hands_set_all (&(game->hands), owners);
error = error || game_step_advance (game);
for (i = 0; i < 78; i++)
{
if (owners[i] >= game->n_players)
{
error = error
|| doscard_add_unplayed_card (&(game->doscard), i);
}
}
assert (error == 0);
}
return error;
......@@ -1347,18 +1363,14 @@ game_add_dog (TarotGameHandle * game, const TarotHand * dog)
int error = (game_check_dog (game, dog) == 0);
if (error == 0)
{
TarotPlayer i;
error = error || doscard_reveal_dog (&(game->doscard), dog);
for (i = 0; i < game->n_players; ++i)
if (game_with_call (game))
{
if (hands_known (&(game->hands), i))
size_t i_card;
for (i_card = 0; i_card < *(dog->n); ++i_card)
{
size_t i_card;
for (i_card = 0; i_card < *(dog->n); ++i_card)
{
TarotCard c = dog->buffer[i_card];
error = error || call_doscard_card (game->call, c);
}
TarotCard c = dog->buffer[i_card];
error = error || call_doscard_card (game->call, c);
}
}
error = error || game_step_advance (game);
......@@ -1367,6 +1379,16 @@ game_add_dog (TarotGameHandle * game, const TarotHand * dog)
return error;
}
static inline int
game_can_autoreveal (const TarotGameHandle * game, TarotHand * dog)
{
if (doscard_can_autoreveal (&(game->doscard), dog))
{
return game_check_dog (game, dog);
}
return 0;
}
static inline int
game_add_discard (TarotGameHandle * game, const TarotHand * discard)
{
......@@ -1390,15 +1412,18 @@ game_add_discard (TarotGameHandle * game, const TarotHand * discard)
error = error
|| doscard_set_partial_discard (&(game->doscard), discard);
}
for (i = 0; i < game->n_players; ++i)
if (game->with_call)
{
if (hands_known (&(game->hands), i))
for (i = 0; i < game->n_players; ++i)
{
size_t i_card;
for (i_card = 0; i_card < *(discard->n); ++i_card)
if (hands_known (&(game->hands), i))
{
TarotCard c = discard->buffer[i_card];
error = error || call_doscard_card (game->call, c);
size_t i_card;
for (i_card = 0; i_card < *(discard->n); ++i_card)
{
TarotCard c = discard->buffer[i_card];
error = error || call_doscard_card (game->call, c);
}
}
}
}
......@@ -1452,6 +1477,20 @@ game_add_card (TarotGameHandle * game, TarotCard card)
assert (error == 0);
hands_remove (&(game->hands), next, card);
assert (error == 0);
if (tricks_count_remaining_cards (&(game->tricks), next) == 0)
{
TarotHand empty;
size_t n = 0;
empty.n = &n;
empty.n_max = 0;
if (hands_known (&(game->hands), next) == 0)
{
if (hands_set (&(game->hands), next, &empty) != 0)
{
assert (0);
}
}
}
}
return error;
}
......@@ -1714,8 +1753,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
game_with_call (&(iterator->handle)))
!= 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1732,12 +1770,12 @@ game_iterator_next_value (TarotGameIterator * iterator)
if (ret == NULL
|| tarot_game_event_set_deal (ret, myself, &cards_array) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
iterator->step = TAROT_BIDS;
iterator->i_player = 0;
}
}
else if (game_get_deal_all (&(iterator->handle), &player_array) == 0)
......@@ -1746,24 +1784,24 @@ game_iterator_next_value (TarotGameIterator * iterator)
if (ret == NULL
|| tarot_game_event_set_deal_all (ret, &player_array) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
iterator->step = TAROT_BIDS;
iterator->i_player = 0;
}
}
break;
case TAROT_BIDS:
next = iterator->i_player;
if (game_get_bid (&(iterator->handle), next, &bid) == 0)
if (game_get_n_bids (&(iterator->handle)) > next
&& game_get_bid (&(iterator->handle), next, &bid) == 0)
{
ret = tarot_game_event_alloc ();
if (ret == NULL || tarot_game_event_set_bid (ret, bid) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1775,20 +1813,22 @@ game_iterator_next_value (TarotGameIterator * iterator)
if (iterator->i_player >= game_n_players (&(iterator->handle)))
{
iterator->step = TAROT_DECLS;
iterator->i_player = 0;
}
}
}
break;
case TAROT_DECLS:
next = iterator->i_player;
if (game_get_declaration (&(iterator->handle), next, &declaration) == 0)
if (game_get_n_declarations (&(iterator->handle)) > next
&& game_get_declaration (&(iterator->handle), next,
&declaration) == 0)
{
ret = tarot_game_event_alloc ();
if (ret == NULL
|| tarot_game_event_set_decl (ret, declaration) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1835,8 +1875,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
ret = tarot_game_event_alloc ();
if (ret == NULL || tarot_game_event_set_call (ret, card) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1874,8 +1913,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
if (ret == NULL
|| tarot_game_event_set_dog (ret, &cards_array) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1894,8 +1932,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
if (ret == NULL
|| tarot_game_event_set_discard (ret, &cards_array) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1928,8 +1965,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
if (ret == NULL
|| tarot_game_event_set_handful (ret, &cards_array) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......@@ -1938,7 +1974,8 @@ game_iterator_next_value (TarotGameIterator * iterator)
}
else
{
assert (0);
iterator->handful_done = 1;
ret = game_iterator_next_value (iterator);
}
}
else
......@@ -1951,8 +1988,7 @@ game_iterator_next_value (TarotGameIterator * iterator)
ret = tarot_game_event_alloc ();
if (ret == NULL || tarot_game_event_set_card (ret, card) != 0)
{
tarot_game_event_free (ret);
ret = NULL;
abort ();
}
else
{
......
......@@ -49,6 +49,9 @@ extern "C"
TAROT_CARD_EVENT
} TarotGameEventT;
/**
* tarot_game_event_alloc: (constructor):
*/
TarotGameEvent *tarot_game_event_alloc ();