pokercore/card.go

194 lines
4.4 KiB
Go

package pokercore
import (
"fmt"
"slices"
"sort"
"strings"
"unicode/utf8"
"github.com/logrusorgru/aurora/v4"
)
type Card struct {
Rank Rank
Suit Suit
}
func NewCardFromString(card string) (Card, error) {
// FIXME extend this later to common format strings like "9s"
length := utf8.RuneCountInString(card)
if length != 2 {
return Card{}, fmt.Errorf("Invalid card string %s", card)
}
var rank Rank
var suit Suit
if strings.ContainsRune(card, rune(SPADE)) {
suit = Suit(SPADE)
} else if strings.ContainsRune(card, rune(HEART)) {
suit = Suit(HEART)
} else if strings.ContainsRune(card, rune(DIAMOND)) {
suit = Suit(DIAMOND)
} else if strings.ContainsRune(card, rune(CLUB)) {
suit = Suit(CLUB)
} else {
return Card{}, fmt.Errorf("Invalid card string %s", card)
}
if strings.ContainsRune(card, rune(DEUCE)) {
rank = Rank(DEUCE)
} else if strings.ContainsRune(card, rune(THREE)) {
rank = Rank(THREE)
} else if strings.ContainsRune(card, rune(FOUR)) {
rank = Rank(FOUR)
} else if strings.ContainsRune(card, rune(FIVE)) {
rank = Rank(FIVE)
} else if strings.ContainsRune(card, rune(SIX)) {
rank = Rank(SIX)
} else if strings.ContainsRune(card, rune(SEVEN)) {
rank = Rank(SEVEN)
} else if strings.ContainsRune(card, rune(EIGHT)) {
rank = Rank(EIGHT)
} else if strings.ContainsRune(card, rune(NINE)) {
rank = Rank(NINE)
} else if strings.ContainsRune(card, rune(TEN)) {
rank = Rank(TEN)
} else if strings.ContainsRune(card, rune(JACK)) {
rank = Rank(JACK)
} else if strings.ContainsRune(card, rune(QUEEN)) {
rank = Rank(QUEEN)
} else if strings.ContainsRune(card, rune(KING)) {
rank = Rank(KING)
} else if strings.ContainsRune(card, rune(ACE)) {
rank = Rank(ACE)
} else {
return Card{}, fmt.Errorf("Invalid card string %s", card)
}
if rank == Rank(0) || suit == Suit(0) {
return Card{}, fmt.Errorf("Invalid card string %s", card)
}
return Card{Rank: rank, Suit: suit}, nil
}
func NewCardsFromString(cards string) (Cards, error) {
// supports a string like 9♠,9♣,Q♥,Q♦,K♣
// FIXME extend this later to common format strings like "9c Qh Qd Kc"
// with or without commas
var newCards Cards
newCards = make(Cards, 0)
cardStrings := strings.Split(cards, ",")
for _, cardString := range cardStrings {
card, err := NewCardFromString(cardString)
if err != nil {
return Cards{}, err
}
newCards = append(newCards, card)
}
if len(newCards) == 0 {
return Cards{}, fmt.Errorf("No cards found in string %s", cards)
}
return newCards, nil
}
func (c *Card) String() string {
return fmt.Sprintf("%s%s", string(c.Rank), string(c.Suit))
}
type Cards []Card
func (c Cards) First() Card {
return c[0]
}
func (c Cards) Second() Card {
return c[1]
}
func (c Cards) Third() Card {
return c[2]
}
func (c Cards) Fourth() Card {
return c[3]
}
func (c Cards) Fifth() Card {
return c[4]
}
func (c Cards) Last() Card {
return c[len(c)-1]
}
func (c Cards) SortByRankAscending() Cards {
newCards := make(Cards, len(c))
copy(newCards, c)
sort.Slice(newCards, func(i, j int) bool {
return newCards[i].Rank.Score() < newCards[j].Rank.Score()
})
return newCards
}
func (c Cards) PrintToTerminal() {
fmt.Printf("%s", c.FormatForTerminal())
}
type SortOrder int
const (
AceHighAscending SortOrder = iota
AceHighDescending
)
func (c Cards) FormatForTerminalSorted(order SortOrder) string {
sorted := c.SortByRankAscending() // this is ascending
if order == AceHighDescending {
slices.Reverse(sorted)
}
return sorted.FormatForTerminal()
}
func (c Cards) FormatForTerminal() string {
var cardstrings []string
for i := 0; i < len(c); i++ {
cardstrings = append(cardstrings, c[i].FormatForTerminal())
}
return strings.Join(cardstrings, ",")
}
func (c Card) FormatForTerminal() string {
var rank string
var suit string
color := aurora.Red
switch c.Suit {
case Suit(DIAMOND):
color = aurora.Blue
case Suit(HEART):
color = aurora.Red
case Suit(CLUB):
color = aurora.Green
case Suit(SPADE):
color = aurora.Black
}
rank = fmt.Sprintf("%s", aurora.Bold(color(c.Rank.Symbol())))
suit = fmt.Sprintf("%s", aurora.Bold(color(c.Suit.Symbol())))
return fmt.Sprintf("%s%s", rank, suit)
}
func (c Cards) HighestRank() Rank {
sorted := c.SortByRankAscending()
return sorted[len(sorted)-1].Rank
}
func (s Cards) String() (output string) {
var cardstrings []string
for i := 0; i < len(s); i++ {
cardstrings = append(cardstrings, s[i].String())
}
output = strings.Join(cardstrings, ",")
return output
}