The problem I needed to solve
I wanted the same core to support both a fixed deal and distributing an entire deck. Hokm’s player and card counts should not leak into every other game.
Implementation in this snapshot
CardDealer.Deal selects a path using DealMode. A fixed deal supports round-robin single-card dealing or dealing each whole hand; the other mode rotates through players until the deck is empty.
The design decision and its cost
DealConfig also controls sorting afterward. DealResult reports player count, cards dealt and remaining cards, keeping logical counts separate from their presentation.
Current boundaries
Fixed dealing checks for insufficient cards before drawing. The service does not invent Hokm’s staged deal or Joker’s no-pair opening; those belong to the game layer.
Equal counts, different dealing orders
Suppose three players each need two cards. DealFixedRoundRobin gives the first three cards to the three players, then makes another pass for their second cards. DealFixedPerPlayer gives two consecutive cards to the first player before proceeding to the second. Final counts are equal, but identical deck order does not produce identical hands. DealOneCardAtATime therefore affects logical allocation rather than appearance alone, and its setting must agree with the game’s rule.
DealUntilDeckEmpty advances a player counter modulo the player count after every draw. If the deck size is not divisible by that count, some players receive an extra card because dealing begins with the first list entry. CardDealer has no parameter for starting halfway through that list. A game can prepare the intended ordering, but must distinguish seat order from method input order. The loop alone does not establish automatic fairness or symmetry.
Validate rejects a missing deck, an empty player list, null players and invalid CardsPerPlayer before dealing. A subtle detail is that CardsPerPlayer must be positive even when emptying the deck, although that mode’s loop does not use it. DealConfig must satisfy the whole current contract. Afterward, SortHandsAfterDeal sorts every hand and DealResult reports counts. Those counts help inspect allocation, but do not govern card-flight timing, sound or trump selection.
What this stage taught me
For me, reuse meant removing unjustified constants. The dealer performs one bounded task, while each game determines when and in what order to call it.




