Skip to content

Commit

Permalink
got some of the hand evaluation in there
Browse files Browse the repository at this point in the history
  • Loading branch information
codeslinger committed May 14, 2012
1 parent be66ef2 commit 11ebeca
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 32 deletions.
49 changes: 22 additions & 27 deletions card.go
Expand Up @@ -44,18 +44,22 @@ var suits = []Suit{Club, Diamond, Heart, Spade}
var rankStr = []string{"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"}
var suitStr = []string{"c", "d", "h", "s"}

// ----- PUBLIC API ---------------------------------------------------------
// ----- SUIT PUBLIC API ----------------------------------------------------

// Is this suit valid?
func (suit Suit) Valid() bool {
return !(suit < Club || suit > Spade)
}

// ----- RANK PUBLIC API ----------------------------------------------------

// Is this rank valid?
func (rank Rank) Valid() bool {
return !(rank < Two || rank > Ace)
}

// ----- CARD PUBLIC API ----------------------------------------------------

// Is this card valid?
func (card Card) Valid() bool {
return (card.rank().Valid() && card.suit().Valid())
Expand All @@ -78,35 +82,23 @@ func (card Card) Suit() Suit {
}

// Compare two cards by rank only, returning:
// 1 if this card is higher
// -1 if the other card is higher, or
// 0 if they represent the same card.
// >0 if this card rank is higher
// <0 if the other card rank is higher, or
// 0 if they represent the same card rank.
func (card Card) Compare(other Card) int {
if card.Rank() > other.Rank() {
return 1
} else if card.Rank() < other.Rank() {
return -1
}
return 0
return int(card.Rank() - other.Rank())
}

// Compare two cards by rank first and then suit, returning:
// 1 if this card is higher
// -1 if the other card is higher, or
// 0 if they represent the same card.
// >0 if this card is higher
// <0 if the other card is higher, or
// 0 if they represent the same card.
func (card Card) FullCompare(other Card) int {
if card.Rank() > other.Rank() {
return 1
} else if card.Rank() < other.Rank() {
return -1
} else {
if card.Suit() > other.Suit() {
return 1
} else if card.Suit() < other.Suit() {
return -1
}
cmp := card.Compare(other)
if cmp != 0 {
return cmp
}
return 0
return int(card.Suit() - other.Suit())
}

// Return string representation of this card.
Expand All @@ -121,15 +113,18 @@ func (card Card) ToString() string {
// NOTE: the constructor for a card is private; external code should not be
// creating cards, just using them as part of Decks and Hands
func newCard(suit Suit, rank Rank) (card Card) {
card = Card(((byte(suit) << 4) & 0xF0) | (byte(rank) & 0x0F))
card = Card(((byte(rank) << 4) & 0xF0) | (byte(suit) & 0x0F))
return
}

// NB: we put the rank first in the byte and then the suit so the cards will
// sort properly when converted to integral values

func (card Card) rank() Rank {
return ranks[(byte(card) & 0x0F) - 1]
return ranks[((byte(card) >> 4) & 0x0F) - 1]
}

func (card Card) suit() Suit {
return suits[((byte(card) >> 4) & 0x0F) - 1]
return suits[(byte(card) & 0x0F) - 1]
}

194 changes: 189 additions & 5 deletions hand.go
Expand Up @@ -3,7 +3,11 @@
// detailed licensing information.
package main

// hand ranks
import (
// "sort"
)

// hand ranks in ascending order (i.e. StraightFlush beats all)
const (
NoHandRank = 0
HighCard = 1
Expand All @@ -17,24 +21,204 @@ const (
StraightFlush = 9
)

const HAND_SIZE = 5

type HandRank byte

type Hand struct {
cards []Card
pos int
rank HandRank
}

var handRanks = []HandRank{HighCard, OnePair, TwoPair, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StraightFlush}

func NewHand() *Hand {
// ----- PUBLIC API ---------------------------------------------------------

// Construct a new Hand instance.
func NewHand(maxCards int) *Hand {
hand := new(Hand)
hand.rank = NoHandRank
hand.cards = make([]Card, maxCards)
hand.pos = 0
return hand
}

func (hand *Hand) Rank() HandRank {
return NoHandRank
// Is this hand higher than, lower than or equal to another hand?
// Returns:
// >0 if this hand is higher
// <0 if the other hand is higher
// 0 if they are equal.
func (hand *Hand) Compare(other *Hand) int {
// TODO: implement this
return 0
}

// How many cards are in this hand?
func (hand *Hand) Size() int {
return hand.pos
}

// Deal this hand a card. Attempts to deal this hand more than its maximum
// number of cards (as specified at construction time) will be silently
// ignored.
func (hand *Hand) DealTo(card Card) {
if hand.pos >= len(hand.cards) {
return
}
hand.cards[hand.pos] = card
hand.pos++
}

func (hand *Hand) Evaluate() {
var cards []Card

if cards = hand.copyAndSortCards(); cards == nil {
return
}
if hasStraightFlush(cards) {
hand.rank = StraightFlush
} else if hasQuads(cards) {
hand.rank = FourOfAKind
} else if hasFullHouse(cards) {
hand.rank = FullHouse
} else if hasFlush(cards) {
hand.rank = Flush
} else if hasStraight(cards) {
hand.rank = Straight
} else if hasSet(cards) {
hand.rank = ThreeOfAKind
} else if hasTwoPair(cards) {
hand.rank = TwoPair
} else if hasPair(cards) {
hand.rank = OnePair
} else {
hand.rank = HighCard
}
}

// ----- INTERNAL FUNCTIONS -------------------------------------------------

func (hand *Hand) copyAndSortCards() []Card {
if hand.Size() < 1 {
return nil
}
t := make([]Card, hand.Size())
copy(hand.cards, t)
//sort.Sort(t)
return t
}

func hasStraightFlush(cards []Card) bool {
if len(cards) < 5 {
return false
}
inARow := 0
for i := range cards {
if i > 0 {
rankDiff := byte(cards[i].Rank()) - byte(cards[i - 1].Rank())
suitDiff := byte(cards[i].Suit()) - byte(cards[i - 1].Suit())
if rankDiff == 1 && suitDiff == 0 {
inARow++
if inARow == 4 && cards[i].Rank() == Two && cards[0].Rank() == Ace && cards[0].Suit() == cards[i].Suit() {
// found a Steal Wheel (A-2-3-4-5 of same suit)
inARow++
}
} else if rankDiff != 0 {
inARow = 1
}
}
if inARow == HAND_SIZE {
return true
}
}
return false
}

func hasQuads(cards []Card) bool {
return hasRunOfSameRank(cards, 4)
}

func hasFullHouse(cards []Card) bool {
if len(cards) < 5 {
return false
}
return false
}

func hasFlush(cards []Card) bool {
if len(cards) < 5 {
return false
}
suitsFound := []byte{0, 0, 0, 0}
for i := range cards {
idx := int(cards[i].Suit()) - int(Club)
suitsFound[idx]++
if suitsFound[idx] == HAND_SIZE {
return true
}
}
return false
}

func hasStraight(cards []Card) bool {
if len(cards) < 5 {
return false
}
inARow := 0
for i := range cards {
if i > 0 {
diff := byte(cards[i].Rank()) - byte(cards[i - 1].Rank())
if diff == 1 {
inARow++
if inARow == 4 && cards[i].Rank() == Two && cards[0].Rank() == Ace {
// found a Wheel (A-2-3-4-5)
inARow++
}
} else if diff != 0 {
inARow = 1
}
}
if inARow == HAND_SIZE {
return true
}
}
return false
}

func hasSet(cards []Card) bool {
return hasRunOfSameRank(cards, 3)
}

func hasTwoPair(cards []Card) bool {
if len(cards) < 4 {
return false
}
return false
}

func hasPair(cards []Card) bool {
return hasRunOfSameRank(cards, 2)
}

func (hand *Hand) isStraightFlush() bool {
func hasRunOfSameRank(cards []Card, runLength int) bool {
if len(cards) < runLength {
return false
}
inARow := 0
for i := range cards {
if i > 0 {
diff := byte(cards[i].Rank()) - byte(cards[i - 1].Rank())
if diff == 0 {
inARow++
if inARow == runLength {
return true
}
} else {
inARow = 1
}
}
}
return false
}

0 comments on commit 11ebeca

Please sign in to comment.