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