Skip to content

Instantly share code, notes, and snippets.

@yangchenyun
Created May 23, 2019 00:26
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 yangchenyun/103bceb5f764655fbc2b604f3c977e3f to your computer and use it in GitHub Desktop.
Save yangchenyun/103bceb5f764655fbc2b604f3c977e3f to your computer and use it in GitHub Desktop.
Poker hands
// # Determine Winning Poker Hand
// Design a program to determine the winner of a
// [poker](https://en.wikipedia.org/wiki/Poker) game.
// The order of a card would be described as "23456789TJQKA", the suit of a card
// would be described as "HSCD" (**H**eart, **S**pade, **C**lub, **D**iamond). Each card
// would be presented by two characters, i.e. "9D", "KC" etc.
// You would be given a list of hands as a text file, each line represents a
// player's hand. Your program should output the winning hand (or hands if they are
// tied.)
// The winning rules for hand rankings could be found at:reverse
// https://www.cardplayer.com/rules-of-poker/hand-rankings. In the event of a tie:
// Highest card wins, and if necessary, the second-highest, third-highest,
// fourth-highest and smallest card can be used to break the tie.
// Example
// ```text
// input:
// 6C 7C 8C 9C TC
// 9D 9H 9S 9C 7D
// TD TC TH 7C 7D
// output:
// 6C 7C 8C 9C TC
// ```
// ```text
// input:
// TD TC TH 7C 7D
// TD TC TH 8C 8D
// output:
// TD TC TH 8C 8D
// ```
// Looking for correctness and good code design.
package main
import (
"fmt"
"sort"
"strconv"
"strings"
)
var (
example1 = [][]string {
{"6C", "7C", "8C", "9C", "TC"},
{"9D", "9H", "9S", "9C", "7D"},
{"TD", "TC", "TH", "7C", "7D"},
}
example1output = []string{"6C", "7C", "8C", "9C", "TC"}
example2 = [][]string{
{"TD","TC","TH","7C","7D"},
{"TD","TC","TH","8C","8D"},
}
example2output = []string {"TD","TC","TH","8C","8D"}
example3 = [][]string{
{"TD","TC","TH","8C","8D"},
{"TD","TC","TH","8C","8D"},
}
example3output = []string {"TD","TC","TH","8C","8D"}
)
type Card struct {
Suit string
Rank int
raw string
}
func (c Card) ToString() string {
return c.raw
}
type Hand []Card
func (h Hand) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
func (h Hand) Len() int {
return len(h)
}
func (h Hand) Less(i, j int) bool {
return h[i].Rank < h[j].Rank
}
func (h Hand) Flush() bool {
for i := 0; i < len(h)-1; i++ {
if h[i].Suit != h[i+1].Suit {
return false
}
}
return true
}
func (h Hand) Straight() bool {
sort.Sort(h)
diff := h[len(h)-1].Rank - h[0].Rank
return diff == 4
}
func (h Hand) HighCard() Card {
sort.Sort(h)
return h[len(h)-1]
}
func (h Hand) Type() Kind {
hist := GetSubHands(h)
kind := evaluateRankHistogram(hist)
flush := h.Flush()
straight := h.Straight()
if straight && flush {
if h.HighCard().Rank == 14 {
return RoyalFlush
} else {
return StraightFlush
}
} else if straight {
return Straight
} else if flush {
return Flush
}
return kind
}
func (h Hand) resolveFlushes(other Hand) (bool, bool) {
h = sort.Reverse(h).(Hand)
other = sort.Reverse(other).(Hand)
for i := 0; i < len(h) && i < len(other); i++ {
if h[i].Rank > other[i].Rank {
return true, false
}
if h[i].Rank < other[i].Rank {
return false, false
}
}
return false, true
}
func (h Hand) resolveSubHands(other Hand) (bool, bool) {
subHands := GetSubHands(h)
otherSubHands := GetSubHands(other)
// Special Case Two Pair, put the highest rank pair first
if len(subHands) == 3 && len(subHands[0]) == 2 { //2, 2, 1
if subHands[0][0].Rank < subHands[1][0].Rank {
subHands[0], subHands[1] = subHands[1], subHands[0]
}
if otherSubHands[0][0].Rank < otherSubHands[1][0].Rank {
otherSubHands[0], otherSubHands[1] = otherSubHands[1], otherSubHands[0]
}
}
for i := 0; i < len(subHands) && i < len(otherSubHands); i++ {
if subHands[i][0].Rank > otherSubHands[i][0].Rank {
return true, false
}
if subHands[i][0].Rank < otherSubHands[i][0].Rank {
return false, false
}
}
return false, true
}
func (h Hand) Trumps(other Hand) (bool, bool) {
t := h.Type()
ot := other.Type()
if t < ot {
return true, false
}
if t > ot {
return false, false
}
switch t {
case Straight:
fallthrough
case StraightFlush:
fallthrough
case HighCard:
return h.HighCard().Rank > other.HighCard().Rank, false
case Flush:
return h.resolveFlushes(other)
case FourKind:
fallthrough
case ThreeKind:
fallthrough
case FullHouse:
fallthrough
case TwoPair:
fallthrough
case OnePair:
return h.resolveSubHands(other)
}
return false, true
}
func (h Hand) ToString() string {
out := make([]string, len(h))
for i, c := range h {
out[i] = c.ToString()
}
return strings.Join(out, " ")
}
func NewHandFromStringArray(s []string) (Hand) {
out := make([]Card, len(s))
for i, h := range s {
rank := h[0:1]
suit := h[1:2]
var r int
// "23456789TJQKA"
switch rank {
case "A":
r = 14 //
case "T":
r = 10
case "J":
r = 11
case "Q":
r = 12
case "K":
r = 13
default:
r , _ = strconv.Atoi(rank)
}
// "HSCD"
out[i].Suit = suit
out[i].Rank = r
out[i].raw = h
}
return out
}
type Kind int
const (
RoyalFlush Kind = iota
StraightFlush
FourKind
FullHouse
Flush
Straight
ThreeKind
TwoPair
OnePair
HighCard
END
)
func GetSubHands(hand Hand) []Hand {
histogram := make(map[int]Hand)
for _, c := range hand {
histogram[c.Rank] = append(histogram[c.Rank], c)
}
a := make([]Hand, 0)
for _, v := range histogram {
a = append(a, v)
}
sort.Slice(a, func(i, j int) bool {
return len(a[i]) > len(a[j])
})
return a
}
func evaluateSubHand(a Hand) Kind {
if len(a) == 4 {
return FourKind
}
if len(a) == 3 {
return ThreeKind
}
if len(a) == 2 {
return OnePair
}
return HighCard
}
func evaluateRankHistogram(a []Hand) Kind {
kinds := make([]Kind, 0)
for _, h := range a {
k := evaluateSubHand(h)
kinds = append(kinds, k)
}
kind := kinds[0]
for i := 1; i < len(kinds); i++ {
k := kinds[i]
if kind == ThreeKind && k == OnePair {
kind = FullHouse
} else if kind == OnePair && k == OnePair {
kind = TwoPair
}
}
return kind
}
func main() {
winners := make([]Hand, 0)
for _, h := range example1 {
hand := NewHandFromStringArray(h)
if len(winners) == 0 {
winners = append(winners, hand)
} else {
win, tie := hand.Trumps(winners[0])
if win {
winners = []Hand{hand}
} else if tie {
winners = append(winners, hand)
}
}
}
output := make([]string, 0)
for _, hand := range winners {
output = append(output, hand.ToString())
}
fmt.Printf("%v=%v", example1output, output)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment