Documentation
¶
Overview ¶
Package ginrummy is a pure-logic rules and scoring library for two-player Gin Rummy, operating on plain card indices (0..51) with no crypto, networking, or service dependencies. Everything here is deterministic (no randomness) so callers can drive and verify games reproducibly.
Card model: a card is an int 0..51 where Rank(c) = c % 13 (0=Ace .. 12=King) and Suit(c) = c / 13 (0=♠, 1=♥, 2=♦, 3=♣).
Melds are the scoring groups: a set is 3 or 4 cards of the same rank, and a run is 3+ consecutive cards of the same suit with Ace LOW only — A-2-3 is a valid run but Q-K-A is not (there is no wraparound). BestMelds finds the decomposition that minimises leftover deadwood.
Lay-off: after a non-gin knock the defender may lay their own deadwood cards onto the knocker's melds, reducing the defender's counted deadwood before scoring (see LayOff). Score applies this in the non-gin branch, so the opponent deadwood (od) it compares is the post-lay-off remainder. Gin scoring is unaffected because a gin opponent has no deadwood and cannot lay off.
Index ¶
- Constants
- func BestMelds(hand []int) (deadwood int, melds [][]int, unmatched []int)
- func CanKnock(hand []int) bool
- func CardString(c int) string
- func Deadwood(hand []int) int
- func DeadwoodValue(c int) int
- func IsGin(hand []int) bool
- func LayOff(deadwood []int, knockerMelds [][]int) (remaining int, laid []int)
- func Rank(c int) int
- func Score(knocker, opponent []int, gin bool) (knockerPts, oppPts int)
- func Suit(c int) int
Constants ¶
const GinBonus = 25
GinBonus is added to the knocker's score for going gin.
const HandTarget = 100
HandTarget is the match target: the first player to reach this cumulative score wins the match. Callers own match bookkeeping; this package only scores a single hand.
const UndercutBonus = 25
UndercutBonus is added to the opponent's score when they undercut the knocker.
Variables ¶
This section is empty.
Functions ¶
func BestMelds ¶
BestMelds partitions a hand so each card belongs to at most one meld, choosing the decomposition that minimises the total deadwood value of the unmatched cards. It returns that minimal deadwood, one optimal set of melds (each a slice of card indices), and the unmatched (deadwood) cards.
A card may be usable in either a set or a run but not both; the optimum is found by an exhaustive backtracking search over all candidate melds (hand sizes are <= 11, so this is cheap), memoised on the set of resolved cards.
func CanKnock ¶
CanKnock reports whether a 10-card hand may knock: its minimal deadwood is at most 10.
func CardString ¶
CardString renders a card as rank+suit, e.g. "A♠", "T♦", "K♣", "5♥".
func Deadwood ¶
Deadwood returns the minimal total deadwood value of a hand, i.e. the deadwood component of BestMelds.
func DeadwoodValue ¶
DeadwoodValue is the point value of a card as deadwood: Ace=1, 2..10 = pip value (rank+1), and J/Q/K = 10.
func LayOff ¶
LayOff models the defender's lay-off after a non-gin knock: the defender may place their own unmatched (deadwood) cards onto the knocker's melds, reducing the deadwood value counted against them.
deadwood is the defender's unmatched card indices (as returned by BestMelds); knockerMelds is the knocker's melds (also from BestMelds). A card may join a SET of its rank (a set caps at 4 cards) or extend either END of a RUN with a same-suit adjacent card. Run extensions cascade (extending 5♠6♠7♠ with 4♠ then admits 3♠), so lay-off iterates to a fixed point. Ace is low only, matching BestMelds: there is no Q-K-A wraparound.
It returns the remaining deadwood VALUE (the sum of DeadwoodValue over the cards NOT laid off) and the list of card indices that were laid off.
func Score ¶
Score computes the points for a single completed hand between the knocker and their opponent. gin indicates the knocker went gin (all cards melded).
Let kd = Deadwood(knocker). In the non-gin case od is the opponent's deadwood AFTER laying off onto the knocker's melds (see LayOff); for gin it is the opponent's full deadwood (a gin opponent cannot lay off).
- Gin: knocker scores od + GinBonus; opponent scores 0.
- Normal knock (kd < od): knocker scores od - kd; opponent scores 0.
- Undercut (kd >= od, non-gin): opponent scores (kd - od) + UndercutBonus; knocker scores 0.
Types ¶
This section is empty.