tarot.org 102 KB
Newer Older
1
# tarot implements the rules of the tarot game
2
# Copyright (C) 2017, 2018, 2019, 2020  Vivien Kraus
3
4
5

# 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
6
# the Free Software Foundation, version 3 of the License.
7
8
9
10
11
12
13
14
15
#
# 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/>.

16
17
#+title: Tarot {{{version}}}
#+subtitle: for version {{{version}}}, {{{updated}}}
18
19
20
21
22
#+author: Vivien Kraus
#+email: vivien@planete-kraus.eu
#+options: ':t toc:t author:t email:t
#+language: en

23
#+macro: updated (eval (shell-command-to-string "echo -n $(date +%Y-%m-%d)"))
24
#+macro: version (eval (package-version))
25
26
27
28

#+texinfo_filename: tarot.info
#+texinfo_dir_category: Games
#+texinfo_dir_title: tarot: (tarot)
Vivien Kraus's avatar
Vivien Kraus committed
29
#+texinfo_dir_desc: The Amazing Rules Of TAROT
30
#+texinfo_printed_title: Tarot
Vivien Kraus's avatar
Vivien Kraus committed
31
#+PROPERTY: header-args :exports both
32

Vivien Kraus's avatar
Vivien Kraus committed
33
34
#+texinfo: @documentencoding UTF-8

35
This manual is for Tarot (version {{{version}}}, {{{updated}}}).
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

* Gender-neutral pronouns                                          :noexport:
*Change these to whatever you wish*.  I am not sufficiently proud of
my English skills to pick and justify person/per/perself/..., but I
know there is a debate.  Here is my way out: I use org-mode macros to
let the user choose.  I have chosen a default, but you can comment it
out and uncomment another choice.  However, if you don't follow my
default choice, you will need to download emacs to recompile the
manual!  What a great piece of advise :-)

You English-speaking people are lucky, since all major gender
neutrality solutions I know of are just drop-in replacements of
pronouns.

For "she" (I chose that by default, that's maybe the worst solution,
so please change it and install emacs):
#+macro: person she
#+macro: per her
#+macro: pers hers
#+macro: perself herself

For "person" (did I get it right?):
# #+macro: person person
# #+macro: per per
# #+macro: pers pers
# #+macro: perself perself

For "he":
# #+macro: person he
# #+macro: per him
# #+macro: pers his
# #+macro: perself himself

For "they" (please check that with extra care too):
# #+macro: person they
# #+macro: per them
# #+macro: pers theirs
# #+macro: perself themselves
* Texinfo setup                                                    :noexport:
#+texinfo_header: @syncodeindex pg cp
Vivien Kraus's avatar
Vivien Kraus committed
76
77
* HTML setup                                                       :noexport:
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="style.css"/>
78
* Other macros                                                     :noexport:
Vivien Kraus's avatar
Vivien Kraus committed
79
#+macro: iftexinfo (eval (if (org-export-derived-backend-p 'texinfo org-export-current-backend) "@@texinfo:$1@@" "$2"))
80
81
#+macro: math {{{iftexinfo(@math{$1},\($1\))}}}
#+macro: dfn {{{iftexinfo(@dfn{$1},/$1/)}}}
Vivien Kraus's avatar
Vivien Kraus committed
82
#+macro: var {{{iftexinfo(@var{$1},/$1/)}}}
Vivien Kraus's avatar
Vivien Kraus committed
83
#+macro: command {{{iftexinfo(@command{$1},=$1=)}}}
84
#+macro: copyright {{{iftexinfo(@copyright{},\copy)}}}
Vivien Kraus's avatar
Vivien Kraus committed
85
86
87
88
89

#+name: el-package-version
#+BEGIN_SRC emacs-lisp
  (package-version)
#+END_SRC
90
91
92
93
94
95
96
* Copying
  :PROPERTIES:
  :COPYING:  t
  :END:

#+texinfo: @hyphenation{im-ple-men-ta-tion}

97
This manual is for Tarot (version {{{version}}}, {{{updated}}}), an
98
99
100
101
102
103
104
105
106
107
108
109
110
111
implementation for a popular
[fn::at least in France ^.^] card *game* (yes a *game* with players).

Copyright {{{copyright}}} 2017, 2018 Vivien Kraus

#+BEGIN_QUOTE
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts.  A copy of the license is included in the section entitled "GNU
Free Documentation License".
#+END_QUOTE

Vivien Kraus's avatar
Vivien Kraus committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
* About
  :PROPERTIES:
  :DESCRIPTION: About the project
  :END:
Tarot is a framework for playing the tarot card game.  It may have had
an incentive to start after a school assignment (PE46, ECL 2016), but
it has been redesigned and rewritten since then.

The development happens on gitlab: [[https://framagit.org/gugurumbe/tarot]]
** The name
   :PROPERTIES:
   :DESCRIPTION: About the name of the project
   :END:
#+cindex: tail-recursive acronym
Tarot stands for /The Amazing Rules Of TAROT/, which is a recursive
acronym.  However, recursive acronyms usually start with the
recursion, so let me call this a {{{dfn(tail-recursive)}}} acronym
instead.
* The game
The tarot game involves players, cards and declarations in different
steps.  The goal is to take as much points as possible with your team.
In the main phase, every player plays in turn a card, and when all
players have played the /trik taker/ ([[Tricks]]) takes all points and a
new trick starts with the remaining cards.

There are different types of cards.  Some will help you take a trick,
but without giving you many points.  Other will add more points to the
trick, but without helping you much to take it.  More details in [[The
cards]].

But before the players start to play in the main phase, some
preliminary steps occur to set up the teams.

** The players
#+cindex: player
The game can be played for three, four of five players.  The players
play in turn.  The players are somewhat associated to their positions
expressed as north, west, south, southeast and east.  However,
assigning players to positions is out of the scope of the program, as
each player is given as an identifier the number of players who play
before {{{per}}}.  When playing multiple games in a row, the first player
changes after each game.  Specifically, the second player becomes the
first one.

** The cards
#+cindex: card
#+cindex: number (card)
#+cindex: card number
#+cindex: suit (card)
#+cindex: card suit
The game has 78 cards.  There are:
- the {{{dfn(excuse)}}}, which is a special card;
- 77 other cards, that can be decomposed into a {{{dfn(number)}}} and
  a {{{dfn(suit.)}}}

#+cindex: trumps
#+cindex: petit
#+cindex: the world
#+cindex: minor suit
#+cindex: ace
#+cindex: jack
#+cindex: knight
#+cindex: queen
#+cindex: king
#+cindex: face cards
There are five different suits:
- the {{{dfn(trumps)}}}, whose numbers range from one (the
  {{{dfn(petit)}}}) to twenty-one (the {{{dfn(twenty-one)}}}), in
  ascending strength;
- the four traditional, {{{dfn(minor)}}} suits, {{{dfn(hearts)}}},
  {{{dfn(clubs)}}}, {{{dfn(diamonds)}}}, {{{dfn(spades)}}}, with the
  following {{{dfn(numbers)}}}:
  - the {{{dfn(ace)}}} (one), abbreviated =A=;
  - the numbers from two to ten inclusive;
  - the {{{dfn(jack)}}} (eleven), abbreviated =J=;
  - the {{{dfn(knight)}}} [fn::This number does not exist in 54-card
    decks] (twelve), abbreviated =C= [fn::as in French, "cavalier", to
    avoid confusions with the /king/];
  - the {{{dfn(queen)}}} (thirteen), abbreviated =Q=;
  - the {{{dfn(king)}}} (fourteen), abbreviated =K=.  The /jacks/,
    /knights/, /queens/ and /kings/ are called the {{{dfn(face
    cards.)}}}

#+cindex: high trump
As we will see later in [[Tricks]], the {{{dfn(higher)}}} trumps are
(i.e. close to the 21), the more likely to take tricks, whereas the
kings add most value to the tricks (see [[Score]]).

#+cindex: oudler
Together with the /excuse/, the /petit/ and /twenty-one/ are called
the {{{dfn(oudlers.)}}}  Having as many of them as possible is the
most effective way to win a game, as we will see in section [[Score]].

#+cindex: straight cut
If a player does not have cards of the lead suit, then {{{person}}}
can trump.  The earlier {{{person}}} trumps, the best chances
{{{person}}} has to forcibly take face cards from {{{per}}} opponents.
This incurs a strategy for the taker: discard (see [[Dog and discard]])
remaining cards from an under-populated suit to be able to trump from
the first trick, which is called a {{{dfn(straight cut.)}}}

#+cindex: play long
In the other hand, if the taker chooses to play every time the same
suit, {{{person}}} minimizes the chances that the defendant "save" face cards,
since they would only be able to save the face of this long suit, and
then trump when no other face would be to take.  This is called
{{{dfn(play long.)}}}

#+cindex: save petit
As a defendant, if you have the petit, do not hesitate to dispose as
soon as possible of your high trumps, so that you can save the petit
if a fellow defendant plays a better trump.

#+cindex: open
If you are a defendant and play just before the taker, try new suits
to let your partners get a chance to save their faces if the taker
does not trump.  This is called "opening a suit".

#+cindex: petit hunt
#+cindex: hunt (petit)
As discussed in section [[Score]], it is vital to have the petit,
the twenty-one or the excuse.  However, it is very difficult to take
the excuse, and impossible to take the twenty-one, since it is the
strongest card (see [[Tricks]]).  But if one player plays master
trumps one after the other, the opponents will be eventually forced to
play the petit and lose it.  This is called the petit hunt.

** Game steps
#+cindex: game
#+cindex: hand
Each hand (called /game/) is decomposed into /steps/.  After all steps
have been carried out, usually a new game starts.

*** Deal
#+cindex: dog
#+cindex: deal
In this step, cards are dealt among the players.  The remaining hidden
cards are put away for now.  The remaining cards are called the /dog/.
Table [[tblncards]] sums up the number of cards for each player.

#+name: tblncards
#+caption: Cards dealt at the beginning
| Number of players | Number / player | Number / dog |
|-------------------+-----------------+--------------|
|                 3 |              24 |            6 |
|                 4 |              18 |            6 |
|                 5 |              15 |            3 |

Since there are 78 cards, we have {{{math(p * n + d = 78)}}}, where
{{{math(p)}}} is the number of players, {{{math(n)}}} is the number of
cards for each player, and {{{math(d)}}} is the number of cards for
the dog.

Each player can see {{{per}}} cards, and only {{{pers}}}.  No player
can see the cards of the dog.

#+cindex: single petit 
#+cindex: petit sec 
#+cindex: petit imprenable
#+cindex: petit (single) 

Since the petit is a very weak card (see [[The cards]]), if a player is
dealt the /petit/ without any other trumps and without the /excuse/,
the deal is void and should be re-dealt.  This situation is called
{{{dfn(single petit)}}} (or in French {{{dfn(petit sec)}}} or
{{{dfn(petit imprenable)}}}).

#+cindex: client game
#+cindex: server game
#+cindex: deal all

There are two ways of dealing cards: {{{dfn(client)}}} game and
{{{dfn(server)}}} game.  In a /client/ game, only one specific player
receives cards.  In a /server/ game however, all cards are dealt at
once.  So the so-called {{{dfn(deal all)}}} event is the list of the
78 owners (one for each card, in the canonical card order -- see
section [[The cards]]).

*** Bids
#+cindex: bid
#+cindex: outbid
#+cindex: pass
Each player in turn spells out a {{{dfn(bid)}}}, starting with the
first player.  The players can only {{{dfn(outbid)}}}, i.e. spell
out a stronger bid, or {{{dfn(pass.)}}}  Higher bids may incur a
higher risk.  The risks are summed up in table [[tblbids]].

#+cindex: Bids in tarot
#+cindex: pass
#+cindex: take
#+cindex: push
#+cindex: straight keep
#+cindex: double keep
#+cindex: keep (straight keep, double keep)
#+name: tblbids
#+caption: Bids in tarot
| Bid             | Rank | Risk multiplier | Additional risks                         |
|-----------------+------+-----------------+------------------------------------------|
| *pass*          |    0 |               0 | -                                        |
| *take*          |    1 |               1 | -                                        |
| *push*          |    2 |               2 | -                                        |
| *straight keep* |    3 |               4 | No discard (see section [[Dog and discard]]) |
| *double keep*   |    4 |               6 | The dog goes to the defense.             |

To know whether to outbid or to pass is a difficult question, perhaps
the most difficult for the beginners.  Read section [[The cards]] to know
what cards will help you in this task, however here is some general
advice:
- be sure to have enough /trumps/ and enough /high trumps/, typically
  more than the average player;
- be sure to have enough /oudlers/, at least one, or expect to /hunt/
  the petit;
- be sure to have high /face cards/, which means kings or queens with
  their king;
- the more unbalanced number of cards in the /minor suits/, the
  better: if you have no cards of hearts and many of clubs, you will
  be able to /play long/ and /trump/.

#+cindex: taker
#+cindex: defense
There is only one round of bids.  We call the winner the
{{{dfn(taker)}}}, and {{{person}}} will have to take a sufficient
amount of points to win this game.  Unless otherwise decided by the
/call/ (see section [[Call]]), the other players will team up against
{{{per}}} and will be cited as the {{{dfn(defense.)}}}

*** Slam declarations
#+cindex: slam (declaration)
#+cindex: declaration
#+cindex: declarant
If a player thinks {{{person}}} will take all /tricks/ (not
necessarily all /points/), {{{person}}} can {{{dfn(declare slam)}}}
after the bids.  In which case, if {{{person}}} wins the bids,
{{{person}}} will be the first player to play in the /tricks/ phase
(see section [[Tricks]]), becoming the {{{dfn(declarant)}}}, and
{{{person}}} will get a colossal bonus if {{{person}}} succeeds, or a
large penalty if {{{person}}} does not.

There can only be one slam declaration, and it is decided in a round
after the bids.  This is not exactly how a game of tarot works in real
life, since in real life an almost necessary condition to succeed a
slam is to own the twenty-one[fn:: if the 21 is in the /dog/ under a
/straight/ or /double keep/, then it is not necessary.  But how
frequent could that be?] , so there are never any ambiguity.  However
the most realistic way to translate this in the digital world would be
to have a timeout of a few seconds, and the first player to declare
would be the declarant.  However this would be both inconvenient (how
long for the timeout?) and unfair towards the non-bots and those with
a slow internet connection.

The slam results are summed up in table [[tblslam]] in section [[Add
bonuses]].

*** Call
#+cindex: call
#+cindex: partner
In some game variants, mainly the "standard" 5-player variant, the
/taker/ is allowed to play with a {{{dfn(partner.)}}}

After the slam declaration phase, the taker names a card, and the
owner of this card becomes {{{per}}} partner without anyone knowing
(since one cannot speak in a tarot game).  The teams are then revealed
when this specific card is played.  In some specific cases, however,
there is no partner.  In these cases, the taker is at the same time
the partner, and {{{person}}} will not share the reward.  These cases
are summed up in table [[tabdegeneratecallee]].

#+name: tabdegeneratecallee
#+caption: Degenerate cases for the call
| owner     | bid                    | the taker knows | the defense knows |
|-----------+------------------------+-----------------+-------------------|
| the taker | /any/                  | from start      | during the game   |
| the dog   | straight / double keep | at the end      | at the end        |
| the dog   | take, push             | from start      | from start        |

#+cindex: call (rules)
The taker can call:
- a /king/;
- a /queen/, but only if {{{person}}} has all /kings/;
- a /knight/, but only if {{{person}}} has all /kings/ and /queens/;
- a /jack/, but only if {{{person}}} has all /kings/, /queens/ and
  /knights/.

See section [[The cards]] for a definition of these cards.

*** Dog and discard
#+cindex: discard
Once the /taker/ is designated by the bids, after a possible call, and
only if the bid permits it, {{{person}}} takes the dog's cards and
secretly exchanges some or all of these to the same number from
{{{per}}} own game.

#+cindex: discard (rules)
The taker can discard:
- anything but /kings/, /trumps/ and /oudlers/;
- a non-oudler /trump/, if {{{person}}} has no other cards but
  /kings/, /trumps/ and /oudlers/, but in this case {{{person}}} has
  to show the discarded trumps to the other players.

See section [[The cards]] for a definition of these cards.

The {{{dfn(discarded)}}} cards will increase the number of points for
the taker (the discard /belongs to/ the taker).

#+cindex: discard (straight or double keep)
In case of a /straight keep/ or a /double keep/, the taker
does not look at the dog, however the dog's cards count for the
points:
- as the taker's cards in case of a /straight keep/;
- as the defense's cards in case of a /double keep/.

*** Handfuls
#+cindex: show
#+cindex: handful
After the /discard/, the players start to play cards.  However, before
playing her first card, a player can show a number of cards from the
/trumps/ suit of {{{per}}} cards, to increase the risk of the taker
(better bonus if the taker succeeds, worse penalty if {{{person}}}
fails).  There are three sizes for a {{{dfn(handful)}}}, a bigger
handful means a higher risk.  These are summed up in table
[[tblhandfuls]].  In order to show the required number of cards, the
player can show:

#+cindex: handful (rules)
- an owned trump;
- the excuse, if {{{person}}} cannot show another owned trump;
- a discarded trump, if {{{person}}} is the taker and cannot do
  otherwise.

#+name: tblhandfuls
#+caption: Handfuls
| Handful | Extra bonus/penalty | Number of cards (3 players) |  4 |  5 |
|---------+---------------------+-----------------------------+----+----|
| simple  |                 +20 |                          13 | 10 |  8 |
| double  |                 +30 |                          15 | 13 | 10 |
| triple  |                 +40 |                          18 | 15 | 13 |

*** Tricks
    :PROPERTIES:
    :DESCRIPTION: The main phase
    :END:
After the /discard/, in the next phase, the players start to play
their cards in turn.

#+cindex: trick
#+cindex: trick leader
Each {{{dfn(trick)}}} has a {{{dfn(trick leader)}}}, which is the
first player to play in this trick.  For the first trick, this is the
first player, or the /declarant/ in case of a declared slam (see
section [[Slam declarations]]).  There are as many tricks as cards in each
player's hand.

#+cindex: lead card
The first card played in a trick decides the {{{dfn(lead suit.)}}}  If
the first card is a trump, then the lead suit is trumps.  If the first
card is the excuse, then the lead suit is that of the second card
played.

#+cindex: playing cards (rule)
#+cindex: follow suits
#+cindex: trump (verb)
#+cindex: overtrump
#+cindex: undertrump
A player can play:
- any card except for the called suit, with the exception of the
  called card itself, if this is the first trick, the first non-excuse
  card and there has been a call;
- any card of the /lead suit/, if there is one, in which case
  {{{person}}} {{{dfn(follows suits)}}};
- any trump stronger than the strongest so far, if {{{person}}} cannot
  play otherwise ({{{person}}} {{{dfn(trumps)}}}, and more
  specifically {{{person}}} {{{dfn(overtrumps)}}});
- any trump, if {{{person}}} cannot do otherwise ({{{person}}}
  {{{dfn(undertrump)}}});
- any card, if {{{person}}} cannot do otherwise.

#+cindex: trick taker
When all players have played a card, the rules decide of a
{{{dfn(trick taker)}}}, who will take all points in the trick and
become the next /trick leader/.

#+cindex: trick taker (rules)
The trick taker is the player who has played:
- the excuse, if this is the last trick and the excuse owner's team
  has taken all other tricks so far;
- the strongest trump, in case a trump has been played;
- the strongest card of the /lead suit/.

Vivien Kraus's avatar
Vivien Kraus committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
** Duplicaté
#+cindex: duplicaté
Since the fourth variant is quite tough, it is quite common that all
players have to pass.  In order to avoid these situations, the tarot
tournaments use the /duplicaté/ technique: every table plays the same
game, and all players of the same positions can compare themselves to
the other players at the same positions in the other tables.  So the
tournament organizers can decide in advance the deal and the bids (the
taker pushes, the other pass) so that the game is kept interesting.

The other events, such as the slam declarations, dog and discard are
not fixed.  The difference between deal and bids and the others is
that:
- a common deal lets us use duplicaté;
- a definite taker lets the competitors play in teams, with the taker
  of one team playing against three other players of the other team.

In order to extend this scheme to the 5-player variant, we also define
the call a priori, so that we can still make teams.  However, this is
of course not interesting in real life, because if the in-game teams
corresponded to known players, the partner would not be a surprise to
anyone.  In electronic tarot, it is possible to play as teams with
duplicaté, at the condition of fixing the call.
Vivien Kraus's avatar
Vivien Kraus committed
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
** Score
When all tricks have been done, the tricks are reviewed to determine
the reward of the taker.

*** Count card points and oudlers
#+cindex: card owner
#+cindex: owner (card)
#+cindex: card taker
#+cindex: taker (card)
For each card, determine the {{{dfn(owner)}}} (the player who has been
dealt the card, or the taker in case the card has been dealt to the
dog) and the {{{dfn(taker)}}} (the player who took the trick in which
this card has been played, the taker in case the card was in an
undisclosed dog under a /straight keep/, the first defendant under a
/double keep/).

Then, determine the team of the card owner and of the card taker.

Then, refer to table [[tblcardpoints]] and sum up the card points and
oudlers.  For instance, if the excuse was played before the last trick
by the taker and taken by a defendant, then the taker adds 4 points
and gets an oudler.  If the excuse was owned by the defendant but
taken by the taker, {{{person}}} would add 1/2 point but not count it
as an oudler.

#+name: tblcardpoints
#+caption: Card points and oudlers to add
| Card type                  | owner | taker | oudler (owner) | oudler (taker) |
|----------------------------+-------+-------+----------------+----------------|
| king                       |    +0 |  +4.5 | no             | no             |
| queen                      |    +0 |  +3.5 | no             | no             |
| knight                     |    +0 |  +2.5 | no             | no             |
| jack                       |    +0 |  +1.5 | no             | no             |
| the 21                     |    +0 |  +4.5 | no             | yes            |
| petit                      |    +0 |  +4.5 | no             | yes            |
| excuse (last trick) [fn:1] |    +0 |  +4.5 | no             | yes            |
| excuse                     |  +4.0 |  +0.5 | yes            | no             |
| other                      |    +0 |  +0.5 | no             | no             |

[fn:1] Note that the excuse is fully taken as a 4.5-point oudler in
the last trick.  However, in case of a succeeded slam where the excuse
belongs to the slammer, the owner of the excuse is also the taker.  So
it is safe to play the excuse in the last trick (if your team has
taken all other tricks, please plan ahead).

*** Determine whether the taker succeeded {{{per}}} contract

The taker succeeded {{{per}}} contract if {{{person}}} has enough
points for the number of oudlers, see table [[tblpointbar]].

#+name: tblpointbar
#+caption: Number of points to reach for the taker to succeed {{{per}}} contract
| Number of oudlers | Number of points |
|-------------------+------------------|
|                 0 |               56 |
|                 1 |               51 |
|                 2 |               41 |
|                 3 |               36 |

Subtract the number of points to reach.  If the total is negative, the
contract is failed, subtract another 25.  If the total is positive,
add another 25.

Round the total further down in the negative values if the contract is
failed, up if it is succeeded.

#+cindex: petit au bout
If the petit has been taken in the last trick, or the owner of the
petit has taken all tricks, played the petit in the penultimate trick
and played the excuse in the last trick, then the petit is {{{dfn(au
bout)}}} and a bonus or a malus applies.

If the taker's team took the /petit au bout/, add +10.  If the
defense's team took the /petit au bout/, subtract 10.

*** Multiply score
Multiply the total by the taker's bid factor.  See table [[tblbids]].

*** Add bonuses
For each handful, whoever showed it, add the corresponding number of
points if the contract is succeeded, or subtract if the contract is
failed.  See table [[tblhandfuls]] for the number of points.  A positive
bonus is favorable to the taker.

#+cindex: slam (results)
If a team has taken all /tricks/ (not necessarily all /cards/), then a
slam applies.  See table [[tblslam]].  A positive bonus is favorable to
the taker.

#+name: tblslam
#+caption: Bonus / malus for slam results
| Slam declared | slam team | bonus |
|---------------+-----------+-------|
| no            | taker     |  +200 |
| no            | defense   |  -200 |
| yes           | taker     |  +400 |
| yes           | defense   |  -400 |

Note that although the case /the taker declared slam but the defense
took all tricks/ is provided for completeness of the rules, but it is
*highly improbable*: it would mean that the taker declared slam
/without/ the twenty-one, and with an extremely bad luck.

*** End of the game
After a game, all /defendant/ /subtract/ the previously computed
amount from their total, and the /partner/ /adds/ the amount (it may
be the taker {{{perself}}}).  The taker sets {{{per}}} score to the opposite
of the sum of the others, so that the total is null.

Note that in a five-player game with a partner, let {{{math(x)}}} be
the previously computed amount.  Then the defendant have added
{{{math(-x)}}}, the partner {{{math(+x)}}} and the taker
{{{math(+2x.)}}}

A new game can then begin, with the new first player being the
previous second.
Vivien Kraus's avatar
Vivien Kraus committed
639

Vivien Kraus's avatar
Vivien Kraus committed
640
* The tarot program
Vivien Kraus's avatar
Vivien Kraus committed
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
To play a game, you may run the =tarot= graphical user interface.  It
will open a graphical user interface to start playing a game.

The tarot user interface has two different states.  The first state is
to ask for game options, and the second plays with these options.
When a game is finished, it is logged to a certain location on your
system.

** Selecting game options
On the front page, you can choose to play a game for 3, 4 or 5
players.  There is a toggle option for the call, which only applies to
5-player games.

Once you have selected an option, the game starts.

** Playing the game
From top to bottom, the interface displays:
- the summary of your opponents, as a table containing bids, slam
  declarations, the call, and (at the end) the score;
- (optional) an area to select your next option, if it is a slam
  declaration, the discard or a handful;
- the trick, containing the cards of your opponents aligned with their
  names in the table, and your cards under theirs;
- the 'center' area, to display the dog, discard and handfuls;
- your cards;
- the summary of your slam declaration, bid, call and score.

When you are to play a card, the available options are slightly
brighter than your other cards and a click on the card plays it.

If you need to articulate a slam declaration, you may use the buttons
above the cards.

If you need to make a discard or show a handful, then you may use the
top widget and click on the cards that you want to use.  Do not click
on your hand!  Once an appropriate number of cards is selected, the
button to do the action should be enabled.

** Additional user interface elements
When playing a game, you can return to the game selection screen at
any time by pressing the "new" button on the top left corner.

#+cindex: logging
The top-right corner has a menu button with three horizontal lines.
This menu has currently two options: show the information about the
program, and open the file manager program to the directory where the
games are logged.
** Invoking tarot
=tarot= is a Gtk+ application.  It does not provide specific options.
The Gtk+ options are listed when running the =--help= command-line
option.
692
693
694
695

#+BEGIN_SRC shell :eval no
  LANG=C tarot --help
#+END_SRC
Vivien Kraus's avatar
Vivien Kraus committed
696

Vivien Kraus's avatar
Vivien Kraus committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
* Programming with libtarot
Libtarot is the library that you can use in your own program.  In
order to use it, you may use the =pkg-config= configuration file that
is distributed with the program.

** Basic initialization
First, let's see how to initialize and quit the library.

#+BEGIN_SRC C -i :noweb yes :tangle basic-initialization.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>

int
main ()
{
717
  /* The installation directories below are just an example. */
718
  tarot_set_datadir ("/usr/local/share");
719
  if (tarot_init ("/usr/local/share/locale") != 0)
Vivien Kraus's avatar
Vivien Kraus committed
720
721
722
723
724
725
726
727
728
729
730
    {
      fprintf (stderr, "Error: could not initialize libtarot.\n");
      return EXIT_FAILURE;
    }
  printf ("Welcome to libtarot!  The current version running is '%s'\n",
	  tarot_libtarot_version ());
  tarot_quit ();
  return EXIT_SUCCESS;
}
#+END_SRC

731
732
733
734
735
736
737
738
#+attr_texinfo: :options {void} tarot_set_datadir (const char *@var{datadir})
#+begin_deftypefun
Define the directory where the libtarot will look up
architecture-independent data.  This function should be called before
=tarot_init=, otherwise you will not be able to call functions that
were introduced after this function.
#+end_deftypefun

Vivien Kraus's avatar
Vivien Kraus committed
739
740
741
#+attr_texinfo: :options {int} tarot_init (const char *@var{localedir})
#+begin_deftypefun
Initialize libtarot.  The localization will use the /localedir/
742
743
744
directory.  Return 0 on success, or an error code.  This function
should be called before any other libtarot function, except the
functions to set up the installation directories.
Vivien Kraus's avatar
Vivien Kraus committed
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_quit (void)
#+begin_deftypefun
Quit libtarot.
#+end_deftypefun

#+attr_texinfo: :options {const char *} tarot_libtarot_version (void)
#+begin_deftypefun
Query the version of the running libtarot.
#+end_deftypefun

** The players and the cards
Let's demonstrate how to manipulate players and cards.

#+BEGIN_SRC C -i :noweb yes :tangle players-and-cards.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#ifndef LOCALEDIR
#define LOCALEDIR "/usr/share/locale"
#endif /* NOT LOCALEDIR */

int
main ()
{
  TarotCard card;
  TarotNumber number;
  TarotSuit suit;
  char *name;
  char *end;
  static const char *ks = "KS";
  if (tarot_init (LOCALEDIR) != 0)
    {
      fprintf (stderr, "Error: could not initialize libtarot.\n");
      return EXIT_FAILURE;
    }
  if (tarot_of (TAROT_KING, TAROT_SPADES, &card) != 0)
    {
      fprintf (stderr, "Computing the king of spades failed.\n");
      return EXIT_FAILURE;
    }
  if (tarot_decompose (card, &number, &suit) != 0)
    {
      fprintf (stderr, "Could not decompose the king of spades.\n");
      return EXIT_FAILURE;
    }
  assert (number == TAROT_KING && suit == TAROT_SPADES);
  if (tarot_decompose (TAROT_EXCUSE, &number, &suit) == 0)
    {
      fprintf (stderr, "Impossible: decomposing the excuse is an error.\n");
      return EXIT_FAILURE;
    }
  name = tarot_card_to_string_alloc (card);
  assert (strcmp (name, "KS") == 0);
  free (name);
  card = tarot_card_parse (ks, &end);
  if ((const char *) end == ks)
    {
      fprintf (stderr, "Could not parse '%s' at all.\n", ks);
    }
  else if (*end == '\0')
    {
      printf ("%s parsed successfully\n", ks);
    }
  else
    {
      fprintf (stderr, "Trailing garbage: '%s'\n", end);
    }
  tarot_quit ();
  return EXIT_SUCCESS;
}
#+END_SRC

#+attr_texinfo: :options {typedef unsigned int} TarotCard
#+begin_deftp
Each card is represented as a number.  The values range to 0 inclusive
to 78 exclusive.  The constant =TAROT_EXCUSE= refers to the excuse.
#+end_deftp

#+attr_texinfo: :options {typedef unsigned int} TarotNumber
#+begin_deftp
The number of a card, between 1 and =TAROT_KING= or 21 (if the suit is
trumps).  The constants =TAROT_ACE=, =TAROT_JACK=, =TAROT_KNIGHT=,
=TAROT_QUEEN= and =TAROT_KING= provide the ace and the face card
numbers.
#+end_deftp

#+attr_texinfo: :options {enum} TarotSuit
#+begin_deftp
Enumeration of all the possible suits:
- =TAROT_HEARTS=;
- =TAROT_CLUBS=;
- =TAROT_DIAMONDS=;
- =TAROT_SPADES=;
- =TAROT_TRUMPS=;
#+end_deftp

#+attr_texinfo: :options {typedef unsigned int} TarotPlayer
#+begin_deftp
The player ID of someone is simply the number of players that play
before {{{per}}}.
#+end_deftp

#+attr_texinfo: :options {int} tarot_of (TarotNumber @var{number}, TarotSuit @var{suit}, TarotCard *@var{card})
#+begin_deftypefun
#+texinfo: @deftypefunx {int} tarot_decompose (TarotCard @var{card}, TarotNumber *@var{number}, TarotSuit *@var{suit})
Try to compose or decompose /card/ as the /number/ of /suit/.  If this
is not possible, return an error code.  Otherwise, return 0.
#+end_deftypefun

#+attr_texinfo: :options {TarotCard} tarot_string_to_card (const char *@var{text})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotCard} tarot_string_to_card_c (const char *@var{text})
#+texinfo: @deftypefunx {TarotPlayer} tarot_string_to_player (const char *@var{text})
#+texinfo: @deftypefunx {TarotPlayer} tarot_string_to_player_c (const char *@var{text})
Convert /text/ to a card, or a player.  The functions with the =_c=
suffix ignore the current locale, so they are suitable for
serialization, but not for interaction with the user.  The value (-1)
converted to an unsigned int is returned, if the conversion failed.
#+end_deftypefun

#+attr_texinfo: :options {TarotCard} tarot_card_parse (const char *@var{text}, char **@var{end})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotCard} tarot_card_parse_c (const char *@var{text}, char **@var{end})
#+texinfo: @deftypefunx {TarotPlayer} tarot_player_parse (const char *@var{text}, char **@var{end})
#+texinfo: @deftypefunx {TarotPlayer} tarot_player_parse_c (const char *@var{text}, char **@var{end})
This is similar to the =tarot_string_to_*= functions, except now this
is a proper parsing function.  The output parameter /end/ is set to
the first byte that is not part of the player or card representation.
So if it points directly to /text/, then the parsing failed entirely.
If it does not point to an empty string, then this is the suffix that
could not be parsed as part of the card or player.
#+end_deftypefun

#+attr_texinfo: :options {size_t} tarot_card_to_string (TarotCard @var{c}, size_t @var{max}, char *@var{dest})
#+begin_deftypefun
#+texinfo: @deftypefunx {size_t} tarot_card_to_string_c (TarotCard @var{c}, size_t @var{max}, char *@var{dest})
#+texinfo: @deftypefunx {size_t} tarot_player_to_string (TarotPlayer @var{p}, size_t @var{max}, char *@var{dest})
#+texinfo: @deftypefunx {size_t} tarot_player_to_string_c (TarotPlayer @var{p}, size_t @var{max}, char *@var{dest})
#+texinfo: @deftypefunx {char *} tarot_card_to_string_alloc (TarotCard @var{c})
#+texinfo: @deftypefunx {char *} tarot_card_to_string_c_alloc (TarotCard @var{c})
#+texinfo: @deftypefunx {char *} tarot_player_to_string_alloc (TarotPlayer @var{p})
#+texinfo: @deftypefunx {char *} tarot_player_to_string_c_alloc (TarotPlayer @var{p})
Get the string representation of card /c/ or player /p/.  The
functions without an =_alloc= suffix write the representation to
/dest/ (up to /max/ bytes), including the final =NUL= character if
/max/ is not 0, and return the number of bytes needed (except the
final =NUL=).  So you should call this function again with at least
one more byte than the return value in /dest/ / /max/.  The functions
with the =_alloc= suffix allocate the string representation when
returning it.  So you should use =free()= on the return value.

As with the other string related functions, the =_c= part indicates
that the locale is ignored.
#+end_deftypefun
** Adding game events to a game
A game is basically an accumulation of /game events/.  You may add
events to a game, and iterate over the events in a game.

#+BEGIN_SRC C -i :noweb yes :tangle events.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#ifndef LOCALEDIR
#define LOCALEDIR "/usr/share/locale"
#endif /* NOT LOCALEDIR */

int
main ()
{
  TarotGame *game;
  TarotGameEvent *event;
  const TarotGameEvent *read_only_event;
  static const char *deal_card_names[] =
    {
     "10H", "JH", "CH", "QH", "KH",
     "11T", "12T", "13T", "14T", "15T", "16T", "17T", "18T", "19T",
     "EXC"
    };
  TarotCard deal_cards[sizeof (deal_card_names) / sizeof (deal_card_names[0])];
  size_t i;
  TarotGameIterator *iterator;
  TarotCard *dog_cards;
  size_t n_cards;
  
  if (tarot_init (LOCALEDIR) != 0)
    {
      fprintf (stderr, "Error: could not initialize libtarot.\n");
      return EXIT_FAILURE;
    }
  game = tarot_game_alloc ();
  
  /* The game has 5 players, with call */
  event = tarot_game_event_alloc_setup (5, 1);
  if (tarot_game_add_event (game, event) != TAROT_GAME_OK)
    {
      fprintf (stderr, "The game refused to be set up for 5 players, with call!\n");
      return EXIT_FAILURE;
    }
  tarot_game_event_free (event);

  /* Deal the cards */
  for (i = 0; i < sizeof (deal_cards) / sizeof (deal_cards[0]); i++)
    {
      deal_cards[i] = tarot_string_to_card_c (deal_card_names[i]);
      assert (deal_cards[i] != ((TarotCard) (-1)));
    }
  event = tarot_game_event_alloc_deal (tarot_string_to_player_c ("P5"),
				       sizeof (deal_cards) / sizeof (deal_cards[0]),
				       deal_cards);
  if (tarot_game_add_event (game, event) != TAROT_GAME_OK)
    {
      fprintf (stderr, "The game refused to deal cards to P5!\n");
      return EXIT_FAILURE;
    }
  tarot_game_event_free (event);

  /* Auto-reveal */
  if (tarot_game_can_autoreveal_alloc (game, &n_cards, &dog_cards))
    {
      /* This is a game for which we know the dog and we should add it! */
      event = tarot_game_event_alloc_dog (n_cards, dog_cards);
      free (dog_cards);
      if (tarot_game_check_event (game, event))
	{
	  printf ("The game is effectively waiting for the dog.\n");
	}
      if (tarot_game_add_event (game, event) != TAROT_GAME_OK)
	{
	  fprintf (stderr, "Could not auto-reveal the dog!\n");
	  return EXIT_FAILURE;
	}
      tarot_game_event_free (event);
    }

  /* Iterate over the events */
  iterator = tarot_game_iterator (game);
  while ((read_only_event = tarot_game_iterator_next_value (iterator)) != NULL)
    {
      switch (tarot_game_event_type (read_only_event))
	{
	case TAROT_SETUP_EVENT:
	  {
	    size_t n_players;
	    int with_call;
	    if (tarot_game_event_get_setup (read_only_event, &n_players, &with_call) != TAROT_EVENT_OK)
	      {
		fprintf (stderr, "This is not possible.\n");
		return EXIT_FAILURE;
	      }
	    printf ("There is a setup event!  The game has %lu players (with call? %d)\n",
		    n_players, with_call);
	  }
	  break;
	case TAROT_DEAL_EVENT:
	  {
	    TarotCard *cards;
	    TarotPlayer who;
	    char *player_name, *card_1_name, *card_2_name;
	    TarotCard card2;
	    size_t has_card_2;
	    if (tarot_game_event_get_deal_alloc (read_only_event, &who, &n_cards, &cards) != TAROT_EVENT_OK)
	      {
		return EXIT_FAILURE;
	      }
	    if (n_cards < 2)
	      {
		return EXIT_FAILURE;
	      }
	    /* Query only a subset (of size 1... i.e. only one card)
	       from the deal event */
	    if (tarot_game_event_get_deal (read_only_event, &who, &has_card_2, 1, 1, &card2) != TAROT_EVENT_OK)
	      {
		return EXIT_FAILURE;
	      }
	    assert (has_card_2 > 0);
	    assert (card2 == cards[1]);
	    player_name = tarot_player_to_string_alloc (who);
	    card_1_name = tarot_card_to_string_alloc (cards[0]);
	    card_2_name = tarot_card_to_string_alloc (cards[1]);
	    printf ("There is a deal event!  The lucky player %s receives cards %s, %s, ...\n",
		    player_name, card_1_name, card_2_name);
	    free (player_name);
	    free (card_1_name);
	    free (card_2_name);
	    free (cards);
	  }
	  break;
	default:
	  fprintf (stderr, "Unknown game event.\n");
	  return EXIT_FAILURE;
	}
    }
  tarot_game_iterator_free (iterator);
  tarot_game_free (game);
  tarot_quit ();
  return EXIT_SUCCESS;
}
#+END_SRC

#+attr_texinfo: :options {struct} TarotGame
#+begin_deftp
A state that describes a game at a certain point in time.
#+end_deftp

#+attr_texinfo: :options {struct} TarotGameEvent
#+begin_deftp
The state for a complete game event, that you should not be able to
mutate from the public API.
#+end_deftp

#+attr_texinfo: :options {enum} TarotGameEventT
#+begin_deftp
An enumeration of all possible game event types:
- =TAROT_SETUP_EVENT= = 0, to define how many players and whether there is a call;
- =TAROT_DEAL_EVENT=, to give cards to a specific player (we won't
  know the cards of the other players);
- =TAROT_DEAL_ALL_EVENT=, to specify the cards for all players and for
  the dog at once;
- =TAROT_BID_EVENT=, to add a bid;
- =TAROT_DECL_EVENT=, to add a boolean slam declaration;
- =TAROT_CALL_EVENT=, to add a call;
- =TAROT_DOG_EVENT=, to reveal the dog;
- =TAROT_DISCARD_EVENT=, to add a discard (it may be empty, if we
  don't know the taker's cards);
- =TAROT_HANDFUL_EVENT=, to add a handful (it may be empty to assert
  that there are no handfuls for the next player);
- =TAROT_CARD_EVENT=, to add a card to the game.
#+end_deftp

#+attr_texinfo: :options {enum} TarotGameEventError
#+begin_deftp
An enumeration of everything that could go wrong when
manipulating events (see =TarotGameError=, and especially
=TAROT_GAME_iNVEV=, for the validity of events).  It has:
- =TAROT_EVENT_OK= = 0;
- =TAROT_EVENT_ERRTP= when querying an event from an incompatible
  type.
#+end_deftp

#+attr_texinfo: :options {TarotGame *} tarot_game_alloc (void)
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_setup (size_t @var{n_players}, int @var{with_call})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_deal (TarotPlayer @var{myself}, size_t @var{n_cards}, const TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_deal_all (size_t @var{n_owners}, const TarotPlayer *@var{owners})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_deal_all_random (size_t @var{nplayers}, size_t @var{seedsize}, const void *@var{seed})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_bid (TarotBid @var{bid})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_decl (int @var{slam})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_call (TarotCard @var{call})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_dog (size_t @var{n_cards}, const TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_discard (size_t @var{n_cards}, const TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_handful (size_t @var{n_cards}, const TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_alloc_card (TarotCard @var{card})
Vivien Kraus's avatar
Vivien Kraus committed
1113
#+texinfo: @deftypefunx {TarotCounter *} tarot_counter_alloc (void)
Vivien Kraus's avatar
Vivien Kraus committed
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
Allocate a new object.  The return value is never =NULL=, it is not
required to check for allocation failures as the whole program
terminates if the internal memory allocation failed.

The game event allocators are used to instanciate all different game
event types.  The additional =tarot_game_event_alloc_deal_all_random=
deals all cards at random, for a given /nplayers/ number of players,
with /seed/ (with /seedsize/, not 0, number of bytes).  The actual
random generator may vary from one version of libtarot to another.

Please note that the event instanciation cannot fail, even if the game
events are not acceptable for the current game, and /even/ if the game
events are not acceptable for any game.  For instance, you may create
a dog event with 7 cards, or deal more than 78 cards, or the random
seed for the random deal may lead to a /petit sec/.  You should always
check the events against the current game.
#+end_deftypefun

#+attr_texinfo: :options TarotGameEventT tarot_game_event_type (const TarotGameEvent *@var{event})
#+begin_deftypefun
Return the type of /event/.
#+end_deftypefun

#+attr_texinfo: :options TarotGameEventError tarot_game_event_get_setup (const TarotGameEvent *@var{event}, size_t *@var{n_players}, int *@var{with_call})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_deal (const TarotGameEvent *@var{event}, TarotPlayer *@var{myself}, size_t *@var{ncards}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_deal_alloc (const TarotGameEvent *@var{event}, TarotPlayer *@var{myself}, size_t *@var{ncards}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_deal_all (const TarotGameEvent *@var{event}, size_t *@var{nowners}, size_t @var{start}, size_t @var{max}, TarotPlayer *@var{owners})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_deal_all_alloc (const TarotGameEvent *@var{event}, size_t *@var{nowners}, TarotPlayer **@var{owners})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_bid (const TarotGameEvent *@var{event}, TarotBid *@var{bid})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_decl (const TarotGameEvent *@var{event}, int *@var{slam})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_call (const TarotGameEvent *@var{event}, TarotCard *@var{call})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_dog (const TarotGameEvent *@var{event}, size_t *@var{ncards}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_dog_alloc (const TarotGameEvent *@var{event}, size_t *@var{ncards}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_discard (const TarotGameEvent *@var{event}, size_t *@var{ncards}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_discard_alloc (const TarotGameEvent *@var{event}, size_t *@var{ncards}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_handful (const TarotGameEvent *@var{event}, size_t *@var{ncards}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_handful_alloc (const TarotGameEvent *@var{event}, size_t *@var{ncards}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameEventError} tarot_game_event_get_card (const TarotGameEvent *@var{event}, TarotCard *@var{card})
Query /event/.  If its type is correct, then return =TAROT_EVENT_OK=.
Otherwise, return =TAROT_EVENT_ERRTP=.  The /owners/ and /cards/
arguments for the =_alloc=-suffixed functions are allocate with
standard =malloc= (or rather, =xmalloc= in order to protect against
memory allocation failures) and thus should be discarded with =free=
when used.  If this behavior is not wanted, you may use the same
functions with no =_alloc= suffix.  These functions will fill /owners/
/ /cards/ from 0 up to /max/ (or * /nowners/ / * /ncards/ if /max/ is
large enough) with the owners and cards of the event, skipping the
/start/ first players / cards.  Anyway, * /ncards/ and * /nowners/ are
always set to the total number of cards / owners.
#+end_deftypefun

#+attr_texinfo: :options {TarotGameIterator *} tarot_game_iterator (const TarotGame *@var{game})
#+begin_deftypefun Allocate an iterator over the canonical list of
game events in /game/.  This is not always the exact list of events
that built /game/, since game imputation will convert simple =deal=
events to full =deal_all= events, and the empty handful events will be
removed.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_game_copy (TarotGame *@var{dest}, const TarotGame *@var{source})
#+begin_deftypefun
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
#+texinfo: @deftypefunx {TarotGameError} tarot_game_copy_as (TarotGame *@var{dest}, const TarotGame *@var{source}, TarotPlayer @var{player})
Copy game /source/ to allocated game /dest/, optionally restricting it
to what /player/ knows about /source/.

If we do not know the cards of /player/ or we do not know some part of
the discard that /player/ would know, then the second function may
fail.

It cannot fail if the following are met:
- /source/ is a server-side game (we know the full deal);
- /source/ is at the end;
- /source/ is already built from /player/'s experience.
Vivien Kraus's avatar
Vivien Kraus committed
1188
1189
1190
1191
1192
#+end_deftypefun

#+attr_texinfo: :options {TarotGame *} tarot_game_dup (const TarotGame *@var{object})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameEvent *} tarot_game_event_dup (const TarotGameEvent *@var{object})
Vivien Kraus's avatar
Vivien Kraus committed
1193
#+texinfo: @deftypefunx {TarotCounter *} tarot_counter_dup (const TarotCounter *@var{object})
Vivien Kraus's avatar
Vivien Kraus committed
1194
1195
1196
1197
1198
1199
1200
Return a new allocated copy of /object/.
#+end_deftypefun

#+attr_texinfo: :options void tarot_game_free (TarotGame *@var{object})
#+begin_deftypefun
#+texinfo: @deftypefunx {void} tarot_game_iterator_free (TarotGameIterator *@var{object})
#+texinfo: @deftypefunx {void} tarot_game_event_free (TarotGameEvent *@var{object})
Vivien Kraus's avatar
Vivien Kraus committed
1201
#+texinfo: @deftypefunx {void} tarot_counter_free (TarotCounter *@var{counter})
Vivien Kraus's avatar
Vivien Kraus committed
1202
1203
1204
1205
1206
1207
1208
1209
1210
Release /object/ that has been allocated with the corresponding
=tarot_*_alloc= or =tarot_*_iterator= function.
#+end_deftypefun

#+attr_texinfo: :options {enum} TarotGameError
#+begin_deftypefun
An enumeration of errror codes for the game API.  It has:
- =TAROT_GAME_OK= = 0, if the operation succeeded;
- =TAROT_GAME_INVEV=, when adding an invalid or unexpected event;
Vivien Kraus's avatar
Vivien Kraus committed
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
- =TAROT_GAME_NA=, when querying game properties that are not set;
- =TAROT_GAME_TOOLATE=, when we set a duplicaté option after it would
  have been used.
#+end_deftypefun

#+attr_texinfo: :options {TarotGameError} tarot_game_duplicate_set_deal (TarotGame *@var{game}, size_t @var{nowners}, const TarotPlayer *@var{owners})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameError} tarot_game_duplicate_set_taker (TarotGame *@var{game}, TarotPlayer @var{taker})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_duplicate_set_call (TarotGame *@var{game}, TarotCard @var{call})
Set the corresponding duplicaté option in /game/.  Return an error
code.  Be aware that these functions can only catch errors if they are
called just before the duplicaté option takes effect.  Otherwise, the
error will be signaled later in the game, usually by refusing to add
the last event before the duplicaté option would kick in.  This may be
very confusing to debug.

Let us illustrate this behavior by setting a call that would be
invalid later on.

#+BEGIN_SRC C -i :noweb yes :tangle duplicate-a-posteriori.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#ifndef LOCALEDIR
#define LOCALEDIR "/usr/share/locale"
#endif /* NOT LOCALEDIR */

#ifndef DATADIR
#define DATADIR "/usr/share"
#endif /* NOT LOCALEDIR */

#define P1 0
#define P2 1
#define P3 2
#define P4 3
#define P5 4
#define DOG 5

static inline TarotCard
queen_of_diamonds (void)
{
  TarotCard c;
  if (tarot_of (TAROT_QUEEN, TAROT_DIAMONDS, &c) != 0)
    {
      abort ();
    }
  return c;
}

int
main ()
{
  TarotGame *game;
  TarotGameEvent *event;
  static const TarotPlayer owners[78] =
    {
     /* Hearts */
     /* A, 2,  3,   4,   5,   6,   7,   8,   9,   10,  J,   C,   Q,   K */
     P5,  P1,  P5,  P3,  DOG, P2,  P1,  P4,  P3,  P2,  P4,  P5,  P3,  P3,
     /* Clubs */
     DOG, P3,  P5,  P2,  P3,  P1,  P4,  P5,  P4,  P4,  P2,  P2,  DOG, P4,
     /* Diamonds */
     P2,  P1,  P3,  P1,  P4,  P4,  P5,  P3,  P3,  P2,  P4,  P2,  P4,  P3,
     /* Spades */
     P2,  P1,  P4,  P5,  P2,  P1,  P1,  P3,  P3,  P2,  P1,  P2,  P5,  P5,
     /* Trumps */
     P1,  P1,  P1,  P3,  P5,  P2,  P3,  P4,  P2,  P5,  P5,  P4,  P1,  P2,  P4,  P5,  P1,  P1,  P5,  P5,  P4,
     /* Excuse */
     P3
    };
  TarotGameError code;
  int i;

  tarot_set_datadir (DATADIR);  
  if (tarot_init (LOCALEDIR) != 0)
    {
      fprintf (stderr, "Error: could not initialize libtarot.\n");
      return EXIT_FAILURE;
    }
  game = tarot_game_alloc ();

  /* Set the duplicaté options early */
  code = tarot_game_duplicate_set_deal (game, 78, owners);
  assert (code == TAROT_GAME_OK);
  code = tarot_game_duplicate_set_taker (game, P2);
  assert (code == TAROT_GAME_OK);
  /* This is impossible, P2 does not have all kings...  It has none in
   ,* fact. */
  code = tarot_game_duplicate_set_call (game, queen_of_diamonds ());
  /* However, since game has not accepted the deal yet, it has no
   ,* reason to refuse. */
  assert (code == TAROT_GAME_OK); /* !!! */
  
  /* The game has 5 players, with call */
  event = tarot_game_event_alloc_setup (5, 1);
  if (tarot_game_add_event (game, event) != TAROT_GAME_OK)
    {
      abort ();
    }
  tarot_game_event_free (event);

  /* Now the game has jumped to the declaration phase */
  assert (tarot_game_step (game) == TAROT_DECLS);

  /* There are no problems for the first 4 declarations */
  for (i = 0; i < 4; i++)
    {
      event = tarot_game_event_alloc_decl (0);
      if (tarot_game_add_event (game, event) != TAROT_GAME_OK)
	{
	  abort ();
	}
      tarot_game_event_free (event);
    }

  /* Let's check the fifth. */
  event = tarot_game_event_alloc_decl (0);
  /* This event is valid. */
  if (!tarot_game_check_event (game, event))
    {
      abort ();
    }
  /* But we cannot add it! */
  if (tarot_game_add_event (game, event) != TAROT_GAME_INVEV)
    {
      abort ();
    }
  tarot_game_event_free (event);
  /* How is that?  The game has advanced to the call phase though! */
  assert (tarot_game_step (game) == TAROT_CALL);

  /* But the duplicaté call is refused. */
  tarot_game_free (game);
  tarot_quit ();
  return EXIT_SUCCESS;
}
#+END_SRC
Vivien Kraus's avatar
Vivien Kraus committed
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
#+end_deftypefun

#+attr_texinfo: :options {int} tarot_game_check_event (const TarotGame *@var{game}, const TarotGameEvent *@var{event})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameError} tarot_game_add_event (TarotGame *@var{game}, const TarotGameEvent *@var{event})
#+texinfo: @deftypefunx {int} tarot_game_check_card (const TarotGame *@var{game}, TarotCard @var{card}, int *@var{cannotfollow}, TarotSuit *@var{leadsuit}, int *@var{cannotovertrump}, TarotNumber *@var{maxtrump}, int *@var{cannotundertrump})
Check that /event/ can be added to /game/.  =tarot_game_add_event=
actually adds /event/ to /game/ and returns an error code, while
=tarot_game_check_event= simply returns a boolean.

The =tarot_game_check_card= function also checks that /card/ may be
played in /game/, but also computes game information /a posteriori/:
/cannotfollow/ is set to whether /card/ is not of the /leadsuit/, and
so on.
Vivien Kraus's avatar
Vivien Kraus committed
1369
1370
1371
1372
1373
1374
1375

Please note that if you have set duplicaté options on /game/, then
adding a totally acceptable setup event or the last slam declaration
may fail for seemingly no reason, while the check went all right.
This may be due to the duplicaté settings being invalid.  By adding
the event, though, the game has advanced to just before the invalid
duplicaté event.
Vivien Kraus's avatar
Vivien Kraus committed
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
#+end_deftypefun

#+attr_texinfo: :options {int} tarot_game_can_autoreveal (const TarotGame *@var{game}, size_t *@var{ndog}, size_t start, size_t max, TarotCard *@var{dog})
#+begin_deftypefun
#+texinfo: @deftypefunx {int} tarot_game_can_autoreveal_alloc (const TarotGame *@var{game}, size_t *@var{n}, TarotCard **@var{dog})
Check if /game/ should reveal the dog, and /game/ knows the dog.  If
so, query /dog/ with the same semantics as the
=tarot_game_event_get_dog= / =tarot_game_event_get_dog_alloc=
functions.
#+end_deftypefun

#+attr_texinfo: :options {const TarotGameEvent *} tarot_game_iterator_next_value (TarotGameIterator *@var{iterator})
#+begin_deftypefun
Return the data associated to the current position of /iterator/, and
advance /iterator/ to the next position.
#+end_deftypefun
Vivien Kraus's avatar
Vivien Kraus committed
1392
** XML representation of games
Vivien Kraus's avatar
Vivien Kraus committed
1393
#+index: relax-ng
Vivien Kraus's avatar
Vivien Kraus committed
1394
The XML representation of a game is simply the collection of events
Vivien Kraus's avatar
Vivien Kraus committed
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
that constitue it.  Here is the Relax-NG schema for the games:

#+BEGIN_SRC xml -i :eval no :tangle tarot.rng
<?xml version="1.0" encoding="utf-8"?>
<!-- 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, version 3 of the License.

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/>.
-->

<grammar xmlns="http://relaxng.org/ns/structure/1.0"
	 ns="http://planete-kraus.eu/tarot">
  <start>
    <element name="game">
      <zeroOrMore>
	<interleave>
	  <ref name="event" />
	</interleave>
      </zeroOrMore>
    </element>
  </start>
  <define name="event">
    <choice>

      <!-- SETUP -->
      <element name="setup">
	<attribute name="n-players" />
	<attribute name="with-call" />
      </element>

      <!-- DEAL or DEAL-ALL -->
      <element name="deal">
	<attribute name="to" />
	<zeroOrMore>
	  <ref name="card" />
	</zeroOrMore>
      </element>
      <element name="deal-all">
	<zeroOrMore>
	  <ref name="player" />
	</zeroOrMore>
      </element>

      <!-- BID -->
      <element name="bid">
	<attribute name="bid" />
      </element>

      <!-- DECL -->
      <element name="decl">
	<attribute name="slam" />
      </element>

      <!-- CALL -->
      <element name="call">
	<attribute name="card" />
      </element>

      <!-- DOG -->
      <element name="dog">
	<oneOrMore>
	  <ref name="card" />
	</oneOrMore>
      </element>

      <!-- DISCARD -->
      <element name="discard">
	<zeroOrMore>
	  <ref name="card" />
	</zeroOrMore>
      </element>

      <!-- HANDFUL -->
      <element name="handful">
	<zeroOrMore>
	  <ref name="card" />
	</zeroOrMore>
      </element>

      <!-- CARD -->
      <ref name="card" />
    </choice>
  </define>

  <define name="card">
    <element name="card">
      <attribute name="card" />
    </element>
  </define>

  <define name="player">
    <element name="player">
      <attribute name="player" />
    </element>
  </define>
</grammar>
#+END_SRC

The validation for game events is volutarily under-specified, because
it ultimately needs to understand the game rules.

Vivien Kraus's avatar
Vivien Kraus committed
1506
There are no code to export to xml or import from xml as of yet.
Vivien Kraus's avatar
Vivien Kraus committed
1507
** Describing a game
Vivien Kraus's avatar
Vivien Kraus committed
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
#+attr_texinfo: :options {enum} TarotStep
#+begin_deftp
The current step of a game.
- =TAROT_SETUP=;
- =TAROT_DEAL=;
- =TAROT_BIDS=;
- =TAROT_DECLS=;
- =TAROT_CALL=;
- =TAROT_DOG=;
- =TAROT_DISCARD=;
- =TAROT_TRICKS=;
- =TAROT_END=.
#+end_deftp

#+attr_texinfo: :options {struct} TarotCardAnalysis \{ TarotCard @var{card}; int @var{cannot_follow}, int @var{cannot_overtrump}, int @var{cannot_undertrump} \}
#+begin_deftp
Card that has been played, with posterior information.
#+end_deftp

#+attr_texinfo: :options {TarotStep} tarot_game_step (const TarotGame *@var{game})
#+begin_deftypefun
#+texinfo: @deftypefunx {size_t} tarot_game_n_players (const TarotGame *@var{game})
#+texinfo: @deftypefunx {int} tarot_game_with_call (const TarotGame *@var{game})
#+texinfo: @deftypefunx {size_t} tarot_game_n_tricks (const TarotGame *@var{game})
Query the properties of /game/ that are always set: its current step,
the number of players, whether there is a call.
#+end_deftypefun

#+attr_texinfo: :options {TarotGameError} tarot_game_get_next (const TarotGame *@var{game}, TarotPlayer *@var{next})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_main_player (const TarotGame *@var{game}, TarotPlayer *@var{main}) 
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_deal_all (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotPlayer *@var{owners})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_deal_all_alloc (const TarotGame *@var{game}, size_t *@var{n}, TarotPlayer **@var{owners})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_deal_of (const TarotGame *@var{game}, TarotPlayer @var{who}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_deal_of_alloc (const TarotGame *@var{game}, TarotPlayer @var{who}, size_t *@var{n}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_cards (const TarotGame *@var{game}, TarotPlayer @var{who}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_cards_alloc (const TarotGame *@var{game}, TarotPlayer @var{who}, size_t *@var{n}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_bids (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotBid *@var{bids})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_bids_alloc (const TarotGame *@var{game}, size_t *@var{n}, TarotBid **@var{bids})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_taker (const TarotGame *@var{game}, TarotPlayer *@var{taker})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_declarations (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, int *@var{decls})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_declarations_alloc (const TarotGame *@var{game}, size_t *@var{n}, int **@var{decls})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_declarant (const TarotGame *@var{game}, TarotPlayer *@var{declarant})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_call (const TarotGame *@var{game}, TarotCard *@var{card})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_partner (const TarotGame *@var{game}, TarotPlayer *@var{partner})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_dog (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_dog_alloc (const TarotGame *@var{game}, size_t *@var{n}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_full_discard (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_full_discard_alloc (const TarotGame *@var{game}, size_t *@var{n}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_public_discard (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_public_discard_alloc (const TarotGame *@var{game}, size_t *@var{n}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_handful (const TarotGame *@var{game}, TarotPlayer @var{p}, int *@var{size}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotCard *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_handful_alloc (const TarotGame *@var{game}, TarotPlayer @var{p}, int *@var{size}, size_t *@var{n}, TarotCard **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_current_trick (const TarotGame *@var{game}, size_t *@var{current})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_lead_suit (const TarotGame *@var{game}, size_t @var{i_trick}, TarotSuit *@var{lead_suit})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_max_trump (const TarotGame *@var{game}, size_t @var{i_trick}, TarotNumber *@var{max_trump})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_trick_leader (const TarotGame *@var{game}, size_t @var{i_trick}, TarotPlayer *@var{leader})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_trick_taker (const TarotGame *@var{game}, size_t @var{i_trick}, TarotPlayer *@var{taker})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_trick_cards (const TarotGame *@var{game}, size_t @var{i_trick}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, TarotGameCardAnalysis *@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_trick_cards_alloc (const TarotGame *@var{game}, size_t @var{i_trick}, size_t *@var{n}, TarotGameCardAnalysis **@var{cards})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_points_in_trick (const TarotGame *@var{game}, size_t @var{i_trick}, unsigned int *@var{halfpoints}, unsigned int *@var{oudlers})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_scores (const TarotGame *@var{game}, size_t *@var{n}, size_t @var{start}, size_t @var{max}, int *@var{scores})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_scores_alloc (const TarotGame *@var{game}, size_t *@var{n}, int **@var{cards})
Vivien Kraus's avatar
Vivien Kraus committed
1571
Query a property of /game/ that may or may not be relevant at evry
Vivien Kraus's avatar
Vivien Kraus committed
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
moment of the game.  Return =TAROT_GAME_OK= on success, or
=TAROT_GAME_NA= if it is not relevant.

=tarot_game_get_main_player= queries the /main/ player that have been
dealt cards; in case of a deal for all players it is not set.

Some properties are still set to a meaningful value, even if the
return value is =TAROT_GAME_NA=, such as the /taker/ for
=tarot_game_get_taker= and =tarot_game_get_trick_taker=.
#+end_deftypefun

#+attr_texinfo: :options {TarotGameError} tarot_game_get_hint_bid (const TarotGame *@var{game}, TarotPlayer *@var{player}, TarotBid *@var{mini})
#+begin_deftypefun
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_decl (const TarotGame *@var{game}, TarotPlayer *@var{player}, int *@var{allowed})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_call (const TarotGame *@var{game}, TarotPlayer *@var{player}, int *@var{mini})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_discard (const TarotGame *@var{game}, TarotPlayer *@var{player}, size_t *@var{n_cards}, size_t *@var{n_prio}, size_t @var{start_prio}, size_t @var{max_prio}, TarotCard *@var{prio}, size_t *@var{n_additional}, size_t @var{start_additional}, size_t @var{max_additional}, TarotCard *@var{additional})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_discard_alloc (const TarotGame *@var{game}, TarotPlayer *@var{player}, size_t *@var{n_cards}, size_t *@var{n_prio}, TarotCard **@var{prio}, size_t *@var{n_additional}, TarotCard **@var{additional})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_handful (const TarotGame *@var{game}, TarotPlayer *@var{player}, size_t *@var{n_simple}, size_t *@var{n_double}, size_t *@var{n_triple}, size_t *@var{n_prio}, size_t @var{start_prio}, size_t @var{max_prio}, TarotCard *@var{prio}, size_t *@var{n_additional}, size_t @var{start_additional}, size_t @var{max_additional}, TarotCard *@var{additional})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_handful_alloc (const TarotGame *@var{game}, TarotPlayer *@var{player}, size_t *@var{n_simple}, size_t *@var{n_double}, size_t *@var{n_triple}, size_t *@var{n_prio}, TarotCard **@var{prio}, size_t *@var{n_additional}, TarotCard **@var{additional})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_card (const TarotGame *@var{game}, TarotPlayer *@var{player}, size_t *@var{n_playable}, size_t @var{start_playable}, size_t @var{max_playable}, TarotCard *@var{playable})
#+texinfo: @deftypefunx {TarotGameError} tarot_game_get_hint_card_alloc (const TarotGame *@var{game}, TarotPlayer *@var{player}, size_t *@var{n_playable}, TarotCard **@var{playable})
Query what can happen next in /game/.  The next /player/ to play is
also set.
#+end_deftypefun

Vivien Kraus's avatar
Vivien Kraus committed
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
** The card counter

#+attr_texinfo: :options {struct} TarotCounter
#+begin_deftp
In order to provide high-level features for machine learning, we use a
/card counter/, which is a device that keeps track of who can have
what cards.  Because it requires extra memory and computing, it is not
part of the =TarotGame= API.
#+end_deftp

#+attr_texinfo: :options {void} tarot_counter_copy (TarotCounter *@var{dest}, const TarotCounter *@var{source})
#+begin_deftypefun
Copy /source/ to /dest/.
#+end_deftypefun

#+attr_texinfo: :options {size_t} tarot_counter_n_cards_remaining (const TarotCounter *@var{counter}, TarotPlayer @var{player})
#+begin_deftypefun
#+texinfo: @deftypefunx {size_t} tarot_counter_n_cards_doscard (const TarotCounter *@var{counter})
Query how many cards are in /player/'s hand or in the dog / discard.
#+end_deftypefun

#+attr_texinfo: :options {int} tarot_counter_may_own (const TarotCounter *@var{counter}, size_t @var{n}, const TarotPlayer *@var{owners}, TarotCard @var{card})
#+begin_deftypefun
#+texinfo: @deftypefunx {int} tarot_counter_may_be_in_doscard (const TarotCounter *@var{counter}, TarotCard @var{card})
Return whether any of the /n/ /owners/ (or the dog or discard for
=tarot_counter_may_be_in_doscard=) may own /card/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_counter_load_from_game (TarotCounter *@var{counter}, const TarotGame *@var{game})
#+begin_deftypefun
Process all information of /game/ and store it in /counter/.
#+end_deftypefun

#+attr_texinfo: :options {enum} TarotImputationError
#+begin_deftp
An enumeration for the status of the =tarot_counter_and_game_impute=
function.  It is either:
1. =TAROT_IMPUTATION_OK= = 0 if the imputation succeeded;
2. =TAROT_IMPUTATION_FAILED= = 1 otherwise.
#+end_deftp

#+attr_texinfo: :options {TarotImputationError} tarot_counter_and_game_impute (const TarotCounter *@var{counter}, TarotGame *@var{game}, size_t @var{n}, const void *@var{seed})
#+begin_deftypefun
Try to infer the cards of all players and those of the dog by using
the information in /counter/.  After this function call, either the
operation succeeded and now /game/ knows all the cards of everyone
(and /counter/ is updated to keep in sync), or the function fails.

This operation uses the /n/ bytes of /seed/ to initialize the
pseudo-random number generator.
#+end_deftypefun
Vivien Kraus's avatar
Vivien Kraus committed
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
** The libtarot test suite
In this section we present the test suite to show different aspects of
libtarot.

*** You cannot deal the petit as the only trump to a player
If a player has the petit as the only trump (and does not posess the
excuse), then the deal is not valid.

#+BEGIN_SRC C -i :noweb yes :tangle petit-sec.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#ifndef LOCALEDIR
#define LOCALEDIR "/usr/share/locale"
#endif /* NOT LOCALEDIR */

int
main ()
{
  TarotGame *game;
  size_t i;
  static const char *card_names[] =
    {
     "1T",
     "KH", "QH", "CH", "JH", "10H", "9H", "8H", "7H", "6H", "5H", "4H", "3H", "2H", "AH",
     "KC", "QC", "CC"
    };
  TarotCard cards[sizeof (card_names) / sizeof (card_names[0])];
  TarotGameEvent *event;
  if (tarot_init (LOCALEDIR) != 0)
    {
      fprintf (stderr, "Error: could not initialize libtarot.\n");
      return EXIT_FAILURE;
    }
  game = tarot_game_alloc ();
  for (i = 0; i < sizeof (cards) / sizeof (cards[0]); i++)
    {
      cards[i] = tarot_string_to_card_c (card_names[i]);
      assert (cards[i] != ((TarotCard) (-1)));
    }
  event = tarot_game_event_alloc_deal (1, sizeof (cards) / sizeof (cards[0]), cards);
  if (tarot_game_add_event (game, event) == TAROT_GAME_OK)
    {
      fprintf (stderr, "Error: the petit sec as accepted.\n");
      return EXIT_FAILURE;
    }
  tarot_game_event_free (event);
  /* Also give the excuse */
  cards[1] = TAROT_EXCUSE;
  event = tarot_game_event_alloc_deal (1, sizeof (cards) / sizeof (cards[0]), cards);
  if (tarot_game_add_event (game, event) != TAROT_GAME_OK)
    {
      fprintf (stderr, "Error: the petit sec was refused for wrong reasons.\n");
      return EXIT_FAILURE;
    }
  tarot_game_event_free (event);
  tarot_game_free (game);
  tarot_quit ();
  return EXIT_SUCCESS;
}
#+END_SRC

** Higher-level language bindings -- introducing the semantic API
The semantic API is an XML file describing the API.  It is available
through pkg-config:

#+BEGIN_SRC shell
  pkg-config --variable=semantic_api libtarot
#+END_SRC

The API has a few concepts.  The top-level element is named 'api', but
it does not carry useful information.  Inside this API, you may find
exactly one namespace, with an attribute, =name=.  =name= is exactly
"tarot".

Under the namespace, you find:
- the =typedef='s, like =TarotCard= and such;
- the =constant='s, like =TAROT_EXCUSE=;
- the =enumeration='s, like =TarotBid=;
- the =class='es, like =TarotGame=;
- the =struct='s, like =TarotGameCardAnalysis=;
- and the top-level function, named =method=.

Inside each type, you will also find methods applicable to that type.
A method is composed of:
- the name of the C function to call;
- a =return= type;
- an optional =instance= parameter (otherwise, this is a top-level
  function, or a static method);
- some =parameter='s.
1745
* Machine learning with tarot
1746
1747
1748
1749
1750
1751
There are support for different paradigms of machine learning in
tarot.  The library provides a set of hand-crafted high-level
features, and tensor-shaped features for use with a Convolutional
Neural Network.

The high level features that way: for each game to learn, we can
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
extract some game features.  The features are, for instance, how many
trumps we have, whether a partner may still play, and so on.

Each move for each player implements one or multiple strategies.  For
instance, one strategy is "play the called suit", or "take the trick",
or how many points you play.  This shows that the strategy may not be
binary.

Then, we record the final score for each player.  So, for a given
strategy, we learn how many points we might get in the given game
state.  It is important to consider the interactions between features:
for instance, we should not have the same model for all game variants.

Please note that these functions are tailored for machine learning:
they are redundent with the rest of the API, and they never fail, but
the value may be meaningless.  Both features and strategies are only
meaningful if the next player is the /main/ player of the given game
(i.e. we know {{{per}}} cards), and there is uncertainty (we don't
know the cards of the other players).  If we know, the learning will
not be very useful because the data set will not be taken from the
same distribution as the test set.

1774
1775
1776
1777
1778
1779
1780
On the other hand, the library also provides support for tensor-shaped
data.
- The individual pages encode game steps.  The first page is for the
  deal, the second page for the bids, the third is for the slam
  declarations, then there is an optional page for the call (if the
  game variant allows it), then a page for the dog (possibly filled
  with zeros), likewise for the next page for the discard, then a page
Vivien Kraus's avatar
Vivien Kraus committed
1781
1782
1783
1784
1785
1786
1787
  for all handfuls, and then a page for each trick.  In order to have
  the same number of pages for all variants, the remaining pages are
  padded with zeros until there are 32 pages.
- Each page contains a line for each player.  The first line is for
  player number 0, not for the first player in the trick.  No line is
  allocated for the dog.  In order to have the same number of rows for
  each game variant, the rows are repated until there are 6 rows.
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
- Each page contains a number of columns.  The first 8 columns encode
  the event type as one-hot: all columns are set to 0, except the
  column encoding the actual type which is set to 1.  The types are in
  this order: deal, bid, declaration, call, dog, discard, handful,
  card.  The type is encoded on each relevant line, i.e. on the line
  corresponding to the player adding that event.  So for instance, on
  the call page, only the call event column is set, and only for the
  taker.  The next column is for the slam declaration: 0 for no slam
  or not decided yet (it is possible to know which applies, by looking
  in the 'declaration' type column: if it is set to 1, then no slam is
  declared, otherwise the player has not decided yet).  Then, 5
  columns encode the bid: pass, take, push, straight or double keep.
  Finally, the 78 other columns encode the card.  In the case that the
  event involves a set of cards, each corresponding card is set at 1
  for the relevant player (the player who has been dealt the cards,
  the player who has shown the handful, the taker for the dog and
  discard (if known), ...).  So, there are 8 + 1 + 5 + 78 = 92 column.

1806
1807
** The features
All features are actually redundant with a clever use of the
Vivien Kraus's avatar
Vivien Kraus committed
1808
/TarotGame/ and /TarotCounter/.  However, this interface will
1809
1810
highlight useful high-level features.  These are the list of
implemented high-level features that you may want to use:
1811

1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
#+attr_texinfo: :options {void} tarot_features_variant (const TarotGame *@var{game}, size_t *@var{nplayers}, int *@var{withcall})
#+begin_deftypefun
Query the game variant used in /game/: the number of players,
/nplayers/, and whether there is a call, /withcall/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_position (const TarotGame *@var{game}, size_t *@var{trick}, size_t *@var{position})
#+begin_deftypefun
Get our /position/ in the /game/, i.e. the number of players that have
already "played" in the given step.  During the tricks phase, this is
the number of players that have played before us in the current
/trick/.  /trick/ is set to the number of tricks played so far.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_partner_known (const TarotGame *@var{game}, int *@var{known})
#+begin_deftypefun
Check whether the taker's partner is /known/ in /game/.  If there is
no call, then the partner is considered known.
#+end_deftypefun

We also have some function to give interesting statistics about your
game.  The statistics are counted with the dog, if you're the taker
and are set to discard.

#+attr_texinfo: :options {void} tarot_features_count_faces (const TarotGame *@var{game}, size_t *@var{nkings}, size_t *@var{nmarriages}, size_t *@var{nextendedmarriages}, size_t *@var{nqueens}, size_t *@var{nkings})
#+begin_deftypefun
Query some statistics about the face cards in /game/: the number of
kings /nkings/, the number of queens, /nqueens/, the number of knights
/nknights/, and the combination of these: the number of marriages
/nmarriages/, i.e. the number of suits where we own the king and the
queen, and the number of extended marriages /nextendedmarriages/,
i.e. the number of suits for which we own the king, the queen and the
knight.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_count_minor (const TarotGame *@var{game}, size_t *@var{nshortest}, size_t *@var{nsecondshortest}, size_t *@var{nsecondlongest}, size_t *@var{nlongest})
#+begin_deftypefun
Query some statistics about the suits that you own in /game/.  The
/longest/ suit is the suit for which you have most cards.  The
/shortest/ is the suit for which you have least.

This notion is important, since calling a suit will be translated as a
strategy of calling the shortest, the second shortest and so on.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_count_oudlers (const TarotGame *@var{game}, int *@var{haspetit}, int *@var{hasexcuse}, int *@var{hastwentyone})
#+begin_deftypefun
Query whether you have the /petit/, /excuse/ or /twentyone/ in /game/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_count_trumps (const TarotGame *@var{game}, size_t *@var{ntrumps}, TarotNumber *@var{max}, TarotNumber *@var{min}, TarotNumber *@var{q1}, TarotNumber *@var{q3}, TarotNumber *@var{median})
#+begin_deftypefun
Count your trumps in /game/.  Count the actual number as /ntrumps/,
but also compute the /max/-imum and /min/-imum, and also the first and
third quartiles, /q1/ and /q3/, and the /median/.

As you know, the first and third quartiles and the median may have
multiple valid values.  Here we choose the smallest.
#+end_deftypefun

*** Features that are only meaningful for bidding
#+attr_texinfo: :options {void} tarot_features_bid_minimum (const TarotGame *@var{game}, TarotBid *@var{minimum})
#+begin_deftypefun
Query the /minimum/ bid to outbid in /game/.
#+end_deftypefun

*** Features for playing
Now there are quite a lot of features when playing.  This list will of
course grow when discovering new interesting features.

#+attr_texinfo: :options {void} tarot_features_team (const TarotGame *@var{game}, int *@var{attack}, int *@var{defence})
#+begin_deftypefun
Check if the next player in /game/ is an /attacker/ or a /defendant/.
If we don't know, then set both to 0.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_trick_players (const TarotGame *@var{game}, size_t *@var{played}, size_t *@var{chances})
#+begin_deftypefun
Look at the current trick in /game/, and count how many players have
/played/, and how many /chances/ our team has, i.e. the number of
allies playing after the last opponent.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_minor_suit (const TarotGame *@var{game}, int *@var{calledsuit}, size_t *@var{timeslead}, size_t *@var{remainingcards}, size_t *@var{remainingpoints}, int *@var{allymaybemaster}, int *@var{ennemymaybemaster})
#+begin_deftypefun
Analyze the suit lead in the current trick in /game/.  Check if this
is the /called suit/, how many times it has been /lead/ previously,
how many of the suit are /remaining/ in total, how many /points/ are
remaining, and whether an /ally/ or an /ennemy may be the master/, if
we assume that noone will trump.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_trump (const TarotGame *@var{game}, size_t *@var{nremaining}, int *@var{allymaybemaster}, int *@var{ennemymaybemaster})
#+begin_deftypefun
Analyze the trumps in the current trick of /game/.  Count how many of
them are /remaining/, and whether the master may be an /ally/ (yes or
no) or an /ennemy/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_features_points (const TarotGame *@var{game}, size_t *@var{nhalfpoints}, size_t *@var{noudlers})
#+begin_deftypefun
Count how many /half-points/ and /oudlers/ there are in the current
trick in /game/.  Please note that in this context, the excuse counts
as 1/2 point, and not an oudler.  This is the number of points that
can change hands if the taker changes.
#+end_deftypefun
** Implemented strategies
The strategies are computed from a game (optionally with a counter)
and an event _that has not occured yet in the game_.  Just like for
the features, there is a perfect redundancy with the =Game=, =Counter=
and =GameEvent= APIs.

#+attr_texinfo: :options {void} tarot_strategy_bid (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, int *@var{pass}, int *@var{take}, int *@var{push}, int *@var{straightkeep}, int *@var{doublekeep})
#+begin_deftypefun
Query the strategy implemented by playing the bid /event/ in /game/.
This function is very simple, it just encodes the bid in /event/.
More specifically, /pass/ is always set to 1.  If the player takes,
then /pass/ and /take/ are set to 1.  If {{{person}}} pushes, then
/pass/, /take/ and /push/ are set to 1.  And so on.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_outbid (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, int *@var{outbid})
#+begin_deftypefun
Compute the /outbid/ implemented by playing /event/ in /game/.  The
value is positive if we outbid, negative if we pass.  It can be zero
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_call_by_length (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, int *@var{shortest}, int *@var{second_shortest}, int *@var{second_longest}, int *@var{longest})
#+begin_deftypefun
Check if we are calling the /shortest/, /second shortest/, /second
longest/ or /longest/ minor suit by adding event /event/ to /game/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_call_myself (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, int *@var{self})
#+begin_deftypefun
Check whether the taker would call {{{perself}}} for sure by adding
event /event/ to /game/.  Obviously the case when the called card is
in the dog does not count as deliberately calling oneself.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_call_marriage (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, int *@var{will_own_marriage})
#+begin_deftypefun
Check if the taker /will own the marriage/ of the called card.  This
is true in exactly two cases:
1. The taker calls the king of a suit for which {{{person}}} has the
   queen;
2. The taker calls the queen of a suit for which {{{person}}} has the
   king.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_discard_save (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, int *@var{queens}, int *@var{knights}, int *@var{jacks})
#+begin_deftypefun
Count the number of face cards (number of /queens/, number of
/knights/ and number of /jacks/) that the taker has saved by
discarding /event/ in /game/.  A saved card is a card for which there
exists a higher card of the same suit that {{{person}}} does not own
nor has called.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_discard_junk (const TarotGame *@var{game}, const TarotGameEvent *@var{discard}, int *@var{lesser})
#+begin_deftypefun
Query the purity of the /discard/ in /game/.  This is the number of
/lesser/ cards that are left in the taker's hand and for which one
higher minor card of the same suit has been discarded.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_discard_by_length (const TarotGame *@var{game}, const TarotGameEvent *@var{discard}, int *@var{shortest}, int *@var{secondshortest}, int *@var{secondlongest}, int *@var{longest})
#+begin_deftypefun
Check if the /discard/ in /game/ aggraves the imbalance of minor suit
in the taker's hand.  Count how many cards are discarded from the
/shortest/, /second shortest/, /second longest/ and /longest suit/ of
{{{per}}} hand with respect from the hand with the dog.
#+end_deftypefun

The next strategies are all for playing.  We analyze the /card/ of the next player in /game/.

#+attr_texinfo: :options {void} tarot_strategy_lead (const TarotGame *@var{game}, const TarotGameEvent *@var{card}, int *@var{calledsuit}, size_t *@var{suitlength}, size_t *@var{ntimeslead}, int *@var{trumps})
#+begin_deftypefun
Check if we lead the /called suit/, check the /length/ of the lead
suit (how many cards of that suit we have), count /how many times this
suit has been lead before/, and whether it is actually /trumps/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_purity (const TarotGame *@var{game}, const TarotGameEvent *@var{event}, size_t *@var{nsmallerkept}, size_t *@var{ngreaternonfacekept}, size_t *@var{npointskept}, size_t *@var{ngreaterkept})
#+begin_deftypefun
Assess the purity of the card played: how many strictly /smaller/,
/greater/ (except /faces/, or counting faces) cards we keep in our
hand, and how many /points/ that makes.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_excuse (const TarotGame *@var{game}, const TarotGameEvent *@var{card}, int *@var{excuse})
#+begin_deftypefun
Check if we are playing the /excuse/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_trump_master (const TarotGame *@var{game}, const TarotGameEvent *@var{card}, int *@var{master}, int *@var{obvious})
#+begin_deftypefun
2009
2010
2011
2012
2013
Check if this trump is actually a /master/ trump (noone has been or
will be able to play better in that trick) and an /obviously/ master
trump, which is to say that all stronger trumps have already been
played.  This distinction is useful because if we play the 20 while
keeping the 21, our allies won't know that we have the 21.
2014
2015
2016
2017
2018
2019
2020
2021
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_strategy_play_points (const TarotGame *@var{game}, const TarotGameEvent *@var{card}, int *@var{halfpoints}, int *@var{oudler})
#+begin_deftypefun
Count how many /half points/ our card is worth (the excuse is worth 9)
and whether it is an /oudler/.
#+end_deftypefun

Vivien Kraus's avatar
Vivien Kraus committed
2022
2023
2024
2025
** Online learning with a multi-layer perceptron
Static learning models are great for the AI, because we learn them at
compile time.  However, it may be a good addition to have a learning
algorithm that is able to learn to know a player.
2026

Vivien Kraus's avatar
Vivien Kraus committed
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
#+attr_texinfo: :options {struct} TarotPerceptron
#+begin_deftp
A model that is capable of being learnt in the course of the program
(at the end of a finished game).
#+end_deftp

#+attr_texinfo: :options {TarotPerceptron *} tarot_perceptron_alloc (size_t @var{nhiddenlayers}, const size_t *@var{hiddensizes}, double @var{learningrate})
#+begin_deftypefun
Allocate a new perceptron with the given hyperparameters: the /number
of hidden layers/, their corresponding /sizes/, and the /learning
rate/.
#+end_deftypefun

2040
2041
2042
2043
2044
2045
2046
#+attr_texinfo: :options {TarotPerceptron *} tarot_perceptron_static_default ()
#+begin_deftypefun
Allocate and return the best perceptron that the maintainer has been
able to learn.  This perceptron is /static/, because no learning will
be remembered the next time you will call this function.
#+end_deftypefun

2047
#+attr_texinfo: :options {void} tarot_perceptron_eval (TarotPerceptron *@var{perceptron}, const TarotGame *@var{base}, size_t @var{n}, TarotGameEvent **@var{candidates}, size_t @var{start}, size_t @var{max}, double *@var{scores})
Vivien Kraus's avatar
Vivien Kraus committed
2048
#+begin_deftypefun
2049
2050
2051
2052
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/.
Vivien Kraus's avatar
Vivien Kraus committed
2053
2054
#+end_deftypefun

2055
#+attr_texinfo: :options {void} tarot_perceptron_learn (TarotPerceptron *@var{perceptron}, const TarotGame *@var{base}, const TarotGameEvent *@var{event}, double @var{final_score})
2056
#+begin_deftypefun
2057
2058
2059
2060
2061
2062
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/.
2063
2064
#+end_deftypefun

Vivien Kraus's avatar
Vivien Kraus committed
2065
2066
#+attr_texinfo: :options {void} tarot_perceptron_free (TarotPerceptron *@var{perceptron})
#+begin_deftypefun
2067
2068
Delete a /perceptron/ allocated by =tarot_perceptron_alloc=,
=tarot_perceptron_dup= or =tarot_perceptron_static_default=.
Vivien Kraus's avatar
Vivien Kraus committed
2069
2070
#+end_deftypefun

2071
2072
2073
2074
2075
#+attr_texinfo: :options {void} tarot_perceptron_set_learning_rate (TarotPerceptron *perceptron, double learning_rate)
#+begin_deftypefun
Change the /learning rate/ in /perceptron/.
#+end_deftypefun

Vivien Kraus's avatar
Vivien Kraus committed
2076
#+attr_texinfo: :options {void} tarot_perceptron_load (TarotPerceptron *@var{perceptron}, size_t @var{start}, size_t @var{nweights}, const double *@var{parameters})
2077
#+begin_deftypefun
Vivien Kraus's avatar
Vivien Kraus committed
2078
2079
2080
2081
Load the internal /parameters/ (size of /nweights/) into /perceptron/.
If /perceptron/ has /n/ parameters, then we skip the first /start/
ones.
#+end_deftypefun
2082

Vivien Kraus's avatar
Vivien Kraus committed
2083
2084
2085
2086
2087
2088
2089
2090
#+attr_texinfo: :options {size_t} tarot_perceptron_save (const TarotPerceptron *@var{perceptron}, size_t @var{start}, size_t @var{max}, double *@var{parameters})
#+begin_deftypefun
#+attr_texinfo: @deftypefunx {void} tarot_perceptron_save_alloc (const TarotPerceptron *@var{perceptron}, size_t *@var{n}, double **@var{data})
Get the /max/ first internal /parameters/ after skipping the /start/
first and return the total number of parameters.  The =_alloc=
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/.
2091
#+end_deftypefun
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
** A general interface for AI predictors
#+attr_texinfo: :options {struct} TarotAi
#+begin_deftp
All AI predictors are in fact used the same way.  Given a bunch of
possibilities to choose from at a given state, predict the score for
each possibility.  From this function, we could derive interesting
elements that do not depend on the particular implementation.  For
instance, playing the next move.  It is very tiresome to enumerate all
possible cases for each different game event type, and even
intractable for the discard.

To solve this problem, the =TarotAi= opaque struct is in fact generic,
and can be used to develop plugins.  For instance, here is how you
would implement a stupid AI that would always predict a score of 42 in
a solo game.

#+BEGIN_SRC C -i :tangle dumb-ai.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#ifndef LOCALEDIR
#define LOCALEDIR "/usr/share/locale"
#endif /* NOT LOCALEDIR */

#ifndef DATADIR
#define DATADIR "/usr/share/tarot"
#endif /* NOT DATADIR */

/* We can parameterize the response, not to always answer 42! */
struct state
{
  double response;
};

static void
my_eval (void *user_data,
	 const TarotGame *base,
	 size_t n_candidates,
	 TarotGameEvent **candidates,
	 size_t start,
	 size_t max,
	 double *scores)
{
  /* At the current state in the /base/ game, we want to make a
   ,* prediction for each candidate event. */
  struct state *state = (struct state *) user_data;
  size_t i;
  for (i = 0; i < n_candidates; i++)
    {
      /* Modification of any elements in the candidates array is not
       ,* documented.  So let us put a 'const' here. */
      const TarotGameEvent *event = candidates[i];
      double prediction;
      /* What prediction to make if we play /event/ in /base/? */
      prediction = state->response;
      /* Store the prediction in the scores array, but discard the
       ,* first /start/ items and only store /max/ items */
      if (i < start || i > start + max)
	{
	  /* This event is not relevant */
	}
      else
	{
	  scores[i - start] = prediction;
	}
    }
}

static void
my_learn (void *user_data,
	  const TarotGame *base,
	  const TarotGameEvent *event,
	  double final_score)
{
  /* We are made aware that predicting /final_score/ for playing
   ,* /event/ in /base/ was the right thing to do. */
  struct state *state = (struct state *) user_data;
  if (final_score == state->response)
    {
      printf ("Ha! I was right!\n");
    }
  else
    {
      printf ("I missed that by %f points.\n", (final_score - state->response) / 2);
    }
}

static void *
my_dup (void *user_data)
{
  /* Return an allocated copy of user_data, we don't use it here */
  abort ();
  return NULL;
}

static void
my_destruct (void *user_data)
{
  /* Do not forget to free the associated resources! */
  struct state *state = (struct state *) user_data;
  state->response = 0;
}

int
main ()
{
  /* Our new AI will play against the library AI in a solo game! */
  TarotGame *game_data;
  TarotSolo *game;
  TarotAi *ai;
  const TarotGameEvent *event;
  struct state ai_state;
  tarot_set_datadir (DATADIR);
  if (tarot_init (LOCALEDIR) != 0)
    {
      fprintf (stderr, "Error: could not initialize libtarot.\n");
      return EXIT_FAILURE;
    }
  game = tarot_solo_alloc ();
  if (tarot_solo_setup_random (game, 5, 1, strlen ("Random!"), "Random!") != TAROT_GAME_OK)
    {
      fprintf (stderr, "Error: this seed is invalid.\n");
      return EXIT_FAILURE;
    }
  /* game_data is here so that we can query the game by the eyes of
   ,* our AI */
  game_data = tarot_solo_get_alloc (game);
  ai_state.response = 42;
  ai = tarot_ai_alloc (&ai_state, my_eval, my_learn, my_dup, my_destruct);
  while (tarot_game_step (game_data) != TAROT_END)
    {
      double predicted_score;
      const TarotGameEvent *best;
      best = tarot_ai_best (ai, game_data, &predicted_score);
      tarot_game_free (game_data);
      if (best == NULL)
	{
	  /* Waiting for the setup, deal, or dog -- but impossible in
	   ,* a solo game */
	  assert (0);
	}
      else
	{
	  printf ("By doing that, I plan to make %f points!\n", predicted_score / 2);
	  if (tarot_solo_add (game, best) != TAROT_GAME_OK)
	    {
	      assert (0);
	    }
	}
      game_data = tarot_solo_get_alloc (game);
    }
  tarot_ai_free (ai);
  assert (ai_state.response == 0);
  tarot_game_free (game_data);
  tarot_solo_free (game);
  tarot_quit ();
  return EXIT_SUCCESS;
}
#+END_SRC
#+end_deftp

#+attr_texinfo: :options {TarotAi *} tarot_ai_alloc (void *@var{user_data}, void (*@var{eval}) (void *, const TarotGame *, size_t, TarotGameEvent **, size_t, size_t, double *), void (*@var{learn}) (void *, const TarotGame *, const TarotGameEvent *, double), void (*@var{destruct}) (void *))
#+begin_deftypefun
Create a new AI with the given behavior.  Please refer to the example
above for how to define the function pointers.  The /eval/, /learn/,
/dup/ and /destruct/ hooks are transparently called by
=tarot_ai_eval=, =tarot_ai_learn=, =tarot_ai_dup= and =tarot_ai_free=,
so they share the same semantics.
#+end_deftypefun

#+attr_texinfo: :options {TarotAi *} tarot_ai_alloc_perceptron ()
#+begin_deftypefun
Create an AI as the perceptron trained by the maintainer, but does not
save its training iterations.
#+end_deftypefun

#+attr_texinfo: :options {TarotAi *} tarot_ai_alloc_random (size_t @var{seed_size}, const void *@var{seed})
#+begin_deftypefun
Create an AI that will give random scores and cannot learn.
#+end_deftypefun

Vivien Kraus's avatar
Vivien Kraus committed
2280
2281
#+attr_texinfo: :options {TarotAi *} tarot_ai_alloc_fuzzy (double @var{fuzziness}, size_t @var{seed_size}, const void *@var{seed}, const TarotAi *@var{base})
#+begin_deftypefun
2282
2283
Create an AI that will play perfectly with probability 1 - fuzziness,
and uniformly random with probability fuzziness.
Vivien Kraus's avatar
Vivien Kraus committed
2284
2285
#+end_deftypefun

2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
#+attr_texinfo: :options {TarotAi *} tarot_ai_dup (const TarotAi *@var{ai})
#+begin_deftypefun
Return an allocated copy of /ai/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_ai_free (TarotAi *@var{ai})
#+begin_deftypefun
Destroy /ai/ (also calls the /destruct/ hook).
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_ai_eval (TarotAi *@var{ai}, const TarotGame *@var{base}, size_t @var{n}, TarotGameEvent **@var{candidates}, size_t @var{start}, size_t @var{max}, double *@var{scores})
#+begin_deftypefun
Try to play each of the /n/ /candidate/ events in /base/, and compute
the corresponding /scores/.  Despite the absence of =const=,
/candidates/ should not be modified.  This function may be called with
one specific event from the /candidates/; thus the /start/ first
candidates should not be considered and only the /max/ first values
should be written to /scores/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_ai_learn (TarotAi *@var{ai}, const TarotGame *@var{base}, const TarotGameEvent *@var{event}, double @var{final_score})
#+begin_deftypefun
Learn that playing /event/ in /base/ results in the given /final
score/.
#+end_deftypefun

#+attr_texinfo: :options {void} tarot_ai_strongest_player (TarotAi *@var{ai}, size_t @var{n_players}, int @var{with_call}, size_t @var{n_cards}, const TarotPlayer *@var{owners}, double *@var{confidence}, TarotCard *@var{call})
#+begin_deftypefun
Check who is the strongest player in the deal defined by /owners/ (a
78-player array giving the owner of each card).  /n_cards/ is always
set to 78.  The game considered has /n players/, and may be /with
call/.  In such a case, /call/ is set to the best possible call.

In any case, /confidence/ is set to the predicted score for the
strongest player to push.
#+end_deftypefun

#+attr_texinfo: :options {const TarotGameEvent *} tarot_ai_best (TarotAi *@var{ai}, const TarotGame *@var{state}, double *@var{score})
#+begin_deftypefun
Get the best possible event that the next player in /state/ can play.
The return value is only valid for the lifetime of /ai/, or until a
new call to this function is made.
#+end_deftypefun

#+attr_texinfo: :options {double} tarot_ai_validate (TarotAi *@var{ai}, const TarotGame *@var{validation_game})
#+begin_deftypefun
Get the RMSE error between the situation predicted in all situations
in the /validation game/ and the actual score, averaged over all
players.
#+end_deftypefun
Vivien Kraus's avatar
Vivien Kraus committed
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
** 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 {TarotSolo *} tarot_solo_alloc (void)
#+begin_deftypefun
2347
#+texinfo: @deftypefunx {TarotSolo *} tarot_solo_alloc_fuzzy (double @var{fuzziness}, size_t @var{seed_size}, const void *@var{seed}, const TarotAi *@var{ai})
Vivien Kraus's avatar
Vivien Kraus committed
2348
#+texinfo: @deftypefunx {void} tarot_solo_free (TarotSolo *@var{solo})
2349
2350
2351
2352
2353
2354
2355
Allocate and free a new game against the AI.  The fuzzy variant uses
an /AI/ that will incorporate a random evaluation in all moves.  If
/fuzziness/ is set to 0, then no random evaluation will be considered.
If /fuzziness/ is set to 1, then all moves will be chosen at random.
If /ai/ is =NULL=, then a default AI will be used.

This is an easy way to change the difficulty of the game.
Vivien Kraus's avatar
Vivien Kraus committed
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
#+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
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
* GNU Free Documentation License
  :PROPERTIES:
  :APPENDIX: t
  :END:

#+texinfo: @include fdl.texi
#+texinfo: @ignore
This document is published under the GNU Free Documentation License.
You may get a copy of the license at
[[https://www.gnu.org/licenses/fdl.html]].
#+texinfo: @end ignore

Vivien Kraus's avatar
Vivien Kraus committed
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
* Index
  :PROPERTIES:
  :INDEX:    cp
  :END:
* Index of libtarot modules
  :PROPERTIES:
  :INDEX:    tp
  :END:
* API Index
  :PROPERTIES:
  :INDEX:    fn
  :END:
2420
2421
2422
* File-local variables                                             :noexport:
# Local Variables:
# mode: org
Vivien Kraus's avatar
Vivien Kraus committed
2423
# tab-width: 4
2424
# End: