The problem I needed to solve
I did not want shuffling hidden inside dealing. If another game later needed a constrained opening, I wanted to replace the ordering strategy while retaining the rest of the core.
Implementation in this snapshot
FisherYatesShuffleStrategy implements IShuffleStrategy. Its loop moves backward through the collection, chooses a position between zero and the current index, and swaps the two elements.
The design decision and its cost
The constructor accepts an optional seed. That is useful for reproducing a logical path; I do not equate System.Random with cryptographic randomness or an anti-cheat guarantee.
Current boundaries
Reproducibility depends on more than the seed. Input order and the number of calls matter too. Without holding those constant, apparently similar runs can produce different orders.
Reproducing an order for investigation
Investigating a dealing issue requires more than saying that the deck was shuffled. The input order and random generator state matter too. FisherYatesShuffleStrategy accepts an optional seed and creates Random in its constructor. Two fresh strategy instances with the same seed and identical inputs allow investigation of a reproducible logical path. That is useful for explaining a scenario; it does not establish that Dalo has complete runtime reporting or match saving.
The loop moves from the list’s end toward its beginning and calls random.Next(i + 1). Adding one makes the current position an eligible choice: an item sometimes stays where it is, which is part of the algorithm. Swaps modify the supplied IList; no new collection is returned. Callers must expect their input to change. If they need the original order for comparison, they must preserve it before Shuffle, rather than after the list has been modified.
Shuffle is generic rather than card-specific, so the same contract can reorder any suitable collection. The cost of that independence is that it knows nothing about Joker opening hands or valid deck composition. Reusing one strategy instance also continues the existing Random sequence. A fixed seed does not reset the generator after each call. Reproducing an issue requires accounting for the order and number of calls as well.
What this stage taught me
This contract became useful for Joker: avoiding opening pairs was a different problem. Ordinary shuffling remained available without absorbing a game-specific rule.




