package pokercore import ( "fmt" "slices" "sort" "strings" "unicode/utf8" aurora "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, must be 2 characters", card) } rankMap := map[rune]Rank{ rune(DEUCE): DEUCE, rune(THREE): THREE, rune(FOUR): FOUR, rune(FIVE): FIVE, rune(SIX): SIX, rune(SEVEN): SEVEN, rune(EIGHT): EIGHT, rune(NINE): NINE, rune(TEN): TEN, rune(JACK): JACK, rune(QUEEN): QUEEN, rune(KING): KING, rune(ACE): ACE, } suitMap := map[rune]Suit{ rune(SPADE): SPADE, rune(HEART): HEART, rune(DIAMOND): DIAMOND, rune(CLUB): CLUB, } var rank Rank var suit Suit for r := range rankMap { if strings.ContainsRune(card, r) { rank = rankMap[r] break } } for s := range suitMap { if strings.ContainsRune(card, s) { suit = suitMap[s] break } } 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 cardStrings := strings.Split(cards, ",") newCards := make(Cards, len(cardStrings)) for i, cardString := range cardStrings { card, err := NewCardFromString(cardString) if err != nil { return nil, err } newCards[i] = card } if len(newCards) == 0 { return nil, 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 (cards Cards) First() Card { return cards[0] } func (cards Cards) Second() Card { return cards[1] } func (cards Cards) Third() Card { return cards[2] } func (cards Cards) Fourth() Card { return cards[3] } func (cards Cards) Fifth() Card { return cards[4] } func (cards Cards) Last() Card { return cards[len(cards)-1] } func (cards Cards) SortByRankAscending() Cards { sortedCards := make(Cards, len(cards)) copy(sortedCards, cards) sort.Slice(sortedCards, func(i, j int) bool { return sortedCards[i].Rank.Score() < sortedCards[j].Rank.Score() }) return sortedCards } func (cards Cards) PrintToTerminal() { fmt.Printf("%s", cards.FormatForTerminal()) } type SortOrder int const ( AceHighAscending SortOrder = iota AceHighDescending ) func (cards Cards) FormatForTerminalSorted(order SortOrder) string { sorted := cards.SortByRankAscending() // this is ascending if order == AceHighDescending { slices.Reverse(sorted) } return sorted.FormatForTerminal() } func (cards Cards) FormatForTerminal() string { var cardstrings []string for i := 0; i < len(cards); i++ { cardstrings = append(cardstrings, cards[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 (cards Cards) HighestRank() Rank { sorted := cards.SortByRankAscending() return sorted[len(sorted)-1].Rank } func (cards Cards) String() string { var cardstrings []string for i := 0; i < len(cards); i++ { cardstrings = append(cardstrings, cards[i].String()) } return strings.Join(cardstrings, ",") }