ID:192608
 
Does anyone have any idea where I might find an algorithm to determine a winning poker hand from a group of hands. Preferably something in C or C++ as I am at least able to read that a bit. I am realizing that this is not the least bit trivial...

I'm sure I could write you one, but it'd be in BYOND. I would hope that you could understand it... I just took a $1000 course on writing concise code and constructive comments to improve code efficiency and reworkability. :-)
You're asking the wrong bunch... if you need some code that can analyze hands, you should ask gamblers. Just go to a casino and announce that you're looking for a system for counting cards.
In response to Lesbian Assassin
heh

Well, Im not looking for a playing AI, I just want something that can compare a group of hands and declare a winner. I found a diagram of an algorithm, which I'm trying to convert to code.
In response to Flick
Well, Im not looking for a playing AI, I just want something that can compare a group of hands and declare a winner. I found a diagram of an algorithm, which I'm trying to convert to code.

Drummond Cribbage has code for this, and you could probably use it, or at least the general idea of it. If you like, send me a reminder at [email protected] and I'll send you the relevant code tonight.
Flick wrote:
Does anyone have any idea where I might find an algorithm to determine a winning poker hand from a group of hands. Preferably something in C or C++ as I am at least able to read that a bit. I am realizing that this is not the least bit trivial... <sigh>

I think this'll be a lot easier in BYOND, so here's my whack at it (untested):
/*
Poker hand comparison:

PokerHand() - Returns a list. The highest hand is determined by comparing
lists; whoever has the first highest element wins. The first
element will always be the type of hand, usually followed by
the high card in the hand. Knowing the exact format doesn't
matter. (Suits are not ranked to break ties.)

- Before calling these procs, change all wilds in a hand to -1
HighHand() - Returns the holder of the highest hand, or a list if the winners are tied
LowHand() - Returns the holder of the lowest hand, or a list if the winners are tied

Card designations:
- Card = Suit + Number
- Suits are 100-400
- Number 1-13 (A=1, J=11, Q=12, K=13)
- Wilds are -1

Service procs:

HighKind() - Finds the highest-ranked card, pair, or n of a kind (excluding wilds)
AceHigh() - Converts a 1-13 designation to 2-14 (changes 1 to 14); expects no suits
HighCard() - Sorts a list of remaining cards in the hand (list is modified); suits stripped
AllInSuit() - Creates a new list as a subset of a list of cards, with all the cards in a suit (1-4)
GetStraight() - Creates a new list as a subset, with all the cards in a known straight
Aces() - Pads a list with suitless aces, representing wild cards
*/


var/const/HAND_HIGH=1
var/const/HAND_PAIR=2
var/const/HAND_2PAIR=3
var/const/HAND_3KIND=4
var/const/HAND_ST=5
var/const/HAND_FLUSH=6
var/const/HAND_FHOUSE=7
var/const/HAND_4KIND=8
var/const/HAND_STFLUSH=9
var/const/HAND_5KIND=10


// hands is an associative list, player=cards
proc/HighHand(list/hands,lowhand)
var/list/best=list()
for(var/handholder in hands)
var/list/challenger=PokerHand(hands[handholder],lowhand)
if(!best.len)
best[handholder]=challenger
continue
var/list/champ=best[best[1]]
var/i
for(i in 1 to min(champ.len,challenger.len))
if(champ[i]==challenger[i]) continue
if(champ[i]<challenger[i])
best=list()
best[handholder]=challenger
break
if(i>=champ.len || i>=challenger.len)
if(challenger.len<champ.len) continue
if(challenger.len>champ.len) best=list()
best[handholder]=challenger
if(best.len==1) return best[1]
return best

proc/LowHand(list/hands)
return HighHand(hands,1)

proc/PokerHand(list/cards,lowhand)
// Convention used here: Suits 100-400 + Number 1-13 (Ace=1)
// Wild = -1
var
c;c2;k
cards=cards.Copy()
if(lowhand)
// switch around 2-K range to K-2 (15-n)
for(k in 1 to cards.len)
if(cards[i]>=0 && cards[i]%100>1) cards[i]+=15-(cards[i]%100)*2
var/list/kind=list(0,0,0,0,0,0,0,0,0,0,0,0,0)
var/list/ofsuit=list(0,0,0,0)
var/nwild=0
while(-1 in cards) nwild+=cards.Remove(-1)
var/nearflush=0
for(c in cards)
nearflush=max(nearflush,++ofsuit[round(c/100)])
++kind[c%100]
var/highkind=HighKind(kind) // find highest card, pair, etc.
// find a straight; allow A-5 up to 10-A
var/straight=0
for(c in 4 to 13)
k=nwild
for(c2=c,(c2>=c-4 && k>=0),--c2)
var/c3=(c2%13)+1
if(!kind[c3]) --k
if(k>=0)
straight=(c%13)+1
// find straight flush -- not the same as (flush && straight) with more than 5 cards
var/stflush=0
for(c in 4 to 13)
var/suits=list(nwild,nwild,nwild,nwild)
for(c2=c,(c2>=c-4 && k>=0),--c2)
var/c3=(c2%13)+1
for(k in 1 to suits.len)
if((k*100+c3) in cards) continue
--suits[k]
for(k in 1 to suits.len)
if(suits[k]>=0)
stflush=(c%13)+1+k*100
// Find a second pair, if there is one
var/pair2=HighKind(kind,highkind)
// 5 of a kind -- highest possible hand
if(kind[highkind]+nwild>=5)
var/padwild=nwild-(5-kind[highkind])
return list(HAND_5KIND,AceHigh(highkind))+Aces(padwild)+HighCard(cards,highkind)
// Royal or straight flush
if(stflush)
var/list/thestraight=GetStraight(AllInSuit(cards,round(stflush/100)),stflush%100)
var/padwild=nwilds-max(5-thestraight.len,0)
return list(HAND_STFLUSH,AceHigh(straight))+Aces(padwild)+HighCard(cards-thestraight)
// 4 of a kind
if(kind[highkind]+nwild>=4)
return list(HAND_4KIND,AceHigh(highkind))+HighCard(cards,highkind)
// Full house
if(kind[highkind]+nwild>=3 && kind[pair2]>=2)
return list(HAND_FHOUSE,AceHigh(highkind),AceHigh(pair2))+HighCard(cards,highkind,pair2)
// Flush
if(nearflush+nwild>=5)
var/list/bestflush // in the unlikely case of 8+ cards
for(var/suit=1 to 4)
if(ofsuit[suit]+nwild<5) continue // nobody cares about this suit
var/list/theflush=AllInSuit(cards,suit,5-nwild)
if(!bestflush) bestflush=theflush
else if(theflush.len>bestflush.len) bestflush=theflush
else if(theflush.len<bestflush.len) continue
else
for(k in 1 to theflush.len)
var/compare=AceHigh(theflush[k]%100)-AceHigh(bestflush[k]%100)
if(!compare) continue
if(compare>0) bestflush=theflush
break
cards-=bestflush
return list(HAND_FLUSH)+Aces(nwild)+HighCard(bestflush)+HighCard(cards)
// Straight
if(straight)
var/thestraight=GetStraight(cards,straight)
var/padwild=nwilds-max(5-thestraight.len,0)
return list(HAND_ST,AceHigh(straight))+Aces(padwild)+HighCard(cards-thestraight)
// 3 of a kind
if(kind[highkind]+nwild>=3)
return list(HAND_3KIND,AceHigh(highkind))+HighCard(cards,highkind)
// 2 pair (this hand is impossible with wilds)
if(kind[highkind]>=2 && kind[pair2]>=2)
return list(HAND_2PAIR,AceHigh(highkind),AceHigh(pair2))+HighCard(cards,highkind,pair2)
// Pair
if(kind[highkind]+nwild>=2)
return list(HAND_PAIR,AceHigh(highkind))+HighCard(cards,highkind)
// High card
return list(HAND_HIGH)+HighCard(cards)

// find the highest or 2nd-highest card, pair, of n of a kind
proc/HighKind(list/kind,exclude)
var/highkind
for(var/c in 1 to 13)
var/c2=(c%13)+1
if(!kind[c2]) continue
if(exclude && c2==exclude) continue // find 2nd highest
if(!highkind || kind[c2]>=kind[highkind]) highkind=c2

proc/AceHigh(n)
return (n>=2)?(n):(n+13)

// sort cards and throw away suit; change aces from 1 to 14
// exclude any cards listed in extra args
proc/HighCard(list/cards)
var
c;i;j;k
for(i=1,i<=cards.len,++i)
c=cards[i]%100
if(args.len>1)
if(args.Find(c,2))
cards.Cut(i,i+1)
--i
continue
cards[i]=AceHigh(c)
for(i in 1 to cards.len-1)
k=i
c=cards[k]
for(j in i+1 to cards.len)
if(cards[j]>c)
k=j
c=cards[k]
if(k!=i)
c=cards[i]
cards[i]=cards[k]
cards[k]=c
return cards

proc/AllInSuit(list/cards,suit,maxlen)
var/list/ofsuit=list()
for(var/c in cards)
if(round(c/100)==suit)
ofsuit+=c
if(maxlen && ofsuit.len>=maxlen) break
return ofsuit

// assume this is a valid straight; skip spots for wild cards
proc/GetStraight(list/cards,straight)
var/list/st=list()
var
c;c2;c3
for(c=straight,c>=straight-4,--c)
c2=(c<1)?(c+13):c
for(c3 in cards)
if(c3%100==c2)
st+=cd
break
return st

proc/Aces(nwild)
var/list/aces=list()
while(aces.len<nwild) aces+=14
return aces

Lummox JR
In response to Lummox JR
Yet again, you post a code that make me want to jump off a bridge.
In response to Lummox JR
Hey look! Theres one now.

Thanks Lummox, I'll play with that for a while and see if I can get it working.
In response to Flick
Flick wrote:
Hey look! Theres one now.

Thanks Lummox, I'll play with that for a while and see if I can get it working.

I found a few errors in it when I finally got a chance to compile. I've got it working now, although the sorting on low hands doesn't seem to be quite right. I'll try to tweak it more over the next couple of days.

Lummox JR