Created
June 7, 2026 14:39
-
-
Save larrasket/266ebfebc1414fb3d2b647e819817ee0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "math/rand" | |
| "sort" | |
| "strings" | |
| "time" | |
| ) | |
| var ( | |
| SUITS = []string{"♠", "♦", "♥", "♣"} | |
| RANKS = []string{"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"} | |
| RANK_VALUE = func() map[string]int { | |
| m := make(map[string]int, len(RANKS)) | |
| for i, r := range RANKS { | |
| m[r] = i | |
| } | |
| return m | |
| }() | |
| ) | |
| // Card represents a standard playing card | |
| type Card struct { | |
| Rank string | |
| Suit string | |
| } | |
| // String returns the string representation of a card | |
| func (c Card) String() string { | |
| return fmt.Sprintf("%s%s", c.Rank, c.Suit) | |
| } | |
| type Shuffler interface { | |
| Shuffle(n int, swap func(i, j int)) | |
| } | |
| // Deck represents a mutable deck of cards | |
| type Deck struct { | |
| shuffler Shuffler | |
| Cards []Card | |
| } | |
| // NewDeck creates a new deck of 52 cards | |
| func NewDeck(shuffler Shuffler) *Deck { | |
| deck := &Deck{Cards: make([]Card, 0, 52), shuffler: shuffler} | |
| for _, rank := range RANKS { | |
| for _, suit := range SUITS { | |
| deck.Cards = append(deck.Cards, Card{Rank: rank, Suit: suit}) | |
| } | |
| } | |
| return deck | |
| } | |
| // String returns the string representation of the deck | |
| func (d *Deck) String() string { | |
| cardStrings := make([]string, len(d.Cards)) | |
| for i, card := range d.Cards { | |
| cardStrings[i] = card.String() | |
| } | |
| return strings.Join(cardStrings, " ") | |
| } | |
| // Draw removes and returns the first card from the deck | |
| func (d *Deck) Draw() Card { | |
| if len(d.Cards) == 0 { | |
| panic("Cannot draw from empty deck") | |
| } | |
| card := d.Cards[0] | |
| d.Cards = d.Cards[1:] | |
| return card | |
| } | |
| // Shuffle randomizes the order of cards in the deck | |
| func (d *Deck) Shuffle() { | |
| d.shuffler.Shuffle(len(d.Cards), func(i, j int) { | |
| d.Cards[i], d.Cards[j] = d.Cards[j], d.Cards[i] | |
| }) | |
| } | |
| // Player represents a player in the game | |
| type Player struct { | |
| Name string | |
| Hand []Card | |
| } | |
| // NewPlayer creates a new player with the given name | |
| func NewPlayer(name string) *Player { | |
| return &Player{ | |
| Name: name, | |
| Hand: make([]Card, 0), | |
| } | |
| } | |
| // String returns the string representation of the player | |
| func (p *Player) String() string { | |
| return p.Name | |
| } | |
| func (p *Player) SortedHand() []Card { | |
| bySuit := make(map[string][]Card) | |
| suitOrder := []string{} | |
| for _, c := range p.Hand { | |
| if _, ok := bySuit[c.Suit]; !ok { | |
| suitOrder = append(suitOrder, c.Suit) | |
| } | |
| bySuit[c.Suit] = append(bySuit[c.Suit], c) | |
| } | |
| for _, suit := range suitOrder { | |
| cards := bySuit[suit] | |
| sort.Slice(cards, func(i, j int) bool { | |
| return RANK_VALUE[cards[i].Rank] < RANK_VALUE[cards[j].Rank] | |
| }) | |
| } | |
| out := make([]Card, 0, len(p.Hand)) | |
| for _, suit := range suitOrder { | |
| out = append(out, bySuit[suit]...) | |
| } | |
| return out | |
| } | |
| func Deal(deck *Deck, players []*Player) { | |
| i := 0 | |
| for len(deck.Cards) > 0 { | |
| player := players[i%len(players)] | |
| player.Hand = append(player.Hand, deck.Draw()) | |
| fmt.Printf("Player (%s) drew a card\n", player.Name) | |
| i++ | |
| } | |
| } | |
| func handString(cards []Card) string { | |
| parts := make([]string, len(cards)) | |
| for i, c := range cards { | |
| parts[i] = c.String() | |
| } | |
| return "[" + strings.Join(parts, ", ") + "]" | |
| } | |
| func playRound(players []*Player, starterIdx, roundNum int) (int, int) { | |
| starter := players[starterIdx] | |
| fmt.Printf("\nRound %d n", roundNum) | |
| fmt.Printf("Player %s starts the round\n", starter.Name) | |
| leadCard := starter.Hand[0] | |
| starter.Hand = starter.Hand[1:] | |
| fmt.Printf("Player %s played %s\n", starter.Name, leadCard) | |
| type play struct { | |
| idx int | |
| card Card | |
| } | |
| plays := []play{{starterIdx, leadCard}} | |
| leadSuit := leadCard.Suit | |
| gameWinnerIdx := -1 | |
| if len(starter.Hand) == 0 { | |
| gameWinnerIdx = starterIdx | |
| } | |
| for offset := 1; offset < len(players); offset++ { | |
| pi := (starterIdx + offset) % len(players) | |
| p := players[pi] | |
| pick := -1 | |
| for i, c := range p.Hand { | |
| if c.Suit == leadSuit { | |
| pick = i | |
| break | |
| } | |
| } | |
| if pick == -1 { | |
| pick = 0 | |
| } | |
| card := p.Hand[pick] | |
| p.Hand = append(p.Hand[:pick], p.Hand[pick+1:]...) | |
| fmt.Printf("Player %s played %s\n", p.Name, card) | |
| plays = append(plays, play{pi, card}) | |
| if gameWinnerIdx == -1 && len(p.Hand) == 0 { | |
| gameWinnerIdx = pi | |
| } | |
| } | |
| winnerIdx := starterIdx | |
| winnerRank := -1 | |
| for _, pl := range plays { | |
| if pl.card.Suit != leadSuit { | |
| continue | |
| } | |
| if RANK_VALUE[pl.card.Rank] > winnerRank { | |
| winnerRank = RANK_VALUE[pl.card.Rank] | |
| winnerIdx = pl.idx | |
| } | |
| } | |
| fmt.Printf("Winner of round %d: Player %s\n", roundNum, players[winnerIdx].Name) | |
| return winnerIdx, gameWinnerIdx | |
| } | |
| func PlayGame(players []*Player, rng *rand.Rand) { | |
| starterIdx := rng.Intn(len(players)) | |
| for roundNum := 1; ; roundNum++ { | |
| var gameWinnerIdx int | |
| starterIdx, gameWinnerIdx = playRound(players, starterIdx, roundNum) | |
| if gameWinnerIdx != -1 { | |
| fmt.Printf("\n🎉 Game Over! Player %s wins the game!\n", players[gameWinnerIdx].Name) | |
| return | |
| } | |
| } | |
| } | |
| func main() { | |
| players := []*Player{ | |
| NewPlayer("A"), | |
| NewPlayer("B"), | |
| NewPlayer("C"), | |
| NewPlayer("D"), | |
| } | |
| shuffler := rand.New(rand.NewSource(time.Now().UnixNano())) | |
| shuffler.Shuffle(10, func(i, j int) {}) | |
| deck := NewDeck(shuffler) | |
| deck.Shuffle() | |
| fmt.Println("Here's the shuffled deck:") | |
| fmt.Println(deck) | |
| fmt.Println() | |
| Deal(deck, players) | |
| fmt.Println("\nHands:") | |
| for _, p := range players { | |
| fmt.Printf("Player %s: %s\n", p.Name, handString(p.SortedHand())) | |
| } | |
| PlayGame(players, shuffler) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment