diff options
Diffstat (limited to 'internal/casino/blackjack.go')
| -rw-r--r-- | internal/casino/blackjack.go | 132 |
1 files changed, 31 insertions, 101 deletions
diff --git a/internal/casino/blackjack.go b/internal/casino/blackjack.go index a158a24..80a4d15 100644 --- a/internal/casino/blackjack.go +++ b/internal/casino/blackjack.go @@ -17,28 +17,8 @@ const ( blackjackPlaying blackjackPhase = "playing" ) -type blackjackCard struct { - rank string - suit string -} - -func (c blackjackCard) String() string { return c.rank + " of " + c.suit } - -func (c blackjackCard) value() int { - switch c.rank { - case "A": - return 11 - case "K", "Q", "J": - return 10 - default: - var value int - fmt.Sscanf(c.rank, "%d", &value) - return value - } -} - type blackjackHand struct { - cards []blackjackCard + cards []card bet int fromSplit bool doubled bool @@ -49,9 +29,9 @@ type blackjackHand struct { func (h *blackjackHand) total() (int, bool) { total, aces := 0, 0 - for _, card := range h.cards { - total += card.value() - if card.rank == "A" { + for _, c := range h.cards { + total += c.blackjackValue() + if c.rank == "A" { aces++ } } @@ -76,45 +56,9 @@ type blackjackPlayer struct { lastBet int } -type blackjackShoe struct { - cards []blackjackCard - rng *rand.Rand - decks int -} - -func newBlackjackShoe(decks int, rng *rand.Rand) *blackjackShoe { - s := &blackjackShoe{rng: rng, decks: decks} - s.shuffle() - return s -} - -func (s *blackjackShoe) shuffle() { - ranks := []string{"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"} - suits := []string{"clubs", "diamonds", "hearts", "spades"} - s.cards = make([]blackjackCard, 0, s.decks*52) - for deck := 0; deck < s.decks; deck++ { - for _, suit := range suits { - for _, rank := range ranks { - s.cards = append(s.cards, blackjackCard{rank: rank, suit: suit}) - } - } - } - s.rng.Shuffle(len(s.cards), func(i, j int) { s.cards[i], s.cards[j] = s.cards[j], s.cards[i] }) -} - -func (s *blackjackShoe) draw(rules BlackjackConfig) blackjackCard { - if len(s.cards) <= int(float64(s.decks*52)*rules.ShuffleAt) { - s.shuffle() - } - card := s.cards[len(s.cards)-1] - s.cards = s.cards[:len(s.cards)-1] - return card -} - type blackjackTable struct { - mu sync.Mutex - RoomID int - Config TableConfig + mu sync.Mutex + tableBase Rules BlackjackConfig participants map[string]*blackjackPlayer order []string @@ -123,16 +67,16 @@ type blackjackTable struct { activePlayer int activeHand int dealer blackjackHand - shoe *blackjackShoe + shoe *shoe } func newBlackjackTable(roomID int, cfg TableConfig, rng *rand.Rand) *blackjackTable { cfg = cfg.Normalize() rules := cfg.Blackjack.Normalize() return &blackjackTable{ - RoomID: roomID, Config: cfg, Rules: rules, + tableBase: tableBase{RoomID: roomID, Config: cfg}, Rules: rules, participants: make(map[string]*blackjackPlayer), phase: blackjackWaiting, - shoe: newBlackjackShoe(rules.Decks, rng), + shoe: newShoe(rules.Decks, rules.ShuffleAt, rng), } } @@ -146,23 +90,6 @@ func (t *blackjackTable) seats() []*Participant { return seats } -func (t *blackjackTable) event(message string, public bool) Event { - return Event{RoomID: t.RoomID, TableID: t.Config.ID, Type: EventResult, Message: message, Public: public, Color: "casino_action"} -} - -func (t *blackjackTable) private(name, message string) Event { - e := t.event(message, false) - e.PrivateTo = name - return e -} - -func (t *blackjackTable) playerAction(name, publicMessage, privateMessage string) Event { - e := t.event(publicMessage, true) - e.PrivateTo = name - e.PrivateMessage = privateMessage - return e -} - func (t *blackjackTable) menuEvent(name string) Event { e := t.private(name, t.menu()) e.Color = "casino_menu" @@ -218,13 +145,16 @@ func (t *blackjackTable) leave(name string) []Event { return events } -func (t *blackjackTable) bet(name string, amount int, wallet Wallet) []Event { +func (t *blackjackTable) bet(name, spot string, amount int, wallet Wallet) []Event { t.mu.Lock() defer t.mu.Unlock() p := t.participants[name] if p == nil { return []Event{t.private(name, "You aren't playing blackjack.")} } + if spot != "" { + return []Event{t.private(name, "Blackjack bets don't take a bet target.")} + } if t.phase != blackjackWaiting && t.phase != blackjackBetting { return []Event{t.private(name, "That blackjack table isn't accepting bets.")} } @@ -317,7 +247,7 @@ func (t *blackjackTable) action(name, action string) []Event { if fromSplitAces(hand) { return []Event{t.private(name, "Split aces cannot be hit.")} } - hand.cards = append(hand.cards, t.shoe.draw(t.Rules)) + hand.cards = append(hand.cards, t.shoe.draw()) total, _ := hand.total() if total > 21 { hand.bust = true @@ -344,7 +274,7 @@ func (t *blackjackTable) action(name, action string) []Event { hand.bet *= 2 hand.doubled = true hand.stood = true - hand.cards = append(hand.cards, t.shoe.draw(t.Rules)) + hand.cards = append(hand.cards, t.shoe.draw()) if total, _ := hand.total(); total > 21 { hand.bust = true } @@ -430,10 +360,10 @@ func (t *blackjackTable) splitHand(name string, p *blackjackPlayer, hand *blackj if _, ok := p.Wallet.Wager(hand.bet); !ok { return []Event{t.private(name, "You don't have enough chips and credits to split that hand.")} } - left := &blackjackHand{cards: []blackjackCard{hand.cards[0]}, bet: hand.bet, fromSplit: true} - right := &blackjackHand{cards: []blackjackCard{hand.cards[1]}, bet: hand.bet, fromSplit: true} - left.cards = append(left.cards, t.shoe.draw(t.Rules)) - right.cards = append(right.cards, t.shoe.draw(t.Rules)) + left := &blackjackHand{cards: []card{hand.cards[0]}, bet: hand.bet, fromSplit: true} + right := &blackjackHand{cards: []card{hand.cards[1]}, bet: hand.bet, fromSplit: true} + left.cards = append(left.cards, t.shoe.draw()) + right.cards = append(right.cards, t.shoe.draw()) index := t.activeHand p.hands = append(p.hands[:index], append([]*blackjackHand{left, right}, p.hands[index+1:]...)...) e := t.playerAction(name, fmt.Sprintf("%s splits the hand.", name), "You split the hand.") @@ -449,21 +379,21 @@ func (t *blackjackTable) splitHand(name string, p *blackjackPlayer, hand *blackj return events } -func splitCompatible(a, b blackjackCard, unlikeTens bool) bool { +func splitCompatible(a, b card, unlikeTens bool) bool { if a.rank == b.rank { return true } - return unlikeTens && a.value() == 10 && b.value() == 10 + return unlikeTens && a.blackjackValue() == 10 && b.blackjackValue() == 10 } func (t *blackjackTable) startRound() []Event { - t.dealer = blackjackHand{cards: []blackjackCard{t.shoe.draw(t.Rules), t.shoe.draw(t.Rules)}} + t.dealer = blackjackHand{cards: []card{t.shoe.draw(), t.shoe.draw()}} for _, name := range t.order { p := t.participants[name] if p == nil || !p.HasBet { continue } - p.hands = []*blackjackHand{{cards: []blackjackCard{t.shoe.draw(t.Rules), t.shoe.draw(t.Rules)}, bet: p.Wager.Total}} + p.hands = []*blackjackHand{{cards: []card{t.shoe.draw(), t.shoe.draw()}, bet: p.Wager.Total}} if p.hands[0].bet/2 <= 0 { // A half-bet that rounds to zero cannot be insured. p.declinedInsurance = true @@ -595,7 +525,7 @@ func (t *blackjackTable) settle() []Event { if total > 17 || total == 17 && (!soft || !t.Rules.DealerHitsSoft17()) { break } - t.dealer.cards = append(t.dealer.cards, t.shoe.draw(t.Rules)) + t.dealer.cards = append(t.dealer.cards, t.shoe.draw()) } dealerTotal, _ := t.dealer.total() dealerEvent := t.event("Dealer's hand:", true) @@ -679,11 +609,11 @@ func (t *blackjackTable) resetRound() { } } -func (t *blackjackTable) rebetAmount(name string) int { +func (t *blackjackTable) rebet(name string) (string, int) { if p := t.participants[name]; p != nil && p.lastBet > 0 { - return p.lastBet + return "", p.lastBet } - return t.Config.MinBet + return "", t.Config.MinBet } func (t *blackjackTable) bettorCount() int { @@ -700,10 +630,10 @@ func (t *blackjackTable) snapshot(revealDealer bool) *BlackjackSnapshot { snapshot := &BlackjackSnapshot{} for i, card := range t.dealer.cards { if i == 0 && !revealDealer { - snapshot.Dealer = append(snapshot.Dealer, BlackjackCardView{Rank: "?", Hidden: true}) + snapshot.Dealer = append(snapshot.Dealer, CardView{Rank: "?", Hidden: true}) continue } - snapshot.Dealer = append(snapshot.Dealer, BlackjackCardView{Rank: card.rank, Suit: card.suit}) + snapshot.Dealer = append(snapshot.Dealer, CardView{Rank: card.rank, Suit: card.suit}) } for _, name := range t.order { p := t.participants[name] @@ -713,13 +643,13 @@ func (t *blackjackTable) snapshot(revealDealer bool) *BlackjackSnapshot { for _, hand := range p.hands { view := BlackjackPlayerView{Name: name, Score: handScore(hand)} for _, card := range hand.cards { - view.Cards = append(view.Cards, BlackjackCardView{Rank: card.rank, Suit: card.suit}) + view.Cards = append(view.Cards, CardView{Rank: card.rank, Suit: card.suit}) } snapshot.Players = append(snapshot.Players, view) } } if len(t.dealer.cards) > 1 { - snapshot.DealerShownScore = handScore(&blackjackHand{cards: []blackjackCard{t.dealer.cards[1]}}) + snapshot.DealerShownScore = handScore(&blackjackHand{cards: []card{t.dealer.cards[1]}}) } snapshot.DealerScore = handScore(&t.dealer) snapshot.DealerRevealed = revealDealer |
