mirror of
https://github.com/Stone-Red-Code/se-poker.git
synced 2026-09-04 00:56:18 +02:00
Refactor into classes
This commit is contained in:
@@ -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.
@@ -0,0 +1,6 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type Card struct {
|
||||||
|
Suit string // H, D, C, S
|
||||||
|
Value int // 2-14 (A=14)
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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])
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user