NAME

Game::Schnapsen::Deck - the seeded deal, and the talon as the tail of it

VERSION

Version 0.01

SYNOPSIS

use Game::Schnapsen::Deck qw(order_for deal_for);

my $order = order_for($seed, 1, 'schnapsen');   # 20 ids, a permutation
my $deal  = deal_for($seed, 1, 'sixtysix');

$deal->{non_dealer};   # five ids, or six
$deal->{dealer};       # the same again
$deal->{talon};        # the face down cards, in draw order
$deal->{turn_up};      # the trump card, face up, drawn last

DESCRIPTION

One shuffle per deal, from the seed, the deal number and the variant, with no call to rand anywhere. A match is therefore a pure function of its seed and its moves and replays on any machine, which is what lets a finished match be checked by anybody once the seed is published.

The deal number is part of the key

A match is several deals. A shuffle fixed once at the start would deal the same cards every deal, and that failure looks like extraordinary luck rather than like a fault.

So is the variant, against a hazard that does not exist yet

The two games have different packs, so their orders already diverge at the first swap and would do so whether or not the key named the variant. Nothing in the test suite catches its removal today, and it is worth being plain about that rather than claiming a defence there is not one of.

It is in the key for a case that has not arrived: a later variant sharing a pack size with one of these two would otherwise deal it an identical order from the same seed, every deal, for ever. That is a silent collision rather than a failure, and the cost of preventing it now is one interpolation.

The turn-up is last in the order, not first

Both rulesets describe the trump card as lying face up under the talon and going to whoever draws last. Putting it at the end of the order makes a draw unconditionally "take the next one", with no special case at the bottom of the pile.

That matters beyond tidiness. A draw is then derivable from the seed and the number of draws already made, so nothing has to record which card was drawn, and a consumer that keeps hands secret gets that for free rather than by filtering its move log. A payload that never held the card cannot leak it.

The cards available to draw are the talon plus the turn-up, which is ten in Schnapsen and twelve in Sixty-Six. Both divide by two, so the draws come out even and the talon empties at the end of a trick rather than in the middle of one.

The shuffle

Fisher-Yates over the variant's pack, driven by 32-bit words from SHA-256 of the seed and the key, rejecting any word past the largest multiple of the range so that no position is favoured.

This is the fifth copy of that routine in its family, after the ones in Game::Cribbage, Game::Dominoes, Goofspiel and Game::Gin::Deck. They are meant to stay in step. This copy differs from them in one way only, that the pack is a parameter rather than a fixed fifty-two, so the difference is not a drift to be tidied away.

FUNCTIONS

Nothing is exported by default.

pack_for

pack_for('schnapsen');   # the twenty ids, in id order

The variant's pack, as an arrayref, memoised. Treat it as read only.

order_for

my $order = order_for($seed, $deal, $variant);

The variant's ids in shuffled order. Dies unless the seed is exactly 32 bytes, the deal number is a positive integer and the variant is one this engine plays.

deal_for

my $deal = deal_for($seed, $deal, $variant);

The same order laid out as non_dealer, dealer, talon and turn_up.

talon_at

The position in the order at which the talon begins, which is both hands dealt.

draw_count

How many cards are available to draw, the turn-up included.

SEE ALSO

Game::Schnapsen::Card, Game::Schnapsen::Variant.

AUTHOR

LNATION, <email@lnation.org>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION.

This is free software, licensed under the Artistic License 2.0.