Metadata-Version: 2.5
Name: magmacrunch-tarot
Version: 0.1.1
Summary: French tarot against three computers. Terminal version.
Project-URL: Homepage, https://magmacrunch.com/arcade/tarot/
Author: magmacrunch media
License-Expression: PolyForm-Noncommercial-1.0.0
License-File: LICENSE
License-File: NOTICE
Keywords: arcade,cards,games,tarot,terminal,tui
Requires-Python: >=3.10
Requires-Dist: magmacrunch>=0.7.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# French Tarot (terminal)

Four-player French Tarot against three computers, in a terminal. It is the
second version of the game, beside `web/`. It runs on the
[magmacrunch](https://github.com/magmacrunch-media/magmacrunch) engine's
terminal backend, either as a cabinet in the magmacrunch arcade or as its own
command, and plays the same either way.

```
pipx install magmacrunch-tarot
tarot              # the title
tarot --play       # straight into a game
tarot --seed 7     # the same deals every time
```

For working on it, from this folder:

```
pip install -e ".[dev]"
python -m tarot
```

## Keys

| key | |
|---|---|
| `←` `→` | along the bids, or along your hand |
| `ENTER` | place the bid, play the card, or mark a card for the dog |
| `C` | with six cards marked, put them in the dog |
| `Y` / `N` | declare or decline your poignée, before the first trick |
| `Esc` | the title (and from there, the arcade) |
| `Q` | quit |

You sit south, with West, North and East round the table. Cards are written
`R♥`, `10♠`, `21` for a trump and `Ex` for the Excuse, and your hand is sorted
as on the page: trumps, the Excuse, then the suits. Only the cards you may
play are lit. The computers bid after half a second and play after 0.6, a
finished trick stays on the table for a second, and a hand nobody takes is
redealt by the next dealer after 1.5, all as on the page; so is a petit sec.
When you hold ten trumps or more you are asked before the first trick to
declare your poignée, showing them, or decline it, and every poignée declared
is shown in the log. At the end of each hand the result is shown: the taker's
oudlers and points against the threshold, and everyone's running total. When
the game ends and your total makes the table, you are asked for initials,
which is when the page saves a score too.

Needs a 76x24 terminal.

## It is the browser's game, and the browser's opponents

`tarot/rules.py` is `web/js/config.js`, `tarot-deck.js`, `trick-logic.js`,
`scoring.js`, `ai.js` and `game.js`, ported function for function, including
the order the computers look through their hands in, because that is how they
break ties. Two tests hold the port to the page:

- **`tests/test_oracle.py`.** `tools/js_oracle.mjs` loads those files
  unmodified, with a seeded `Math.random`, and plays 30 games of five hands
  through `TarotGame`'s own API in `main.js`'s order: 148 hands and about
  11,700 moves. In odd games your seat plays at random, and declares or
  declines a poignée at random; in even games it bids what `scoring.js`
  suggests, plays the page's own computer moves and declares. Between them
  they cover 56 redeals, 88 hands you took, 18 Garde Sans, 22 Garde Contre,
  146 Excuses (12 of whose half points were settled in the score), 19 petits
  au bout paid, 2 chelems and 7 poignées of yours, one declined. The test replays every move through the port and
  requires the same state after each: phase, dealer, bidder, player, taker,
  bids, every hand, the dog, the trick, every trick pile, the scores, the
  poignées and whether yours is still to answer. Each hand's result must match too, line by line.
- **`tests/test_rules.py`.** It sets up by hand the cases worth pinning,
  including the rules below, so that a change to one shows.

## The page's rules

Porting the page found places where its rules were not French Tarot's, and
magmacrunch-media/tarot#3 fixed them on the page; this follows them. Petit au
bout is paid to its side; the Excuse stays with its side and is paid for with
a half-point card, or in the score when its side has won no trick yet; it
changes sides at the last trick unless its side is sweeping; a redeal is a
fresh auction from the next dealer, and a petit sec is dealt again; the dog
joins the taker's hand before the discard, a trump goes down only when there
are not six other cards, and a Garde Contre dog goes to the defence once; the
player after the dealer leads; every player's poignée counts, at 20, 30 and
40, yours only if you declare it; a chelem scores 200; the difference is
rounded to a whole point, so every share is whole and every round sums to
zero; and the highest score wins.

**The page used to stop when your bid closed the auction.** `main.js`
ignored what your bid returned and asked the computers to bid again, which
they couldn't, for ever. Both fixes for it, `handleBidResult` on main and
`afterBid` in tarot#3, hand your bid's result on as a computer's is; the merge
kept `afterBid`. Here the game always went on; `test_app.py` bids last and
bids Garde Contre by keys and checks it does.

**The computers bid boldly.** In the oracle's 148 hands a computer taker made
28 contracts of 60, with 44 points on average against about 46 needed.

## Licence

PolyForm Noncommercial 1.0.0, as for the rest of this repository. See `LICENSE`
and `NOTICE`.
