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

Always use the game with a counter.

parent aa3cf2d4
Pipeline #94852 passed with stages
in 7 minutes and 32 seconds
......@@ -815,9 +815,40 @@ actually do something.
#+attr_texinfo: :options struct TarotGame
#+begin_deftp
An abstract type that holds the state for a whole game.
An abstract type that holds the state for a whole game. You can
create an empty one with =tarot_game_alloc=.
#+end_deftp
#+attr_texinfo: :options {TarotGame *} tarot_game_alloc ()
#+begin_deftypefun
Allocate a new empty game that is ready to receive events. The return
value should be disposed of with =tarot_game_free=.
#+end_deftypefun
#+attr_texinfo: :options void tarot_game_free (TarotGame *@var{game})
#+begin_deftypefun
Destroy a previously allocated /game/.
#+end_deftypefun
#+attr_texinfo: :options struct TarotCounter
#+begin_deftp
An abstract type that tracks in-game information about the other
players: whether some player cannot follow suits, for instance. You
can create one with =tarot_counter_alloc=. Please note that a counter
should always be in sync with a game, otherwise it is worthless.
#+end_deftp
#+attr_texinfo: :options {TarotCounter *} tarot_counter_alloc ()
#+begin_deftypefun
Allocate a new empty counter that is ready to receive events. The return
value should be disposed of with =tarot_counter_free=.
#+end_deftypefun
#+attr_texinfo: :options void tarot_counter_free (TarotCounter *@var{counter})
#+begin_deftypefun
Destroy a previously allocated /counter/.
#+end_deftypefun
There are two things that we want to be able to do: check an event,
and actually add it to our state.
......@@ -826,9 +857,10 @@ and actually add it to our state.
Check whether /event/ may be added to /game/.
#+end_deftypefun
#+attr_texinfo: :options int tarot_game_add_event (const TarotGame *@var{game}, const TarotGameEvent *@var{event})
#+attr_texinfo: :options int tarot_counter_and_game_add_event (const TarotCounter *@var{counter}, const TarotGame *@var{game}, const TarotGameEvent *@var{event})
#+begin_deftypefun
Try to add /event/ to /game/. Return 0 on success, or an error code.
Try to add /event/ to /game/ and analyze this event through the
/counter/. Return 0 on success, or an error code.
#+end_deftypefun
What's more, some commands are not directly acting on games. So we
......@@ -866,24 +898,49 @@ Check whether the next command in /cli/ is a =load= command, and if so
set /filename/ to an unowned copy of the filename.
#+end_deftypefun
#+attr_texinfo: :options int tarot_counter_and_game_load_from_xml (TarotCounter *@var{counter}, TarotGame *@var{game}, const char *@var{input})
#+begin_deftypefun
Load a /game/ (and analyze it through /counter/) from /input/, which
is an utf-8 encoded XML document, and return 0 on success, or an error
code.
#+end_deftypefun
#+attr_texinfo: :options int tarot_cli_is_save (const TarotCli *@var{cli}, char **@var{filename})
#+begin_deftypefun
Check whether the next command in /cli/ is a =save= command, and if so
set /filename/ to an unowned copy of the filename.
#+end_deftypefun
#+attr_texinfo: :options {char *} tarot_game_save_to_xml (const TarotGame *@var{game})
#+begin_deftypefun
Write the XML representation of /game/ to an UTF-8 encoded stream, and
return it. The return value is fully transfered; you should =free()=
it.
#+end_deftypefun
#+attr_texinfo: :options int tarot_cli_is_check (const TarotCli *@var{cli}, TarotGameEvent **@var{event})
#+begin_deftypefun
Check whether the next command in /cli/ is a =check= command, and if
so set /event/ to an unowned copy of the event.
#+end_deftypefun
#+attr_texinfo: :options int tarot_game_check_event (const TarotGame *@var{game}, const TarotGameEvent *@var{event})
#+begin_deftypefun
Check and return whether /event/ may be added to /game/.
#+end_deftypefun
#+attr_texinfo: :options int tarot_cli_is_event (const TarotCli *@var{cli}, TarotGameEvent **@var{event})
#+begin_deftypefun
Check whether the next command in /cli/ is a =event= command, and if
so set /event/ to an unowned copy of the event.
#+end_deftypefun
#+attr_texinfo: :options int tarot_counter_and_game_add_event (TarotCounter *@var{counter}, TarotGame *@var{game}, const TarotGameEvent *@var{event})
#+begin_deftypefun
Add /event/ to /game/ (and analyze it through /counter/). Return 0 on
success, or an error code.
#+end_deftypefun
So, when we have a new command to process, it is simply a matter of
finding which one it is.
......@@ -951,7 +1008,9 @@ See the manual for the definition of the cards and players.\n\
else
{
char *xml = read_whole_file (file);
int error = tarot_game_load_from_xml (current_game, xml);
int error = tarot_counter_and_game_load_from_xml (current_counter,
current_game,
xml);
if (error)
{
fprintf (stderr, "ERROR: invalid file %s\n", filename);
......@@ -993,7 +1052,8 @@ See the manual for the definition of the cards and players.\n\
}
else if (tarot_cli_is_event (cli, &event))
{
if (tarot_game_add_event (current_game, event) != 0)
if (tarot_counter_and_game_add_event
(current_counter, current_game, event) != 0)
{
fprintf (stderr, "ERROR: this is not possible\n");
}
......@@ -2057,6 +2117,7 @@ add_history (const char *line)
#include "tarot-opts.h"
static TarotGame *current_game;
static TarotCounter *current_counter;
static void print_status (const TarotGame * game);
static char *read_whole_file (FILE * file);
......@@ -2141,6 +2202,7 @@ int
tarot_run ()
{
current_game = tarot_game_alloc ();
current_counter = tarot_counter_alloc ();
if (HAVE_OPT (BRIEF) && ENABLED_OPT (BRIEF))
{
/* Do not print the greeting */
......@@ -2151,6 +2213,7 @@ tarot_run ()
}
tarot_shell ();
tarot_game_free (current_game);
tarot_counter_free (current_counter);
return 0;
}
/* *INDENT-OFF* */
......
......@@ -39,6 +39,7 @@ LIBTAROT_VERSION_INFO=0:0:0
%reldir%/lexer/libtarot-lexer.la \
%reldir%/parser/libtarot-parser.la \
%reldir%/cli/libtarot-cli.la \
%reldir%/xml/libtarot-xml.la \
lib-library/libgnulibrary.la
%canon_reldir%_tarot_SOURCES = \
......@@ -82,3 +83,4 @@ include %reldir%/counter/Makefile.am
include %reldir%/lexer/Makefile.am
include %reldir%/parser/Makefile.am
include %reldir%/cli/Makefile.am
include %reldir%/xml/Makefile.am
......@@ -20,33 +20,18 @@ noinst_LTLIBRARIES += %reldir%/libtarot-core-game.la
tarotinclude_HEADERS += %reldir%/tarot/game.h
EXTRA_DIST += %reldir%/check_xml_1.xml
%canon_reldir%_libtarot_core_game_la_SOURCES = \
%reldir%/game.c \
%reldir%/xml.c \
%reldir%/tarot/game_private.h \
%reldir%/tarot/game_private_impl.h
%canon_reldir%_libtarot_core_game_la_CFLAGS = \
$(AM_CFLAGS) $(XML_CFLAGS)
$(AM_CFLAGS)
%canon_reldir%_libtarot_core_game_la_CXXFLAGS = \
$(AM_CXXFLAGS)
%canon_reldir%_libtarot_core_game_la_CPPFLAGS = \
$(AM_CPPFLAGS)
%canon_reldir%_libtarot_core_game_la_LDFLAGS = \
-no-undefined $(AM_LDADD) $(XML_LIBS)
check_PROGRAMS += %reldir%/check_xml
%canon_reldir%_check_xml_SOURCES = \
%reldir%/check_xml.c
%canon_reldir%_check_xml_CFLAGS = \
$(AM_CFLAGS)
%canon_reldir%_check_xml_CXXFLAGS = \
$(AM_CXXFLAGS)
%canon_reldir%_check_xml_CPPFLAGS = \
$(AM_CPPFLAGS)
%canon_reldir%_check_xml_LDADD = \
src/libtarot.la
-no-undefined $(AM_LDADD)
AM_CPPFLAGS += \
-I $(srcdir)/%reldir% \
......
......@@ -24,6 +24,7 @@
#include <tarot/game.h>
#include <tarot/cards_private.h>
#include <tarot/player_private.h>
#include <tarot/xml.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
......@@ -131,6 +132,29 @@ tarot_game_serialize (const TarotGame * game, TarotGameEventArray * events)
return game_serialize (&h, events);
}
char *
tarot_game_save_to_xml (const TarotGame * game)
{
TarotGameEventArray *events = tarot_game_event_array_alloc ();
size_t i, n;
char *ret = NULL;
if (events == NULL)
{
return NULL;
}
if (tarot_game_serialize (game, events) == 0)
{
ret = tarot_xml_save (events);
}
n = tarot_game_event_array_size (events);
for (i = 0; i < n; i++)
{
tarot_game_event_free (tarot_game_event_array_get (events, i));
}
tarot_game_event_array_free (events);
return ret;
}
int
tarot_game_load (TarotGame * game, const TarotGameEventArray * array)
{
......@@ -151,6 +175,27 @@ tarot_game_load (TarotGame * game, const TarotGameEventArray * array)
return game_load (&h, (n_events - i), &(events[i]));
}
int
tarot_game_load_from_xml (TarotGame * game, const char *input)
{
TarotGameEventArray *events = tarot_game_event_array_alloc ();
int load_ok = 0;
size_t i, n;
if (events == NULL)
{
return 1;
}
load_ok = (tarot_xml_load (events, input) == 0);
load_ok = load_ok && (tarot_game_load (game, events) == 0);
n = tarot_game_event_array_size (events);
for (i = 0; i < n; i++)
{
tarot_game_event_free (tarot_game_event_array_get (events, i));
}
tarot_game_event_array_free (events);
return load_ok;
}
size_t
tarot_game_n_players (const TarotGame * game)
{
......
......@@ -28,7 +28,6 @@
#include <tarot/step.h>
#include <tarot/cards.h>
#include <tarot/game_event.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C"
......
......@@ -31,6 +31,7 @@
#include <tarot/lexer.h>
#include <tarot/parser.h>
#include <tarot/cli.h>
#include <tarot/xml.h>
#ifdef __cplusplus
extern "C"
......
......@@ -167,6 +167,20 @@ tarot_counter_and_game_add_event (TarotCounter * counter, TarotGame * game,
return counter_and_game_add_event (counter, game, event);
}
int
tarot_counter_and_game_load (TarotCounter * counter, TarotGame * game,
const TarotGameEventArray * events)
{
return counter_and_game_load (counter, game, events);
}
int
tarot_counter_and_game_load_from_xml (TarotCounter * counter,
TarotGame * game, const char *xml)
{
return counter_and_game_load_from_xml (counter, game, xml);
}
#include "counter_private_impl.h"
#include <tarot/cards_private_impl.h>
#include <tarot/player_private_impl.h>
......
......@@ -73,6 +73,12 @@ extern "C"
int tarot_counter_and_game_add_event (TarotCounter * counter,
TarotGame * game,
const TarotGameEvent * event);
int tarot_counter_and_game_load (TarotCounter * counter,
TarotGame * game,
const TarotGameEventArray * events);
int tarot_counter_and_game_load_from_xml (TarotCounter * counter,
TarotGame * game,
const char *input);
#ifdef __cplusplus
}
......
......@@ -95,6 +95,12 @@ extern "C"
static int counter_and_game_add_event (TarotCounter * counter,
TarotGame * game,
const TarotGameEvent * event);
static int counter_and_game_load (TarotCounter * counter,
TarotGame * game,
const TarotGameEventArray * events);
static int counter_and_game_load_from_xml (TarotCounter * counter,
TarotGame * game,
const char *input);
#ifdef __cplusplus
}
......
......@@ -23,6 +23,7 @@
#include "counter_private.h"
#include <tarot/cards_private.h>
#include <tarot/game_event_private.h>
#include <tarot/xml.h>
#include <assert.h>
#include <stdio.h>
......@@ -323,7 +324,7 @@ counter_remaining_trumps (const TarotCounter * counter, size_t n,
return ret;
}
int
static inline int
counter_and_game_add_event (TarotCounter * counter, TarotGame * game,
const TarotGameEvent * event)
{
......@@ -385,7 +386,7 @@ counter_and_game_add_event (TarotCounter * counter, TarotGame * game,
cards[n_cards++] = card;
}
}
counter_deal (counter, myself, 78, cards);
counter_deal (counter, myself, n_cards, cards);
}
break;
case TAROT_CALL_EVENT:
......@@ -431,3 +432,42 @@ counter_and_game_add_event (TarotCounter * counter, TarotGame * game,
(void) is_excuse;
return 0;
}
static inline int
counter_and_game_load (TarotCounter * counter,
TarotGame * game, const TarotGameEventArray * events)
{
size_t n, i;
n = tarot_game_event_array_size (events);
for (i = 0; i < n; i++)
{
const TarotGameEvent *event = tarot_game_event_array_get (events, i);
if (counter_and_game_add_event (counter, game, event) != 0)
{
return 1;
}
}
return 0;
}
static inline int
counter_and_game_load_from_xml (TarotCounter * counter,
TarotGame * game, const char *input)
{
TarotGameEventArray *events = tarot_game_event_array_alloc ();
int load_ok = 0;
size_t i, n;
if (events == NULL)
{
return 1;
}
load_ok = (tarot_xml_load (events, input) == 0);
load_ok = load_ok && (counter_and_game_load (counter, game, events) == 0);
n = tarot_game_event_array_size (events);
for (i = 0; i < n; i++)
{
tarot_game_event_free (tarot_game_event_array_get (events, i));
}
tarot_game_event_array_free (events);
return load_ok;
}
# 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/>.
noinst_LTLIBRARIES += %reldir%/libtarot-xml.la
tarotinclude_HEADERS += %reldir%/tarot/xml.h
EXTRA_DIST += %reldir%/check_xml_1.xml
%canon_reldir%_libtarot_xml_la_SOURCES = \
%reldir%/xml.c \
%reldir%/tarot/xml.h \
%reldir%/tarot/xml_private.h \
%reldir%/tarot/xml_private_impl.h
%canon_reldir%_libtarot_xml_la_CFLAGS = \
$(AM_CFLAGS) $(XML_CFLAGS)
%canon_reldir%_libtarot_xml_la_CXXFLAGS = \
$(AM_CXXFLAGS)
%canon_reldir%_libtarot_xml_la_CPPFLAGS = \
$(AM_CPPFLAGS)
%canon_reldir%_libtarot_xml_la_LDFLAGS = \
-no-undefined $(AM_LDADD) $(XML_LIBS)
check_PROGRAMS += %reldir%/check_xml
%canon_reldir%_check_xml_SOURCES = \
%reldir%/check_xml.c
%canon_reldir%_check_xml_CFLAGS = \
$(AM_CFLAGS)
%canon_reldir%_check_xml_CXXFLAGS = \
$(AM_CXXFLAGS)
%canon_reldir%_check_xml_CPPFLAGS = \
$(AM_CPPFLAGS)
%canon_reldir%_check_xml_LDADD = \
src/libtarot.la
AM_CPPFLAGS += \
-I $(srcdir)/%reldir% \
-I %reldir% \
-DABS_TOP_SRCDIR="\"$(abs_top_srcdir)\""
INDENTED += $(%canon_reldir%_libtarot_xml_la_SOURCES)
LIBTAROT_XML_LA = %reldir%/libtarot-xml.la
......@@ -19,7 +19,8 @@
*/
#include <config.h>
#include <tarot/game.h>
#include <tarot/game_event.h>
#include <tarot/xml.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
......@@ -27,17 +28,18 @@
static void
unit_test (const char *xml)
{
TarotGame *game = tarot_game_alloc ();
TarotGameEventArray *events = tarot_game_event_array_alloc ();
char *rebuilt = NULL;
if (game == NULL)
size_t i = 0, n;
if (events == NULL)
{
abort ();
}
if (tarot_game_load_from_xml (game, xml) != 0)
if (tarot_xml_load (events, xml) != 0)
{
abort ();
}
rebuilt = tarot_game_save_to_xml (game);
rebuilt = tarot_xml_save (events);
if (rebuilt == NULL)
{
abort ();
......@@ -47,7 +49,12 @@ unit_test (const char *xml)
abort ();
}
free (rebuilt);
tarot_game_free (game);
n = tarot_game_event_array_size (events);
for (i = 0; i < n; i++)
{
tarot_game_event_free (tarot_game_event_array_get (events, i));
}
tarot_game_event_array_free (events);
}
static void
......@@ -88,7 +95,7 @@ read_all (FILE *file)
int
main ()
{
const char *filename = ABS_TOP_SRCDIR "/src/core/game/check_xml_1.xml";
const char *filename = ABS_TOP_SRCDIR "/src/xml/check_xml_1.xml";
FILE *file = fopen (filename, "r");
char *buffer = NULL;
if (file == NULL)
......
/**
* file tarot/xml.h
*
* 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/>.
*/
#ifndef H_TAROT_XML_INCLUDED
#define H_TAROT_XML_INCLUDED
#include <tarot/game_event.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
int tarot_xml_load (TarotGameEventArray * events, const char *input);
char *tarot_xml_save (const TarotGameEventArray * events);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* not H_TAROT_XML_INCLUDED */
/**
* file tarot/xml_private.h
*
* 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/>.
*/
#ifndef H_TAROT_XML_PRIVATE_INCLUDED
#define H_TAROT_XML_PRIVATE_INCLUDED
#include <tarot/game_event.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
static int xml_load (TarotGameEventArray * events, const char *input);
static char *xml_save (const TarotGameEventArray * events);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* not H_TAROT_XML_PRIVATE_INCLUDED */
/**
* file xml.c Save / load to / from XML with libxml2
* file tarot/xml_private_impl.h
*
* Copyright (C) 2017, 2018 Vivien Kraus <vivien@planete-kraus.eu>
* 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
......@@ -18,11 +18,14 @@
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <tarot/game.h>
#ifndef H_TAROT_XML_PRIVATE_IMPL_INCLUDED
#define H_TAROT_XML_PRIVATE_IMPL_INCLUDED
#include <tarot/game_event.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <libxml/parser.h>
static int
......@@ -502,20 +505,15 @@ parse_event (xmlNodePtr node)
return NULL;
}
static TarotGameEventArray *
parse_events (xmlNodePtr root)
static int
parse_events (xmlNodePtr root, TarotGameEventArray * ret)
{
size_t n_children = 0;
TarotGameEventArray *ret = tarot_game_event_array_alloc ();
xmlNodePtr child = root->xmlChildrenNode;
int one_event_failed = 0;
if (ret == NULL)
{
return NULL;
}
if (xmlStrcmp (root->name, (const xmlChar *) "game") != 0)
{