From fc5e2afaac0889d78cc97d9de15459b251999ef1 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Mon, 22 Dec 2025 16:45:48 +0100 Subject: [PATCH] Refactor into classes --- Hands to be tested.txt | 44 +++++ Texas HoldEm Hand comparison test cases.xlsx | Bin 0 -> 12474 bytes card.go | 6 + hand.go | 185 +++++++++++++++++++ main.go | 120 ++++++++++++ poker_test.go | 85 +++++++++ 6 files changed, 440 insertions(+) create mode 100644 Hands to be tested.txt create mode 100644 Texas HoldEm Hand comparison test cases.xlsx create mode 100644 card.go create mode 100644 hand.go create mode 100644 main.go create mode 100644 poker_test.go diff --git a/Hands to be tested.txt b/Hands to be tested.txt new file mode 100644 index 0000000..9abe50e --- /dev/null +++ b/Hands to be tested.txt @@ -0,0 +1,44 @@ +// royal flush +"CT CJ CQ CK CA" + +// straight flush +"D8 D9 DT DJ DQ" +"H7 H8 H9 HT HJ" + +// four of a kind +"HT SQ ST DT CT" +"HT SK ST DT CT" +"H8 SQ S8 D8 C8" +"H7 SK S7 D7 C7" + +// full house +"H2 SQ C2 D2 CQ" +"H2 SJ C2 D2 CJ" + +// flush +"HK HQ H2 H4 H5" +"D5 D4 D2 DQ DK" + +// straight +"H3 S7 H5 D6 H4" +"C9 CT SJ D7 H8" +"H4 S5 HA D3 H2" + + +// three of a kind +"H2 SQ S2 D2 CK" +"H2 S7 S2 D2 C9" +"H2 S8 S2 D2 C9" + +// two pairs +"H5 SQ C5 DT CT" +"H9 SQ C9 DT CT" + +// one pair +"H3 S8 H5 D8 CA" +"S4 DA H3 CA HT" + +// high card +"H3 S8 H5 DK CA" +"H3 S8 H5 DK CT" +"H3 S8 H5 DK C2" \ No newline at end of file diff --git a/Texas HoldEm Hand comparison test cases.xlsx b/Texas HoldEm Hand comparison test cases.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..dab0251e38470d61d109182d8ba85cf3fe332fd4 GIT binary patch literal 12474 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 literal 0 HcmV?d00001 diff --git a/card.go b/card.go new file mode 100644 index 0000000..be81a77 --- /dev/null +++ b/card.go @@ -0,0 +1,6 @@ +package main + +type Card struct { + Suit string // H, D, C, S + Value int // 2-14 (A=14) +} \ No newline at end of file diff --git a/hand.go b/hand.go new file mode 100644 index 0000000..3016787 --- /dev/null +++ b/hand.go @@ -0,0 +1,185 @@ +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 +} \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..a38f0fd --- /dev/null +++ b/main.go @@ -0,0 +1,120 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +// --- Testing --- + +func parseFile(path string) { + file, _ := os.Open(path) + if file == nil { + fmt.Println("Could not open file:", path) + return + } + defer file.Close() + + fscanner := bufio.NewScanner(file) + for fscanner.Scan() { + var input = fscanner.Text() + input = strings.TrimSpace(input) + + if len(input) == 0 { + continue + } + + if strings.HasPrefix(input, "//") { + input = strings.Trim(input, "/ ") + fmt.Printf("\n=== %s ===\n", input) + continue + } + + input = strings.Trim(input, "\",") + + hand, err := NewHand(input) + if err != nil { + fmt.Println("Error:", err) + continue + } + + result := hand.Evaluate() + fmt.Printf("Input: [%s]\nResult: %s\n", input, handNames[result.Category]) + } +} + +// Reads all hands and compares them against each other +func compareFileAllVsAll(path string) { + file, err := os.Open(path) + if err != nil { + fmt.Println("Error opening file:", err) + return + } + defer file.Close() + + type SavedHand struct { + Raw string + Hand *Hand + } + var allHands []SavedHand + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + + if len(line) == 0 || strings.HasPrefix(line, "//") { + continue + } + + cleanLine := strings.Trim(line, "\",") + + hand, err := NewHand(cleanLine) + if err != nil { + continue + } + + allHands = append(allHands, SavedHand{Raw: cleanLine, Hand: hand}) + } + + count := 0 + for i := 0; i < len(allHands); i++ { + for j := i; j < len(allHands); j++ { + h1 := allHands[i] + h2 := allHands[j] + + winner := h1.Hand.Compare(h2.Hand) + + fmt.Printf("Comparison: [%s] vs [%s]\n", h1.Raw, h2.Raw) + + h1Result := h1.Hand.Evaluate() + h2Result := h2.Hand.Evaluate() + + switch winner { + case 1: + fmt.Printf("Winner: Hand 1 (%s beats %s)\n", handNames[h1Result.Category], handNames[h2Result.Category]) + case 2: + fmt.Printf("Winner: Hand 2 (%s beats %s)\n", handNames[h2Result.Category], handNames[h1Result.Category]) + default: + fmt.Printf("Tie: %s\n", handNames[h1Result.Category]) + } + + fmt.Println() + count++ + } + } + fmt.Printf("Total comparisons: %d\n", count) +} + +// --- Main --- + +func main() { + filename := "Hands to be tested.txt" + + fmt.Println("--- Task 1a: Single Evaluation ---") + parseFile(filename) + + fmt.Println("\n--- Task 1b: Comparison (All vs All) ---") + compareFileAllVsAll(filename) +} \ No newline at end of file diff --git a/poker_test.go b/poker_test.go new file mode 100644 index 0000000..d5ab06a --- /dev/null +++ b/poker_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "testing" +) + +func TestRoyalFlush(t *testing.T) { + hand, _ := NewHand("CT CJ CQ CK CA") + result := hand.Evaluate() + if result.Category != RoyalFlush { + t.Errorf("Expected RoyalFlush, got %s", handNames[result.Category]) + } +} + +func TestStraightFlush(t *testing.T) { + hand, _ := NewHand("D8 D9 DT DJ DQ") + result := hand.Evaluate() + if result.Category != StraightFlush { + t.Errorf("Expected StraightFlush, got %s", handNames[result.Category]) + } +} + +func TestFourOfAKind(t *testing.T) { + hand, _ := NewHand("HT SQ ST DT CT") + result := hand.Evaluate() + if result.Category != FourOfAKind { + t.Errorf("Expected FourOfAKind, got %s", handNames[result.Category]) + } +} + +func TestFullHouse(t *testing.T) { + hand, _ := NewHand("H2 SQ C2 D2 CQ") + result := hand.Evaluate() + if result.Category != FullHouse { + t.Errorf("Expected FullHouse, got %s", handNames[result.Category]) + } +} + +func TestFlush(t *testing.T) { + hand, _ := NewHand("HK HQ H2 H4 H5") + result := hand.Evaluate() + if result.Category != Flush { + t.Errorf("Expected Flush, got %s", handNames[result.Category]) + } +} + +func TestStraight(t *testing.T) { + hand, _ := NewHand("H3 S7 H5 D6 H4") + result := hand.Evaluate() + if result.Category != Straight { + t.Errorf("Expected Straight, got %s", handNames[result.Category]) + } +} + +func TestThreeOfAKind(t *testing.T) { + hand, _ := NewHand("H2 SQ S2 D2 CK") + result := hand.Evaluate() + if result.Category != ThreeOfAKind { + t.Errorf("Expected ThreeOfAKind, got %s", handNames[result.Category]) + } +} + +func TestTwoPair(t *testing.T) { + hand, _ := NewHand("H5 SQ C5 DT CT") + result := hand.Evaluate() + if result.Category != TwoPair { + t.Errorf("Expected TwoPair, got %s", handNames[result.Category]) + } +} + +func TestPair(t *testing.T) { + hand, _ := NewHand("H3 S8 H5 D8 CA") + result := hand.Evaluate() + if result.Category != Pair { + t.Errorf("Expected Pair, got %s", handNames[result.Category]) + } +} + +func TestHighCard(t *testing.T) { + hand, _ := NewHand("H3 S8 H5 DK CA") + result := hand.Evaluate() + if result.Category != HighCard { + t.Errorf("Expected HighCard, got %s", handNames[result.Category]) + } +} \ No newline at end of file