Refactor into classes

This commit is contained in:
Stone_Red
2025-12-22 16:45:48 +01:00
parent 1928dcd24f
commit fc5e2afaac
6 changed files with 440 additions and 0 deletions
+44
View File
@@ -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"
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
package main
type Card struct {
Suit string // H, D, C, S
Value int // 2-14 (A=14)
}
+185
View File
@@ -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
}
+120
View File
@@ -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)
}
+85
View File
@@ -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])
}
}