Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Tarot
tarot
Commits
2ba6fa62
Commit
2ba6fa62
authored
Oct 07, 2019
by
Vivien Kraus
Browse files
Implement the solo game
parent
4b9e7b53
Changes
11
Hide whitespace changes
Inline
Side-by-side
doc/tarot.org
View file @
2ba6fa62
...
...
@@ -1570,7 +1570,6 @@ also set.
#+end_deftypefun
** TODO The card counter
** TODO Artificial intelligence through the Monte-Carlo Tree Search
#+attr_texinfo: :options {struct} TarotMcts
#+begin_deftp
...
...
@@ -1685,7 +1684,6 @@ card points and {{{per}}} opponents will play low-valued cards.
Return the least number of iterations to achieve state-of-the-art card
playing with MCTS.
#+end_deftypefun
** The libtarot test suite
In this section we present the test suite to show different aspects of
libtarot.
...
...
@@ -2630,6 +2628,66 @@ player while setting /confidence/ to a low value.
This function is especially useful for determining the duplicaté
options.
#+end_deftypefun
** Playing a game against the AI
libtarot has an API endpoint to run a game against the AI.
#+attr_texinfo: :options {struct} TarotSolo
#+begin_deftp
A game, where all players but the specific dealt player play using the
AI.
#+end_deftp
#+attr_texinfo: :options {size_t} tarot_solo_construct (size_t @var{maxmem}, char *@var{memout}, size_t *@var{alignment}
#+begin_deftypefun
Construct a new solo game in /memout/, writing at most /maxmem/ bytes.
Output the alignment requirement for /memout/ in /alignment/, and
return the required size.
#+end_deftypefun
#+attr_texinfo: :options {TarotSolo *} tarot_solo_alloc (void)
#+begin_deftypefun
#+texinfo: @deftypefunx {void} tarot_solo_free (TarotSolo *@var{solo})
Allocate and free a new game against the AI.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_solo_copy (TarotSolo *@var{dest}, const TarotSolo *@var{source})
#+begin_deftypefun
#+texinfo: @deftypefunx {void} tarot_solo_copy_as (TarotSolo *@var{dest}, const TarotSolo *@var{source}, TarotPlayer @var{who})
Copy /source/ to /dest/ (optionally changing the human player to
/who/).
#+end_deftypefun
#+attr_texinfo: :options {TarotSolo *} tarot_solo_dup (const TarotSolo *@var{source})
#+begin_deftypefun
Allocate and return a copy of /source/.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_solo_get (const TarotSolo *@var{solo}, TarotGame *@var{game})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGame *} tarot_solo_get_alloc (const TarotSolo *@var{solo})
Get the /game/ as known by the human player in /solo/. The second
function allocates the results.
#+end_deftypefun
#+attr_texinfo: :options {TarotGameError} tarot_solo_setup (TarotSolo *@var{solo}, size_t @var{nplayers}, int @var{withcall}, TarotPlayer @var{player}, size_t @var{nowners}, const TarotPlayer *@var{owners}, TarotPlayer @var{taker}, TarotCard @var{call})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameError} tarot_solo_setup_random (TarotSolo *@var{solo}, size_t @var{nplayers}, int @var{withcall}, size_t @var{seedsize}, const char *@var{seed})
Set up the /solo/ game for /nplayers/ players (and /withcall/ if there
is a call). The /random/-suffixed function will select an interesting
game at random. Otherwise, you can specify which /player/ to play,
the individual /owners/ for each card (an array of size /nowners/,
which should be 78), the expected /taker/ and /call/ if relevant.
This function returns an error code. The only error that could happen
is a /petit sec/. There cannot be any /duplicaté/-related ticking
bomb as seen in the /duplicaté/ section, so nothing bad to fear here.
#+end_deftypefun
#+attr_texinfo: :options {TarotGameError} tarot_solo_add (TarotSolo *@var{game}, const TarotGameEvent *@var{event})
#+begin_deftypefun
Try and add /event/ to /game/. This function may only fail if /event/
is not correct for the human player.
#+end_deftypefun
* GNU Free Documentation License
:PROPERTIES:
:APPENDIX: t
...
...
src/libtarot/Makefile.am
View file @
2ba6fa62
...
...
@@ -46,3 +46,4 @@ include %reldir%/simulation/Makefile.am
include
%reldir%/xml/Makefile.am
include
%reldir%/features/Makefile.am
include
%reldir%/cnn/Makefile.am
include
%reldir%/solo/Makefile.am
src/libtarot/core/tarot.h
View file @
2ba6fa62
...
...
@@ -31,6 +31,7 @@
#include
<tarot/mcts.h>
#include
<tarot/features.h>
#include
<tarot/cnn.h>
#include
<tarot/solo.h>
#ifdef __cplusplus
extern
"C"
...
...
src/libtarot/core/tarot_private.h
View file @
2ba6fa62
...
...
@@ -388,6 +388,12 @@ extern "C"
int
cnn
;
};
struct
TarotSolo
{
TarotGame
game
;
TarotPlayer
myself
;
};
#ifdef __cplusplus
}
#endif
/* __cplusplus */
...
...
src/libtarot/gobject/tarot-gobject.c.in
View file @
2ba6fa62
...
...
@@ -85,6 +85,7 @@ TAROT_BOXED_TYPE (GameEvent, game_event)
TAROT_BOXED_TYPE (GameIterator, game_iterator)
TAROT_BOXED_TYPE (Mcts, mcts)
TAROT_BOXED_TYPE (Predictor, predictor)
TAROT_BOXED_TYPE (Solo, solo)
TAROT_BOXED_TYPE (XmlParser, xml_parser)
TAROT_BOXED_TYPE (XmlParserIterator, xml_parser_iterator)
/*** END file-header ***/
...
...
src/libtarot/gobject/tarot-gobject.h.in
View file @
2ba6fa62
...
...
@@ -50,6 +50,7 @@ extern "C"
GType tarot_game_iterator_get_type (void);
GType tarot_mcts_get_type (void);
GType tarot_predictor_get_type (void);
GType tarot_solo_get_type (void);
GType tarot_xml_parser_get_type (void);
GType tarot_xml_parser_iterator_get_type (void);
...
...
src/libtarot/solo/Makefile.am
0 → 100644
View file @
2ba6fa62
# tarot implements the rules of the tarot game
# Copyright (C) 2019 Vivien Kraus
# 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/>.
AM_CPPFLAGS
+=
-I
$(srcdir)
/%reldir%
-I
%reldir%
tarotinclude_HEADERS
+=
%reldir%/tarot/solo.h
src_libtarot_libtarot_la_SOURCES
+=
\
%reldir%/solo.c
\
%reldir%/tarot/solo_private.h
\
%reldir%/tarot/solo_private_impl.h
ENUM_HEADER_FILES
+=
%reldir%/tarot/solo.h
INTROSPECTED_SOURCES
+=
%reldir%/solo.c
src/libtarot/solo/solo.c
0 → 100644
View file @
2ba6fa62
/* tarot implements the rules of the tarot game
* Copyright (C) 2019 Vivien Kraus
*
* 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/solo_private.h>
#include
<string.h>
#include
<assert.h>
#include
<stdlib.h>
#include
<stdalign.h>
#include
"xalloc.h"
#ifdef __FRAMAC__
#undef alignof
#define alignof(x) (16)
#endif
/* __FRAMAC__ */
TarotSolo
*
tarot_solo_alloc
(
void
)
{
size_t
alignment
;
size_t
required
=
solo_construct
(
0
,
NULL
,
&
alignment
);
size_t
unused
;
void
*
mem
=
xmalloc
(
required
);
assert
(
alignment
>=
1
&&
alignment
<=
alignof
(
max_align_t
));
unused
=
solo_construct
(
required
,
mem
,
&
alignment
);
assert
(
unused
==
required
);
(
void
)
unused
;
return
mem
;
}
TarotSolo
*
tarot_solo_dup
(
const
TarotSolo
*
source
)
{
TarotSolo
*
ret
=
tarot_solo_alloc
();
tarot_solo_copy
(
ret
,
source
);
return
ret
;
}
void
tarot_solo_free
(
TarotSolo
*
solo
)
{
free
(
solo
);
}
size_t
tarot_solo_construct
(
size_t
max_mem
,
char
*
mem
,
size_t
*
alignment
)
{
return
solo_construct
(
max_mem
,
mem
,
alignment
);
}
void
tarot_solo_copy
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
)
{
solo_copy
(
dest
,
source
);
}
void
tarot_solo_copy_as
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
,
TarotPlayer
who
)
{
solo_copy_as
(
dest
,
source
,
who
);
}
void
tarot_solo_get
(
const
TarotSolo
*
solo
,
TarotGame
*
game
)
{
solo_get
(
solo
,
game
);
}
TarotGame
*
tarot_solo_get_alloc
(
const
TarotSolo
*
solo
)
{
TarotGame
*
ret
=
tarot_game_alloc
();
solo_get
(
solo
,
ret
);
return
ret
;
}
TarotGameError
tarot_solo_setup
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
TarotPlayer
myself
,
size_t
n_owners
,
const
TarotPlayer
*
owners
,
TarotPlayer
taker
,
TarotCard
call
)
{
return
solo_setup
(
solo
,
n_players
,
with_call
,
myself
,
n_owners
,
owners
,
taker
,
call
);
}
TarotGameError
tarot_solo_setup_random
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
size_t
seed_size
,
const
void
*
seed
)
{
return
solo_setup_random
(
solo
,
n_players
,
with_call
,
seed_size
,
seed
);
}
TarotGameError
tarot_solo_add
(
TarotSolo
*
solo
,
const
TarotGameEvent
*
event
)
{
return
solo_add
(
solo
,
event
);
}
#include
<tarot/solo_private_impl.h>
src/libtarot/solo/tarot/solo.h
0 → 100644
View file @
2ba6fa62
/* tarot implements the rules of the tarot game
* Copyright (C) 2019 Vivien Kraus
*
* 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_SOLO_INCLUDED
#define H_TAROT_SOLO_INCLUDED
#include
<stddef.h>
#include
<tarot/game.h>
#include
<tarot/player.h>
#include
<tarot/cards.h>
#ifdef __cplusplus
extern
"C"
{
#endif
/* __cplusplus */
struct
TarotSolo
;
typedef
struct
TarotSolo
TarotSolo
;
/**
* tarot_solo_alloc: (constructor)
*/
TarotSolo
*
tarot_solo_alloc
(
void
);
TarotSolo
*
tarot_solo_dup
(
const
TarotSolo
*
source
);
void
tarot_solo_free
(
TarotSolo
*
solo
);
/**
* tarot_solo_construct:
* @max_mem: available number of bytes in @mem
* @mem_out: (array length=max_mem): available aligned memory
* @alignment: (out): the game alignment
*/
size_t
tarot_solo_con
(
size_t
max_mem
,
char
*
mem_out
,
size_t
*
alignment
);
void
tarot_solo_copy
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
);
void
tarot_solo_copy_as
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
,
TarotPlayer
who
);
/**
* tarot_solo_get:
* @game: (out):
*/
void
tarot_solo_get
(
const
TarotSolo
*
solo
,
TarotGame
*
game
);
TarotGame
*
tarot_solo_get_alloc
(
const
TarotSolo
*
solo
);
/**
* tarot_solo_setup:
* @with_call: (type boolean):
*/
TarotGameError
tarot_solo_setup
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
TarotPlayer
myself
,
size_t
n_owners
,
const
TarotPlayer
*
owners
,
TarotPlayer
taker
,
TarotCard
call
);
/**
* tarot_solo_setup_random:
* @seed: (array length=seed_size) (type char):
* @with_call: (type boolean):
*/
TarotGameError
tarot_solo_setup_random
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
size_t
seed_size
,
const
void
*
seed
);
TarotGameError
tarot_solo_add
(
TarotSolo
*
solo
,
const
TarotGameEvent
*
event
);
#ifdef __cplusplus
}
#endif
/* __cplusplus */
#endif
/* not H_TAROT_SOLO_INCLUDED */
src/libtarot/solo/tarot/solo_private.h
0 → 100644
View file @
2ba6fa62
/* tarot implements the rules of the tarot game
* Copyright (C) 2019 Vivien Kraus
*
* 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_SOLO_PRIVATE_INCLUDED
#define H_TAROT_SOLO_PRIVATE_INCLUDED
#include
<stddef.h>
#include
<tarot_private.h>
#include
<tarot/solo.h>
#ifdef __cplusplus
extern
"C"
{
#endif
/* __cplusplus */
static
size_t
solo_construct
(
size_t
max_mem
,
char
*
mem_out
,
size_t
*
alignment
);
static
void
solo_copy
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
);
static
void
solo_copy_as
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
,
TarotPlayer
who
);
static
void
solo_get
(
const
TarotSolo
*
solo
,
TarotGame
*
game
);
static
TarotGameError
solo_setup
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
TarotPlayer
myself
,
size_t
n_owners
,
const
TarotPlayer
*
owners
,
TarotPlayer
taker
,
TarotCard
call
);
static
TarotGameError
solo_setup_random
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
size_t
seed_size
,
const
unsigned
char
*
seed
);
static
TarotGameError
solo_add
(
TarotSolo
*
solo
,
const
TarotGameEvent
*
event
);
#ifdef __cplusplus
}
#endif
/* __cplusplus */
#endif
/* not H_TAROT_SOLO_PRIVATE_INCLUDED */
src/libtarot/solo/tarot/solo_private_impl.h
0 → 100644
View file @
2ba6fa62
/* tarot implements the rules of the tarot game
* Copyright (C) 2018, 2019 Vivien Kraus
*
* 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_SOLO_PRIVATE_IMPL_INCLUDED
#define H_TAROT_SOLO_PRIVATE_IMPL_INCLUDED
#include
<tarot/solo_private.h>
#include
<tarot/game_private.h>
#include
<tarot/game_event_private.h>
#include
<tarot/features_private.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<assert.h>
#include
<string.h>
#include
<nettle/yarrow.h>
#include
<float.h>
static
inline
void
solo_advance
(
TarotSolo
*
dest
);
static
inline
size_t
solo_construct
(
size_t
max_mem
,
char
*
mem
,
size_t
*
alignment
)
{
size_t
required
=
sizeof
(
TarotSolo
);
*
alignment
=
alignof
(
TarotSolo
);
if
(
max_mem
>=
required
)
{
TarotSolo
*
solo
=
(
TarotSolo
*
)
mem
;
game_initialize
(
&
(
solo
->
game
),
4
,
0
);
solo
->
myself
=
0
;
return
max_mem
;
}
return
required
;
}
static
inline
void
solo_copy
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
)
{
game_copy
(
&
(
dest
->
game
),
&
(
source
->
game
));
dest
->
myself
=
source
->
myself
;
}
static
inline
void
solo_copy_as
(
TarotSolo
*
dest
,
const
TarotSolo
*
source
,
TarotPlayer
who
)
{
TarotGameError
err
=
game_copy_as
(
&
(
dest
->
game
),
&
(
source
->
game
),
who
);
if
(
err
!=
TAROT_GAME_OK
)
{
assert
(
0
);
}
dest
->
myself
=
who
;
solo_advance
(
dest
);
}
static
inline
void
solo_get
(
const
TarotSolo
*
solo
,
TarotGame
*
game
)
{
TarotGameError
err
=
game_copy_as
(
game
,
&
(
solo
->
game
),
solo
->
myself
);
if
(
err
!=
TAROT_GAME_OK
)
{
assert
(
0
);
}
}
static
inline
TarotGameError
solo_setup
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
TarotPlayer
myself
,
size_t
n_owners
,
const
TarotPlayer
*
owners
,
TarotPlayer
taker
,
TarotCard
call
)
{
/* To check whether these options are valid, we first run a game
* with noone doing a slam. If we can accept the call, then these
* options are valid. */
TarotGame
check
;
TarotGameEvent
setup_event
;
TarotGameEvent
decl_event
;
size_t
i
;
game_initialize
(
&
check
,
4
,
0
);
if
(
game_duplicate_set_deal
(
&
check
,
n_owners
,
owners
)
!=
TAROT_GAME_OK
)
{
return
TAROT_GAME_INVEV
;
}
if
(
game_duplicate_set_taker
(
&
check
,
taker
)
!=
TAROT_GAME_OK
)
{
return
TAROT_GAME_INVEV
;
}
if
(
game_duplicate_set_call
(
&
check
,
call
)
!=
TAROT_GAME_OK
)
{
return
TAROT_GAME_INVEV
;
}
setup_event
.
t
=
TAROT_SETUP_EVENT
;
setup_event
.
u
.
setup
.
n_players
=
n_players
;
setup_event
.
u
.
setup
.
with_call
=
with_call
;
decl_event
.
t
=
TAROT_DECL_EVENT
;
decl_event
.
u
.
decl
=
0
;
if
(
game_add_event
(
&
check
,
&
setup_event
)
!=
TAROT_GAME_OK
)
{
return
TAROT_GAME_INVEV
;
}
for
(
i
=
0
;
i
<
n_players
;
i
++
)
{
if
(
game_add_event
(
&
check
,
&
decl_event
)
!=
TAROT_GAME_OK
)
{
return
TAROT_GAME_INVEV
;
}
}
assert
(
game_step
(
&
check
)
==
TAROT_DOG
);
/* These options are correct */
if
(
game_add_event
(
&
(
solo
->
game
),
&
setup_event
)
!=
TAROT_GAME_OK
)
{
return
TAROT_GAME_TOOLATE
;
}
if
(
game_duplicate_set_deal
(
&
(
solo
->
game
),
n_owners
,
owners
)
!=
TAROT_GAME_OK
)
{
assert
(
0
);
}
if
(
game_duplicate_set_taker
(
&
(
solo
->
game
),
taker
)
!=
TAROT_GAME_OK
)
{
assert
(
0
);
}
if
(
game_duplicate_set_call
(
&
(
solo
->
game
),
call
)
!=
TAROT_GAME_OK
)
{
assert
(
0
);
}
assert
(
myself
<
n_players
);
solo
->
myself
=
myself
;
solo_advance
(
solo
);
return
TAROT_GAME_OK
;
}
static
inline
TarotGameError
solo_setup_random
(
TarotSolo
*
solo
,
size_t
n_players
,
int
with_call
,
size_t
seed_size
,
const
unsigned
char
*
seed
)
{
struct
yarrow256_ctx
generator
;
unsigned
char
next_seed
[
256
];
TarotPlayer
best_owners
[
78
];
TarotPlayer
best_taker
;
TarotCard
best_call
;
double
best_prediction
=
-
DBL_MAX
;
size_t
i
;
unsigned
int
is_taker
;
unsigned
int
other_player
;
TarotPlayer
myself
;
unsigned
char
random_buffer
[
sizeof
(
unsigned
int
)];
yarrow256_init
(
&
generator
,
0
,
NULL
);
yarrow256_seed
(
&
generator
,
seed_size
,
seed
);
for
(
i
=
0
;
i
<
10
;
i
++
)
{
TarotGameEvent
ev
;
unsigned
int
ev_data
[
78
];
size_t
j
;
TarotPlayer
candidate_owners
[
78
];
TarotPlayer
candidate_taker
;
TarotCard
candidate_call
=
(
TarotCard
)
(
-
1
);
double
candidate_prediction
;
ev
.
n
=
78
;
ev
.
data
=
ev_data
;
yarrow256_random
(
&
generator
,
sizeof
(
next_seed
),
next_seed
);
event_set_deal_all_random
(
&
ev
,
n_players
,
sizeof
(
next_seed
),
next_seed
);
assert
(
ev
.
n
==
78
);
for
(
j
=
0
;
j
<
ev
.
n
;
j
++
)
{
candidate_owners
[
j
]
=
ev
.
data
[
j
];
}
candidate_taker
=
features_strongest_player
(
n_players
,
with_call
,
78
,
candidate_owners
,
&
candidate_prediction
,
&
candidate_call
);
if
(
candidate_prediction
>=
best_prediction
)
{
for
(
j
=
0
;
j
<
78
;
j
++
)
{
best_owners
[
j
]
=
candidate_owners
[
j
];
}
best_taker
=
candidate_taker
;
best_call
=
candidate_call
;
best_prediction
=
candidate_prediction
;
if
(
candidate_prediction
>
0
)
{
i
=
10
;
}
}
}
yarrow256_random
(
&
generator
,
sizeof
(
random_buffer
),
random_buffer
);
memcpy
(
&
is_taker
,
random_buffer
,
sizeof
(
is_taker
));
other_player
=
is_taker
/
2
;
is_taker
=
is_taker
%
2
;
if
(
is_taker
)
{
myself
=
best_taker
;
}
else
{
myself
=
(
other_player
%
n_players
);
}
return
solo_setup
(
solo
,
n_players
,
with_call
,
myself
,
78
,
best_owners
,
best_taker
,
best_call
);
}
static
inline
TarotGameError
solo_add
(
TarotSolo
*
solo
,
const
TarotGameEvent
*
event
)
{