NAME
Game::Durak::Bout - one attack and its defence, laid out on the table
VERSION
Version 0.01
SYNOPSIS
my $bout = Game::Durak::Bout->build(
attacker => 1, defender => 2, cap => 6,
);
$bout->add_attack($card);
$bout->unbeaten; # that card, until it is answered
$bout->add_beat($other);
$bout->all_beaten; # 1
$bout->ranks; # { K => 1, A => 1 }, both cards
DESCRIPTION
A bout is the unit of play. One seat attacks, the other answers card by card, and at the end the whole thing is either thrown away or picked up by the seat that could not answer it.
The two lists are parallel: beats->[$i] is the card that answered attacks->[$i], or undef while it is unanswered. That is the layout the table has, "each card played by the defender is placed face up on top of the card it is beating, slightly offset so that the values of all cards can be seen", and it is also what a consumer needs in order to draw it.
The cap is fixed when the bout opens
the total number of cards played by the attackers during a bout must
never exceed six; if the defender had fewer than six cards before the
bout, the number of cards played by the attackers must not be more than
the number of cards in the defender's hand.
-- https://www.pagat.com/beating/podkidnoy_durak.html
Read that again for the word before. The defender's hand shrinks by one for every card they beat, so a cap recomputed from the hand as it stands falls as the bout runs: a defender who started with four cards and has beaten two would be attackable twice more instead of four times. Every deal still finishes, every card is still accounted for, and the game is quietly a gentler one than the rules describe.
So the cap is set once, by the constructor, from the defender's hand at that moment, and this class offers no way to change it. room is what is left.
A bout is never opened against an empty hand
build dies at a cap of zero. A seat with no cards and no talon to draw from is out of the deal, which is decided before the next bout opens, so a zero cap means the caller has skipped that decision. It is a bug and not a refusal.
METHODS
build
Game::Durak::Bout->build(attacker => 1, defender => 2, cap => 4);
Two different seats and a cap of one to six. Dies otherwise.
attacker, defender
The seat numbers, 1 or 2. A bout does not change hands: when the defence is beaten off the deal opens a new bout the other way round.
cap
The most cards the attack may hold, set once.
attacks, beats
The two parallel lists. Treat them as read only and use add_attack and add_beat.
taken
True once the defender has picked the bout up. The cards stay on the table until the bout closes, because the attacker may still throw more in.
size, room
How many cards the attack holds, and how many more it may hold.
unbeaten
The first attack card with no answer, or undef. Outside the pile-on after a take there is never more than one, because the attacker plays a card and waits.
all_beaten
True when every attack card has been answered.
cards
Every card on the table, attacks and answers together, for the discard or for the defender's hand.
ranks
The set of ranks on the table, the defender's answers included. This is what a new attack card has to match:
each new attack card must be of the same rank as some card already played
during the current bout - either an attack card or a card played by the
defender
A set built from the attack cards alone is a subset, so nothing ever refuses a move it should allow, no invariant breaks, and the attack is narrower than the game's for ever.
add_attack, add_beat
Put a card on the table. Both die rather than refusing, because the rules answer legality before either is called.
SEE ALSO
Game::Durak, Game::Durak::Rules.
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.