Files
2025-12-22 16:46:08 +01:00

223 lines
5.2 KiB
Go

package main
import (
"fmt"
"sort"
"strings"
)
type Hand struct {
Cards []Card
}
// NewHand parses an input string and returns a new Hand.
func NewHand(input string) (*Hand, error) {
parts := strings.Fields(input)
if len(parts) != 5 {
return nil, fmt.Errorf("invalid number of cards: %d", len(parts))
}
var cards []Card
valueMap := map[byte]int{
'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14,
}
for _, p := range parts {
if len(p) != 2 {
return nil, fmt.Errorf("invalid card format: %s", p)
}
suitChar := string(p[0])
valChar := p[1]
val, ok := valueMap[valChar]
if !ok {
return nil, fmt.Errorf("invalid value: %c", valChar)
}
cards = append(cards, Card{Suit: suitChar, Value: val})
}
return &Hand{Cards: cards}, nil
}
type HandCategory int
const (
HighCard HandCategory = iota
Pair
TwoPair
ThreeOfAKind
Straight
Flush
FullHouse
FourOfAKind
StraightFlush
RoyalFlush
)
var handNames = []string{
"High Card", "Pair", "Two Pair", "Three of a Kind", "Straight",
"Flush", "Full House", "Four of a Kind", "Straight Flush", "Royal Flush",
}
type HandResult struct {
Category HandCategory
TieBreakers []int
}
// Evaluate evaluates the hand and returns its category and tiebreakers.
func (h *Hand) Evaluate() HandResult {
sort.Slice(h.Cards, func(i, j int) bool {
return h.Cards[i].Value > h.Cards[j].Value
})
counts := make(map[int]int)
suits := make(map[string]int)
for _, c := range h.Cards {
counts[c.Value]++
suits[c.Suit]++
}
isFlush := len(suits) == 1
isStraight, straightHigh := h.checkStraight()
if isFlush && isStraight {
if straightHigh == 14 {
return HandResult{Category: RoyalFlush, TieBreakers: []int{}}
}
return HandResult{Category: StraightFlush, TieBreakers: []int{straightHigh}}
}
type group struct {
val int
count int
}
var groups []group
for v, c := range counts {
groups = append(groups, group{v, c})
}
sort.Slice(groups, func(i, j int) bool {
if groups[i].count != groups[j].count {
return groups[i].count > groups[j].count
}
return groups[i].val > groups[j].val
})
var tieBreakers []int
for _, g := range groups {
tieBreakers = append(tieBreakers, g.val)
}
if len(groups) > 1 && groups[0].count == 1 {
// Fallback for Straight/Flush Sortierung: sicherstellen, dass es rein nach Wert geht
tieBreakers = nil
for _, c := range h.Cards {
tieBreakers = append(tieBreakers, c.Value)
}
}
if groups[0].count == 4 {
return HandResult{Category: FourOfAKind, TieBreakers: []int{groups[0].val, groups[1].val}}
}
if groups[0].count == 3 && groups[1].count == 2 {
return HandResult{Category: FullHouse, TieBreakers: []int{groups[0].val, groups[1].val}}
}
if isFlush {
return HandResult{Category: Flush, TieBreakers: tieBreakers}
}
if isStraight {
return HandResult{Category: Straight, TieBreakers: []int{straightHigh}}
}
if groups[0].count == 3 {
return HandResult{Category: ThreeOfAKind, TieBreakers: []int{groups[0].val, groups[1].val, groups[2].val}}
}
if groups[0].count == 2 && groups[1].count == 2 {
return HandResult{Category: TwoPair, TieBreakers: []int{groups[0].val, groups[1].val, groups[2].val}}
}
if groups[0].count == 2 {
return HandResult{Category: Pair, TieBreakers: []int{groups[0].val, groups[1].val, groups[2].val, groups[3].val}}
}
return HandResult{Category: HighCard, TieBreakers: tieBreakers}
}
func (h *Hand) checkStraight() (bool, int) {
isStd := true
for i := 0; i < 4; i++ {
if h.Cards[i].Value != h.Cards[i+1].Value+1 {
isStd = false
break
}
}
if isStd {
return true, h.Cards[0].Value
}
if h.Cards[0].Value == 14 && h.Cards[1].Value == 5 && h.Cards[2].Value == 4 && h.Cards[3].Value == 3 && h.Cards[4].Value == 2 {
return true, 5
}
return false, 0
}
// Compare compares the current hand with another hand.
// Returns 1 if the current hand wins, 2 if the other hand wins, and 0 for a tie.
func (h *Hand) Compare(other *Hand) int {
h1Result := h.Evaluate()
h2Result := other.Evaluate()
if h1Result.Category > h2Result.Category {
return 1
}
if h2Result.Category > h1Result.Category {
return 2
}
for i := 0; i < len(h1Result.TieBreakers); i++ {
if h1Result.TieBreakers[i] > h2Result.TieBreakers[i] {
return 1
}
if h2Result.TieBreakers[i] > h1Result.TieBreakers[i] {
return 2
}
}
return 0
}
// FindBestHand finds the best 5-card hand from 7 given cards.
func FindBestHand(sevenCards []Card) (*Hand, error) {
if len(sevenCards) != 7 {
return nil, fmt.Errorf("expected 7 cards, got %d", len(sevenCards))
}
var bestHand *Hand
// Generate all combinations of 5 cards from 7
for i := 0; i < 7; i++ {
for j := i + 1; j < 7; j++ {
for k := j + 1; k < 7; k++ {
for l := k + 1; l < 7; l++ {
for m := l + 1; m < 7; m++ {
currentCards := []Card{
sevenCards[i], sevenCards[j], sevenCards[k], sevenCards[l], sevenCards[m],
}
currentHand := &Hand{Cards: currentCards}
if bestHand == nil {
bestHand = currentHand
} else {
// Compare currentHand with bestHand
// h.Compare(other) returns 1 if h wins, 2 if other wins, 0 for tie
if currentHand.Compare(bestHand) == 1 {
bestHand = currentHand
}
}
}
}
}
}
}
return bestHand, nil
}