Skip to content

Instantly share code, notes, and snippets.

@17twenty
Created November 13, 2023 01:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 17twenty/524aa2bc667d35b3a6a50c18a86eb6a4 to your computer and use it in GitHub Desktop.
Save 17twenty/524aa2bc667d35b3a6a50c18a86eb6a4 to your computer and use it in GitHub Desktop.
Poker Hands in Go
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")
}
}
@17twenty
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment