Created
November 13, 2023 01:15
-
-
Save 17twenty/524aa2bc667d35b3a6a50c18a86eb6a4 to your computer and use it in GitHub Desktop.
Poker Hands in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"cmp" | |
"log" | |
"math/rand" | |
"os" | |
"strconv" | |
"golang.org/x/exp/slices" | |
) | |
var ( | |
cards = []string{ | |
"AD", "KD", "QD", "JD", "10D", "9D", "8D", "7D", "6D", "5D", "4D", "3D", "2D", | |
"AH", "KH", "QH", "JH", "10H", "9H", "8H", "7H", "6H", "5H", "4H", "3H", "2H", | |
"AC", "KC", "QC", "JC", "10C", "9C", "8C", "7C", "6C", "5C", "4C", "3C", "2C", | |
"AS", "KS", "QS", "JS", "10S", "9S", "8S", "7S", "6S", "5S", "4S", "3S", "2S", | |
} | |
) | |
// isFlush checks to see if all the cards are the same suit | |
func isFlush(hand []string) bool { | |
s := suit(hand[0]) | |
for i := range hand { | |
if suit(hand[i]) != s { | |
return false | |
} | |
} | |
return true | |
} | |
func isStraight(hand []string) bool { | |
slices.SortFunc(hand, func(a, b string) int { | |
return cmp.Compare(value(a), value(b)) | |
}) | |
runningCount := value(hand[0]) | |
for i := range hand { | |
if value(hand[i]) != runningCount { | |
return false | |
} | |
runningCount++ | |
} | |
return true | |
} | |
func highCard(hand []string) int { | |
slices.SortFunc(hand, func(a, b string) int { | |
return cmp.Compare(value(a), value(b)) | |
}) | |
return value(hand[len(hand)-1]) | |
} | |
func isRoyalFlush(hand []string) bool { | |
return isStraight(hand) && isFlush(hand) && highCard(hand) == 14 | |
} | |
func isStraightFlush(hand []string) bool { | |
return isStraight(hand) && isFlush(hand) | |
} | |
func isFourOfAKind(hand []string) bool { | |
dist := getOccurrences(hand) | |
for _, v := range dist { | |
if v == 4 { | |
return true | |
} | |
} | |
return false | |
} | |
func isThreeOfAKind(hand []string) bool { | |
dist := getOccurrences(hand) | |
for _, v := range dist { | |
if v == 3 { | |
return true | |
} | |
} | |
return false | |
} | |
func getPairs(hand []string) int { | |
pairs := 0 | |
dist := getOccurrences(hand) | |
for _, v := range dist { | |
if v == 2 { | |
pairs++ | |
} | |
} | |
return pairs | |
} | |
func isFullHouse(hand []string) bool { | |
pairings := 0 | |
dist := getOccurrences(hand) | |
for _, v := range dist { | |
if v == 3 { | |
pairings++ | |
} | |
if v == 2 { | |
pairings++ | |
} | |
} | |
// I don't like this function. It used to match on 2 pairs due to the count | |
// So i just removed the ability for it to happen by checking the pairings | |
// in the distribution | |
return pairings == 2 && len(dist) == 2 | |
} | |
func getOccurrences(hand []string) map[int]int { | |
dict := map[int]int{} | |
for _, v := range hand { | |
dict[value(v)]++ | |
} | |
return dict | |
} | |
func suit(card string) string { | |
switch card[len(card)-1] { | |
case 'D': | |
return "Diamonds" | |
case 'H': | |
return "Hearts" | |
case 'C': | |
return "Clubs" | |
case 'S': | |
return "Spades" | |
} | |
return "Unknown" | |
} | |
func handRank(hand []string) (string, int) { | |
if isRoyalFlush(hand) { | |
return "Royal Flush", 9 | |
} | |
if isStraightFlush(hand) { | |
return "Straight flush", 8 | |
} | |
if isFourOfAKind(hand) { | |
return "Four Of A Kind", 7 | |
} | |
if isFullHouse(hand) { | |
return "Full House", 6 | |
} | |
if isFlush(hand) { | |
return "Flush", 5 | |
} | |
if isStraight(hand) { | |
return "Straight", 4 | |
} | |
if isThreeOfAKind(hand) { | |
return "Three Of A Kind", 3 | |
} | |
if getPairs(hand) == 2 { | |
return "Two Pair", 2 | |
} | |
if getPairs(hand) == 1 { | |
return "Pair", 1 | |
} | |
return "", 0 | |
} | |
func value(card string) int { | |
switch card[0] { | |
case 'A': | |
return 14 | |
case 'K': | |
return 13 | |
case 'Q': | |
return 12 | |
case 'J': | |
return 11 | |
default: | |
v, _ := strconv.Atoi(string(card[0 : len(card)-1])) | |
return v | |
} | |
} | |
func main() { | |
// for i := range cards { | |
// log.Println(value(cards[i]), "of", suit(cards[i])) | |
// } | |
// log.Println("isStraigh?", isStraight([]string{"2D", "3D", "AD", "8D", "4D"})) | |
// log.Println("isStraigh?", isStraight([]string{"2D", "3D", "4D", "5D", "6D"})) | |
// log.Println("isFlush?", isFlush([]string{"AC", "10D", "5D", "4D", "2D"})) | |
// log.Println("isFlush?", isFlush([]string{"AD", "10D", "5C", "4D", "2D"})) | |
tests := [][]string{ | |
{"10D", "KD", "QD", "JD", "AD"}, // Royal flush | |
{"5D", "6D", "7D", "8D", "9D"}, // Straight Flush | |
{"10D", "10C", "10S", "10H", "AD"}, // Four of a kind | |
{"10D", "10C", "10S", "4H", "4D"}, // Full house | |
{"2D", "3D", "AD", "8D", "4D"}, // Flush | |
{"5D", "6C", "7H", "8C", "9D"}, // Straight | |
{"10D", "10C", "10S", "4H", "3D"}, // Three of a kind | |
{"10D", "10C", "8H", "8D", "3D"}, // Two Pair | |
{"10D", "10C", "4S", "2H", "3D"}, // Pair | |
// -- | |
{"AD", "10D", "5C", "4D", "2D"}, // High card Ace | |
{"2C", "3H", "4D", "6C", "7D"}, // High card 7D | |
} | |
for i := range tests { | |
log.Println(handRank(tests[i])) | |
} | |
for f := 0; ; f++ { | |
hand1 := []string{} | |
for i := 0; i < 5; i++ { | |
hand1 = append(hand1, cards[rand.Intn(len(cards))]) | |
} | |
hand2 := []string{} | |
for i := 0; i < 5; i++ { | |
hand2 = append(hand2, cards[rand.Intn(len(cards))]) | |
} | |
log.Println("Hands are", hand1, "vs", hand2) | |
res1, val1 := handRank(hand1) | |
res2, val2 := handRank(hand1) | |
if val1 > val2 { | |
log.Println("Hand 1 wins against Hand 2 with", res1) | |
log.Println("Games played", f) | |
os.Exit(0) | |
} else if val1 < val2 { | |
log.Println("Hand 2 wins against Hand 1 with", res2) | |
log.Println("Games played", f) | |
os.Exit(0) | |
} else if val1 == val2 && val1 > 0 { | |
log.Println("Hand 1 draws against Hand 2 with", res1) | |
log.Println("Games played", f) | |
} else { | |
log.Println("It would go to high card") | |
log.Println("hand1", highCard(hand1), "- hand2", highCard(hand2)) | |
} | |
log.Println("... AGAIN!!1") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Should have a check to as Ace can be low too - https://gist.github.com/17twenty/524aa2bc667d35b3a6a50c18a86eb6a4#file-gagaface-go-L38