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
4c23e435
Commit
4c23e435
authored
Dec 15, 2019
by
Vivien Kraus
Browse files
Use the solo game for the perceptron bootstrap
parent
c03de337
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
doc/tarot.org
View file @
4c23e435
...
...
@@ -2242,14 +2242,22 @@ able to learn. This perceptron is /static/, because no learning will
be remembered the next time you will call this function.
#+end_deftypefun
#+attr_texinfo: :options {TarotPerceptron *
} tarot_
perceptron
_dup (
const Tarot
Perceptron
*@var{
perceptron
})
#+attr_texinfo: :options {
void} tarot_perceptron_eval (
TarotPerceptron *
@var{
perceptron
},
const Tarot
Game *@var{base}, size_t @var{n}, TarotGameEvent
*
*@var{
candidates}, size_t @var{start}, size_t @var{max}, double *@var{scores
})
#+begin_deftypefun
Return an allocated copy of /perceptron/.
Starting at /base/, for each of the /n/ /candidates/, make a
prediction using /perceptron/. Discard the predictions for the
/start/ first /candidates/, then store the following /max/ predictions
inside /scores/.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_perceptron_
set_
learn
ing_rate
(TarotPerceptron *perceptron
, double learning_rate
)
#+attr_texinfo: :options {void} tarot_perceptron_learn (TarotPerceptron *
@var{
perceptron
}, const TarotGame *@var{base}, const TarotGameEvent *@var{event}, double @var{final_score}
)
#+begin_deftypefun
Change the /learning rate/ in /perceptron/.
Learn that playing /event/ in /base/ leads to the given /final score/.
#+end_deftypefun
#+attr_texinfo: :options {TarotPerceptron *} tarot_perceptron_dup (const TarotPerceptron *@var{perceptron})
#+begin_deftypefun
Return an allocated copy of /perceptron/.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_perceptron_free (TarotPerceptron *@var{perceptron})
...
...
@@ -2258,6 +2266,11 @@ Delete a /perceptron/ allocated by =tarot_perceptron_alloc=,
=tarot_perceptron_dup= or =tarot_perceptron_static_default=.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_perceptron_set_learning_rate (TarotPerceptron *perceptron, double learning_rate)
#+begin_deftypefun
Change the /learning rate/ in /perceptron/.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_perceptron_load (TarotPerceptron *@var{perceptron}, size_t @var{start}, size_t @var{nweights}, const double *@var{parameters})
#+begin_deftypefun
Load the internal /parameters/ (size of /nweights/) into /perceptron/.
...
...
@@ -2274,38 +2287,6 @@ function does all the allocations for you, and simply sets /*n/ to the
total number of parameters and copy them in the newly-allocated
/*data/.
#+end_deftypefun
#+attr_texinfo: :options {double} tarot_perceptron_learn (TarotPerceptron *@var{perceptron}, const TarotGame *@var{state}, const TarotGameEvent *@var{action}, double @var{score})
#+begin_deftypefun
#+attr_texinfo: @deftypefunx {void} tarot_perceptron_learn_game (TarotPerceptron *@var{perceptron}, const TarotGame *@var{full_game})
Teach /perceptron/ that doing the given /action/ in the given /state/
results in the given final /score/. For the =_game= function, learn
from all actions in the /fullgame/. Return the mean update to the
internal parameters. If the return value is /Not a Number/, then it
means that the learning has failed. Try again with a lower learning
rate. If the return value is very close to 0, then the algorithm did
not learn anything from that.
#+end_deftypefun
#+attr_texinfo: :options {double} tarot_perceptron_predict (TarotPerceptron *@var{perceptron}, const TarotGame *@var{state}, const TarotGameEvent *@var{action})
#+begin_deftypefun
Return the score predicted by /perceptron/ for doing the given
/action/ in the given /state/.
#+end_deftypefun
#+attr_texinfo: :options {const TarotGameEvent *} tarot_perceptron_best (TarotPerceptron *@var{perceptron}, const TarotGame *@var{state}, double *@var{score})
#+begin_deftypefun
Return the predicted best action in /state/ according to /perceptron/,
and set /score/ to the predicted score. If nothing is to be played in
/state/, then return =NULL= (in which case /score/ may not be set).
#+end_deftypefun
#+attr_texinfo: :options {double} tarot_perceptron_validate (TarotPerceptron *@var{perceptron}, const TarotGame *@var{validation_game})
#+begin_deftypefun
Analyze the /validation game/ and return the mean error at each event
between what the /perceptron/ would predict and the actual score for
the player.
#+end_deftypefun
** A general interface for AI predictors
#+attr_texinfo: :options {struct} TarotAi
#+begin_deftp
...
...
po/fr.po
View file @
4c23e435
...
...
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: tarot 0.4.2.83-ebdc-dirty\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
"POT-Creation-Date: 2019-12-
07 13:07
+0100\n"
"PO-Revision-Date: 2019-12-
07 13:07
+0100\n"
"POT-Creation-Date: 2019-12-
15 16:44
+0100\n"
"PO-Revision-Date: 2019-12-
15 16:50
+0100\n"
"Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n"
"Language-Team: French\n"
"Language: fr\n"
...
...
@@ -48,7 +48,7 @@ msgstr "Affiche l'information de version et quitte"
#: src/tarot-app/tarot_deal.c:70 src/tarot-app/tarot_mcts.c:88
#: src/tarot-app/tarot_stacking.c:80 src/tarot-app/tarot_features.c:62
#: src/tarot-app/tarot_cnn_features.c:58
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
2
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
3
msgid "version"
msgstr "version"
...
...
@@ -56,7 +56,7 @@ msgstr "version"
#: src/tarot-app/tarot_deal.c:112 src/tarot-app/tarot_mcts.c:136
#: src/tarot-app/tarot_stacking.c:112 src/tarot-app/tarot_features.c:93
#: src/tarot-app/tarot_cnn_features.c:89
#: src/tarot-app/tarot_perceptron_bootstrap.c:13
1
#: src/tarot-app/tarot_perceptron_bootstrap.c:13
2
#, c-format
msgid ""
"%s (libtarot %s)\n"
...
...
@@ -1201,7 +1201,7 @@ msgstr ""
#: src/tarot-app/tarot_deal.c:69 src/tarot-app/tarot_mcts.c:87
#: src/tarot-app/tarot_stacking.c:79 src/tarot-app/tarot_features.c:61
#: src/tarot-app/tarot_cnn_features.c:57
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
1
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
2
msgid "help"
msgstr "aide"
...
...
@@ -1218,7 +1218,7 @@ msgid "no-call-allowed"
msgstr "appel-interdit"
#: src/tarot-app/tarot_deal.c:74 src/tarot-app/tarot_mcts.c:90
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
6
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
7
msgid "seed"
msgstr "graine"
...
...
@@ -1569,24 +1569,24 @@ msgstr "Poignée"
msgid "Discarding"
msgstr "Écart"
#: src/tarot-app/tarot_perceptron_bootstrap.c:6
8
#: src/tarot-app/tarot_perceptron_bootstrap.c:6
9
#, c-format
msgid "
Mean update\tValidation score
\tMaximum weight\n"
msgstr "M
ise à jour moyenne\tScore de validation
\tPoids maximum\n"
msgid "
Fading accumulated metric
\tMaximum weight\n"
msgstr "M
étrique accumulée évanescente
\tPoids maximum\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
3
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
4
msgid "learning-rate"
msgstr "taux-d-apprentissage"
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
4
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
5
msgid "exploration"
msgstr "exploration"
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
5
#: src/tarot-app/tarot_perceptron_bootstrap.c:9
6
msgid "continue"
msgstr "continuer"
#: src/tarot-app/tarot_perceptron_bootstrap.c:11
7
#: src/tarot-app/tarot_perceptron_bootstrap.c:11
8
#, c-format
msgid ""
"Usage: tarot-perceptron-bootstrap [OPTIONS]... [HIDDEN_SIZE]...\n"
...
...
@@ -1609,14 +1609,14 @@ msgstr ""
"- -s GRAINE, --seed=GRAINE : définit la graine aléatoire. GRAINE ne\n"
" peut pas être une chaîne vide.\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:14
3
#: src/tarot-app/tarot_perceptron_bootstrap.c:14
4
#, c-format
msgid "Error: the learning rate should be a positive number, not '%s'.\n"
msgstr ""
"Erreur : le taux d'apprentissage doit être un nombre positif, et pas "
"« %s ».\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:15
5
#: src/tarot-app/tarot_perceptron_bootstrap.c:15
6
#, c-format
msgid ""
"Error: the exploration probability should be a probability (between 0 and "
...
...
@@ -1625,18 +1625,18 @@ msgstr ""
"Erreur : la probabilité d'exploration doit être une probabilité (entre\n"
"0 et 1), et pas « %s ».\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:17
0
#: src/tarot-app/tarot_perceptron_bootstrap.c:17
1
#, c-format
msgid "Error: the seed must not be empty.\n"
msgstr "Erreur : la graine ne doit pas être vide.\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:19
1
#: src/tarot-app/tarot_perceptron_bootstrap.c:19
2
#, c-format
msgid "Error: if you are continuing learning, do not specify the structure!\n"
msgstr ""
"Erreur : si vous continuez l'apprentissage, ne spécifiez pas la structure !\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:20
6
#: src/tarot-app/tarot_perceptron_bootstrap.c:20
7
#, c-format
msgid ""
"Error: the %d-th dimension should be a strictly positive integer, not '%s'.\n"
...
...
src/libtarot/ai/tarot/ai_private_impl.h
View file @
4c23e435
...
...
@@ -126,13 +126,9 @@ ai_perceptron_eval (void *state, const TarotGame * base, size_t n_candidates,
TarotGameEvent
**
candidates
,
size_t
start
,
size_t
max
,
double
*
scores
)
{
size_t
i
;
TarotPerceptron
*
perceptron
=
(
TarotPerceptron
*
)
state
;
for
(
i
=
0
;
i
<
max
&&
i
+
start
<
n_candidates
;
i
++
)
{
scores
[
i
]
=
tarot_perceptron_predict
(
perceptron
,
base
,
candidates
[
i
+
start
]);
}
tarot_perceptron_eval
(
perceptron
,
base
,
n_candidates
,
candidates
,
start
,
max
,
scores
);
}
static
inline
void
...
...
src/libtarot/features/tarot/features_private_impl.h
View file @
4c23e435
...
...
@@ -2069,10 +2069,7 @@ features_strongest_player_try_bid (const TarotGame * game)
candidates
[
1
].
u
.
bid
=
TAROT_PUSH
;
candidates
[
2
].
u
.
bid
=
TAROT_STRAIGHT_KEEP
;
candidates
[
3
].
u
.
bid
=
TAROT_DOUBLE_KEEP
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
scores
[
i
]
=
tarot_perceptron_predict
(
perceptron
,
game
,
pointers
[
i
]);
}
tarot_perceptron_eval
(
perceptron
,
game
,
4
,
pointers
,
0
,
4
,
scores
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
if
(
scores
[
i
]
>
max
)
...
...
@@ -2180,6 +2177,7 @@ predictor_perceptron_select_call (const TarotGame * game, TarotCard * call,
};
TarotNumber
minimum
,
candidate
;
TarotGameEvent
e
;
TarotGameEvent
*
pointer_e
=
&
e
;
TarotPlayer
player
;
int
ret
=
1
;
int
isuit
;
...
...
@@ -2203,7 +2201,8 @@ predictor_perceptron_select_call (const TarotGame * game, TarotCard * call,
assert
(
0
);
}
event_set_call
(
&
e
,
c
);
candidate_score
=
tarot_perceptron_predict
(
perceptron
,
game
,
&
e
);
tarot_perceptron_eval
(
perceptron
,
game
,
1
,
&
pointer_e
,
0
,
1
,
&
candidate_score
);
if
(
candidate_score
>
*
best_score
)
{
*
call
=
c
;
...
...
src/libtarot/perceptron/perceptron.c
View file @
4c23e435
...
...
@@ -92,40 +92,22 @@ tarot_perceptron_save_alloc (const TarotPerceptron * perceptron, size_t *n,
}
}
double
tarot_perceptron_learn
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
,
double
score
)
{
return
perceptron_learn
(
perceptron
,
state
,
action
,
score
);
}
double
tarot_perceptron_learn_game
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
full_game
)
{
return
perceptron_learn_game
(
perceptron
,
full_game
);
}
double
tarot_perceptron_predict
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
)
{
return
perceptron_predict
(
perceptron
,
state
,
action
);
}
const
TarotGameEvent
*
tarot_perceptron_best
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
double
*
score
)
void
tarot_perceptron_learn
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
base
,
const
TarotGameEvent
*
event
,
double
final_score
)
{
return
perceptron_
best
(
perceptron
,
state
,
score
);
perceptron_
learn
(
perceptron
,
base
,
event
,
final_
score
);
}
double
tarot_perceptron_validate
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
validation_game
)
void
tarot_perceptron_eval
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
base
,
size_t
n_candidates
,
TarotGameEvent
**
candidates
,
size_t
start
,
size_t
max
,
double
*
scores
)
{
return
perceptron_validate
(
perceptron
,
validation_game
);
return
perceptron_eval
(
perceptron
,
base
,
n_candidates
,
candidates
,
start
,
max
,
scores
);
}
#include
<tarot/perceptron_private_impl.h>
...
...
src/libtarot/perceptron/tarot/perceptron.h
View file @
4c23e435
...
...
@@ -37,17 +37,35 @@ extern "C"
double
learning_rate
);
/**
* tarot_perceptron_
free
:
* tarot_perceptron_
static_default: (constructor)
:
*/
void
t
arot
_p
erceptron
_free
(
T
arot
P
erceptron
*
perceptron
);
T
arot
P
erceptron
*
t
arot
_p
erceptron
_static_default
(
);
/**
* tarot_perceptron_static_default: (constructor):
* tarot_perceptron_eval:
* @candidates: (array length=n_candidates):
* @scores: (array length=max):
*/
TarotPerceptron
*
tarot_perceptron_static_default
();
void
tarot_perceptron_eval
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
base
,
size_t
n_candidates
,
TarotGameEvent
**
candidates
,
size_t
start
,
size_t
max
,
double
*
scores
);
/**
* tarot_perceptron_learn:
*/
void
tarot_perceptron_learn
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
base
,
const
TarotGameEvent
*
event
,
double
final_score
);
TarotPerceptron
*
tarot_perceptron_dup
(
const
TarotPerceptron
*
perceptron
);
/**
* tarot_perceptron_free:
*/
void
tarot_perceptron_free
(
TarotPerceptron
*
perceptron
);
void
tarot_perceptron_set_learning_rate
(
TarotPerceptron
*
perceptron
,
double
learning_rate
);
...
...
@@ -72,34 +90,6 @@ extern "C"
void
tarot_perceptron_save_alloc
(
const
TarotPerceptron
*
perceptron
,
size_t
*
n
,
double
**
data
);
/**
* tarot_perceptron_learn:
*/
double
tarot_perceptron_learn
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
,
double
score
);
/**
* tarot_perceptron_learn_game:
*/
double
tarot_perceptron_learn_game
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
full_game
);
double
tarot_perceptron_predict
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
);
/**
* tarot_perceptron_best:
* @score: (out):
*/
const
TarotGameEvent
*
tarot_perceptron_best
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
double
*
score
);
double
tarot_perceptron_validate
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
validation_game
);
#ifdef __cplusplus
}
#endif
/* __cplusplus */
...
...
src/libtarot/perceptron/tarot/perceptron_private.h
View file @
4c23e435
...
...
@@ -45,28 +45,25 @@ extern "C"
size_t
start
,
size_t
max
,
double
*
parameters
);
static
size_t
perceptron_encode
(
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
,
size_t
start
,
size_t
max
,
double
*
input
);
static
size_t
perceptron_encode_base
(
const
TarotGame
*
base
,
size_t
start
,
size_t
max
,
double
*
input
);
static
size_t
perceptron_encode_action
(
const
TarotGame
*
base
,
const
TarotGameEvent
*
action
,
size_t
start
,
size_t
max
,
double
*
input
);
static
double
perceptron_learn
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
,
double
score
);
static
double
perceptron_learn_game
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
full_game
);
static
double
perceptron_predict
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
const
TarotGameEvent
*
action
);
static
const
TarotGameEvent
*
perceptron_best
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
double
*
score
);
static
double
perceptron_validate
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
validation_game
);
static
void
perceptron_eval
(
TarotPerceptron
*
perceptron
,
const
TarotGame
*
state
,
size_t
n_candidates
,
TarotGameEvent
**
candidates
,
size_t
start
,
size_t
max
,
double
*
scores
);
#ifdef __cplusplus
}
...
...
src/libtarot/perceptron/tarot/perceptron_private_impl.h
View file @
4c23e435
This diff is collapsed.
Click to expand it.
src/tarot-app/tarot_perceptron_bootstrap.c
View file @
4c23e435
...
...
@@ -21,6 +21,7 @@ static size_t n_hidden_layers;
static
size_t
*
hidden_sizes
;
static
double
learning_rate
;
static
double
exploration
;
static
double
metric
;
static
int
cont
=
0
;
static
struct
yarrow256_ctx
generator
;
...
...
@@ -65,7 +66,7 @@ main (int argc, char *argv[])
tarot_perceptron_load
(
perceptron
,
0
,
n_weights
,
weights
);
free
(
weights
);
}
fprintf
(
stderr
,
_
(
"
Mean update
\t
Validation score
\t
Maximum weight
\n
"
));
fprintf
(
stderr
,
_
(
"
Fading accumulated metric
\t
Maximum weight
\n
"
));
while
(
1
)
{
self_learn
(
perceptron
);
...
...
@@ -210,303 +211,191 @@ Copyright © 2019 Vivien Kraus\nThis is free software; see the source for copyin
}
}
static
TarotGameEvent
*
random_move
(
const
TarotGame
*
game
)
static
inline
void
custom_ai_eval
(
void
*
data
,
const
TarotGame
*
base
,
size_t
n_candidates
,
TarotGameEvent
**
candidates
,
size_t
start
,
size_t
max
,
double
*
scores
)
{
TarotBid
mini_bid
;
int
decl_allowed
;
TarotPlayer
next
;
TarotNumber
mini_call
;
size_t
n_cards
;
size_t
n_prio
;
size_t
n_additional
;
TarotCard
*
prio
;
TarotCard
*
additional
;
if
(
tarot_game_get_hint_bid
(
game
,
&
next
,
&
mini_bid
)
==
TAROT_GAME_OK
)
TarotPerceptron
*
p
=
(
TarotPerceptron
*
)
data
;
tarot_perceptron_eval
(
p
,
base
,
n_candidates
,
candidates
,
start
,
max
,
scores
);
}
static
inline
void
custom_ai_learn
(
void
*
data
,
const
TarotGame
*
base
,
const
TarotGameEvent
*
event
,
double
final_score
)
{
TarotPerceptron
*
p
=
(
TarotPerceptron
*
)
data
;
/* We need to validate before learning */
double
predicted
;
TarotGameEvent
*
evaluated
=
(
TarotGameEvent
*
)
event
;
double
diff
;
static
int
has_metric
=
0
;
tarot_perceptron_eval
(
p
,
base
,
1
,
&
evaluated
,
0
,
1
,
&
predicted
);
diff
=
final_score
-
predicted
;
if
(
diff
<
0
)
{
TarotBid
bids
[]
=
{
TAROT_PASS
,
TAROT_TAKE
,
TAROT_TAKE
,
TAROT_TAKE
,
TAROT_PUSH
,
TAROT_PUSH
,
TAROT_STRAIGHT_KEEP
,
TAROT_DOUBLE_KEEP
};
size_t
position
;
uint8_t
position_data
[
sizeof
(
position
)];
yarrow256_random
(
&
generator
,
sizeof
(
position_data
),
position_data
);
memcpy
(
&
position
,
position_data
,
sizeof
(
position
));
position
%=
(
sizeof
(
bids
)
/
sizeof
(
bids
[
0
]));
if
(
bids
[
position
]
>=
mini_bid
)
{
return
tarot_game_event_alloc_bid
(
bids
[
position
]);
}
else
{
return
tarot_game_event_alloc_bid
(
TAROT_PASS
);
}
diff
=
-
diff
;
}
else
if
(
tarot_game_get_hint_decl
(
game
,
&
next
,
&
decl_allowed
)
==
TAROT_GAME_OK
)
if
(
!
has_metric
)
{
uint8_t
no_decl
;
/* Even in high-exploration scenarios, we want to avoid slam
* declarations. */
yarrow256_random
(
&
generator
,
sizeof
(
no_decl
),
&
no_decl
);
no_decl
%=
16
;
if
(
no_decl
==
0
&&
decl_allowed
)
{
return
tarot_game_event_alloc_decl
(
1
);
}
else
{
return
tarot_game_event_alloc_decl
(
0
);
}
}
else
if
(
tarot_game_get_hint_call
(
game
,
&
next
,
&
mini_call
)
==
TAROT_GAME_OK
)
{
static
const
TarotSuit
suits
[]
=
{
TAROT_HEARTS
,
TAROT_CLUBS
,
TAROT_DIAMONDS
,
TAROT_SPADES
};
uint8_t
suit_i
;
TarotCard
c
;
yarrow256_random
(
&
generator
,
sizeof
(
suit_i
),
&
suit_i
);
suit_i
%=
(
sizeof
(
suits
)
/
sizeof
(
suits
[
0
]));
if
(
tarot_of
(
mini_call
,
suits
[
suit_i
],
&
c
)
!=
0
)
{
assert
(
0
);
}
return
tarot_game_event_alloc_call
(
c
);
metric
=
diff
;
has_metric
=
1
;
}
else
if
(
tarot_game_get_hint_discard_alloc
(
game
,
&
next
,
&
n_cards
,
&
n_prio
,
&
prio
,
&
n_additional
,
&
additional
)
==
TAROT_GAME_OK
)
{
TarotCard
selected
[
78
];
size_t
n_selected
=
0
;
size_t
n_selectable
=
n_prio
;
TarotCard
*
selectable
=
prio
;
size_t
i
;
if
(
n_prio
<
n_cards
)
{
n_selectable
=
n_additional
;
selectable
=
additional
;
for
(
n_selected
=
0
;
n_selected
<
n_prio
;
n_selected
++
)
{
selected
[
n_selected
]
=
prio
[
n_selected
];
}
}
for
(
i
=
n_selected
;
i
<
n_cards
;
i
++
)
{
size_t
position
;
uint8_t
position_data
[
sizeof
(
position
)];
yarrow256_random
(
&
generator
,
sizeof
(
position
),
position_data
);
memcpy
(
&
position
,
position_data
,
sizeof
(
position
));
position
%=
n_selectable
;
selected
[
i
]
=
selectable
[
position
];
selectable
[
position
]
=
selectable
[
--
n_selectable
];
}
free
(
prio
);
free
(
additional
);
return
tarot_game_event_alloc_discard
(
n_cards
,
selected
);
metric
=
0
.
999
*
metric
+
0
.
001
*
diff
;
}
else
if
(
tarot_game_get_hint_card_alloc
(
game
,
&
next
,
&
n_prio
,
&
prio
)
==
TAROT_GAME_OK
)
{
TarotCard
selected
;
size_t
position
;
uint8_t
position_data
[
sizeof
(
position
)];
yarrow256_random
(
&
generator
,
sizeof
(
position
),
position_data
);
memcpy
(
&
position
,
position_data
,
sizeof
(
position
));
position
%=
n_prio
;
selected
=
prio
[
position
];
free
(
prio
);
return
tarot_game_event_alloc_card
(
selected
);
}
assert
(
0
);
return
NULL
;
tarot_perceptron_learn
(
p
,
base
,
event
,
final_score
);
}
static
inline
void
*
custom_ai_dup
(
void
*
data
)
{
/* No memory management: the perceptron is a global variable and we
* need to track its values */
return
data
;
}
static
inline
void
custom_ai_destruct
(
void
*
data
)
{
(
void
)
data
;
}
static
in
t
is_empt
y_game
(
const
TarotGame
*
game
)
static
in
line
TarotGame
*
pla
y_game
(
TarotPerceptron
*
p
,
size_t
n_players
,
int
with_call
)
{
size_t
i_bid
;
size_t
n_bids
;
TarotBid
*
bids
;
if
(
tarot_game_get_bids_alloc
(
game
,
&
n_bids
,
&
bids
)
!=
TAROT_GAME_OK
)
uint8_t
next_seed
[
256
];
TarotAi
*
pure
=
tarot_ai_alloc
(
p
,
custom_ai_eval
,
custom_ai_learn
,
custom_ai_dup
,
custom_ai_destruct
);
TarotAi
*
fuzzy
;
TarotSolo
*
solo
;