Poker hand analyser: Difference between revisions
Content added Content deleted
m (used more consistent indentations in the task's preamble.) |
m (→{{header|REXX}}: added/changed comments, simplified the function.) |
||
Line 1,759: | Line 1,759: | ||
2x 2h 3h 4h 5h Error: invalid suit x in 2x</pre> |
2x 2h 3h 4h 5h Error: invalid suit x in 2x</pre> |
||
===version 2=== |
===version 2 with suit glyphs=== |
||
This REXX version supports: |
This REXX version supports: |
||
* upper/lower/mixed case for suits and pips |
::* upper/lower/mixed case for suits and pips |
||
* allows commas or blanks for card separation |
::* allows commas or blanks for card separation |
||
* alternate names for |
::* alternate names for aces and tens |
||
* alphabetic letters for suits and/or glyphs |
::* alphabetic letters for suits and/or glyphs |
||
* specification of number of cards in a hand |
::* specification of number of cards in a hand |
||
* the dealt hands can be in a file (blank lines are ignored) |
::* the dealt hands can be in a file (blank lines are ignored) |
||
* dealt hands in the file can have comments after a semicolon (''';''') |
::* dealt hands in the file can have comments after a semicolon (''';''') |
||
<lang rexx>/*REXX program analyzes an N-card poker hand, displays what the hand is.*/ |
<lang rexx>/*REXX program analyzes an N-card poker hand, and displays what the poker hand is. */ |
||
parse arg iFID .; if iFID=='' then iFID='POKERHAN.DAT' |
parse arg iFID .; if iFID=='' | iFID=="," then iFID='POKERHAN.DAT' |
||
/* [↓] read the poker hands dealt*/ |
/* [↓] read the poker hands dealt. */ |
||
do while lines(iFID)\==0; ox=linein(iFID); if ox='' then iterate |
do while lines(iFID)\==0; ox=linein(iFID); if ox='' then iterate |
||
say right(ox,max(30,length(ox))) ' ◄─── ' analyze(ox) |
say right(ox, max(30, length(ox) ) ) ' ◄─── ' analyze(ox) |
||
end /*while*/ /* [↑] analyze/validate the hand |
end /*while*/ /* [↑] analyze/validate the poker hand*/ |
||
exit /*stick a fork in it, we're done.*/ |
exit /*stick a fork in it, we're all done. */ |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
/*──────────────────────────────────ANALYZE subroutine──────────────────*/ |
|||
analyze: procedure; arg x ';',mc; hand=translate(x,'♥♦♣♠1',"HDCSA,") |
analyze: procedure; arg x ';',mc; hand=translate(x, '♥♦♣♠1', "HDCSA,") |
||
kinds=0; suit.=0; flush=0; pairs=0; @.=0; run=copies(0,13); pips=run |
kinds=0; suit.=0; flush=0; pairs=0; @.=0; run=copies(0 ,13); pips=run |
||
if mc=='' then mc=5; n=words(hand); if n\==mc then return 'invalid' |
if mc=='' then mc=5; n=words(hand); if n\==mc then return 'invalid' |
||
/* [↓] PIP can be 1 or 2 |
/* [↓] PIP can be 1 or 2 characters.*/ |
||
do j=1 for n; _=word(hand, j) /*obtain a card from the dealt hand. */ |
|||
pip=left(_, length(_)-1); ws=right(_, 1) /*obtain the card's pip; get the suit.*/ |
|||
if pip==10 then pip='T' /*allow an alternate form for a "TEN". */ |
|||
@._=@._+1; #=pos(pip, 123456789TJQK) /*bump the card counter, get pip index.*/ |
|||
if pos(ws, "♥♣♦♠")==0 | #==0 | @._\==1 then return 'invalid' |
|||
suit.ws=suit.ws+1; flush=max(flush,suit.ws) /*count suits for a flush; find # suits*/ |
|||
_=substr(pips,#,1)+1; pips=overlay(_,pips, #); kinds=max(kinds,_) |
|||
run=overlay(.,run,#); _=substr(pips,#,1)+1 /*convert run to series of dots. */ |
|||
⚫ | |||
pips=overlay(_,pips,#); kinds=max(kinds,_) /*convert certain pips to their number.*/ |
|||
⚫ | |||
pairs=countstr(2,pips) /*count |
pairs=countstr(2, pips) /*count number of pairs (2s in PIPS).*/ |
||
straight=pos(....., run||left(run,1))\==0 /*RUN contains a straight?*/ |
straight=pos(....., run || left(run, 1))\==0 /*does the RUN contains a straight? */ |
||
if flush==5 & straight then return 'straight-flush' |
|||
select |
|||
if kinds==4 then return 'four-of-a-kind' |
|||
if kinds==3 & pairs==1 then return 'full-house' |
|||
if flush==5 then return 'flush' |
|||
if straight then return 'straight' |
|||
if kinds==3 then return 'three-of-a-kind' |
|||
if kinds==2 & pairs==2 then return 'two-pair' |
|||
if kinds==2 then return 'one-pair' |
|||
return 'high-card'</lang> |
|||
⚫ | |||
end /*select*/</lang> |
|||
Programming note: some older REXXes don't have the '''countstr''' BIF, so that REXX statement (above, line 21) can be replaced with: |
Programming note: some older REXXes don't have the '''countstr''' BIF, so that REXX statement (above, line 21) can be replaced with: |
||
<lang rexx>pairs=13-length(space(translate(pips,,2),0)) /*count # of 2's in PIPS.*/</lang> |
<lang rexx>pairs=13-length(space(translate(pips,,2),0)) /*count # of 2's in PIPS.*/</lang> |
||
Line 1,818: | Line 1,818: | ||
ah 2h 3h 4h |
ah 2h 3h 4h |
||
</pre> |
</pre> |
||
'''output''' when using the (above) input file: |
|||
<pre> |
<pre> |
||
2♥ 2♦ 2♠ k♠ q♦ ◄─── three-of-a-kind |
2♥ 2♦ 2♠ k♠ q♦ ◄─── three-of-a-kind |
||
Line 1,833: | Line 1,833: | ||
</pre> |
</pre> |
||
===version 3 |
===version 3 with suit glyphs and jokers=== |
||
This REXX version has three additional features: |
This REXX version has three additional features: |
||
* "invalid" hands have additional diagnostic information |
::* "invalid" hands have additional diagnostic information |
||
* supports up to two ''jokers'' |
::* supports up to two ''jokers'' |
||
* the ''joker'' card may be abbreviated (and in upper/lower/mixed case) |
::* the ''joker'' card may be abbreviated (and can be in upper/lower/mixed case) |
||
<lang rexx>/*REXX program analyzes an N-card poker hand, displays what the hand is |
<lang rexx>/*REXX program analyzes an N-card poker hand, and displays what the poker hand is, */ |
||
/* |
/*──────────────────────────────────────────── poker hands may contain up to two jokers.*/ |
||
parse arg iFID .; if iFID=='' then iFID=' |
parse arg iFID .; if iFID=='' | iFID=="," then iFID='POKERHAN.DAT' |
||
/* [↓] read the poker hands dealt*/ |
/* [↓] read the poker hands dealt. */ |
||
do while lines(iFID)\==0; ox=linein(iFID); if ox='' then iterate |
do while lines(iFID)\==0; ox=linein(iFID); if ox='' then iterate |
||
say right(ox,max(30,length(ox))) ' ◄─── ' analyze(ox) |
say right(ox, max(30, length(ox) ) ) ' ◄─── ' analyze(ox) |
||
end /*while*/ /* [↑] analyze/validate the hand |
end /*while*/ /* [↑] analyze/validate the poker hand*/ |
||
exit /*stick a fork in it, we're done.*/ |
exit /*stick a fork in it, we're all done. */ |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
/*──────────────────────────────────ANALYZE subroutine──────────────────*/ |
|||
analyze: procedure; arg x ';',mc; hand=translate(x,'♥♦♣♠1',"HDCSA,") |
analyze: procedure; arg x ';',mc; hand=translate(x, '♥♦♣♠1', "HDCSA,") |
||
kinds=0; suit.=0; flush=0; pairs=0; @.=0; run=copies(0,13); pips=run |
kinds=0; suit.=0; flush=0; pairs=0; @.=0; run=copies(0 ,13); pips=run |
||
if mc=='' then mc=5; n=words(hand) /*N is the |
if mc=='' then mc=5; n=words(hand) /*N is the number of cards in hand. */ |
||
if n\==mc then return 'invalid number of cards, must be' mc |
if n\==mc then return 'invalid number of cards, must be' mc |
||
/* [↓] PIP can be 1 or 2 chars.*/ |
/* [↓] the PIP can be 1 or 2 chars. */ |
||
do j=1 for n; _=word(hand,j) /*obtain a card from the dealt hand. */ |
|||
pip=left(_, length(_)-1); ws=right(_, 1) /*obtain card's pip; obtain card's suit*/ |
|||
if pip==10 then pip='T' /*allow alternate form for a TEN pip.*/ |
|||
if abbrev('JOKER',_,1) then _="JK" /*allow altername forms of JOKER names.*/ |
|||
@._=@._+1; #=pos(pip,123456789TJQK) /*bump card counter, get the pip index.*/ |
|||
if _=='JK' then do |
|||
if _=='JK' then do; if @.j>2 then return 'invalid, too many jokers' |
|||
iterate |
iterate |
||
end |
|||
if pos(ws, "♥♣♦♠")==0 then return 'invalid suit in card:' _ |
|||
if #==0 then return 'invalid pip in card:' _ |
|||
if @._\==1 then return 'invalid, duplicate card:' _ |
|||
suit.ws=suit.ws+1; flush=max(flush,suit.ws) /*count suits for a flush; find # suits*/ |
|||
_=substr(pips,#,1)+1 |
run=overlay(.,run,#); _=substr(pips,#,1)+1 /*convert run to series of dots. */ |
||
pips=overlay(_,pips,#); kinds=max(kinds,_) /*convert certain pips to their number.*/ |
|||
end /*i*/ /*keep track of N-of-a-kind. [↑] */ |
|||
⚫ | |||
run=run || left(run,1) /* |
run=run || left(run, 1) /*An ace can be high -or- low. */ |
||
jok=@.jk; kinds=kinds+jok; flush=flush+jok /* |
jok=@.jk; kinds=kinds+jok; flush=flush+jok /*N─of─a─kind; adjustments for jokers.*/ |
||
straight= pos(..... , run)\==0 |, /*RUN |
straight= pos(..... , run)\==0 |, /*does the RUN contain a straight? */ |
||
(pos(.... , run)\==0 & jok>=1) |, /* " " " " */ |
(pos(.... , run)\==0 & jok>=1) |, /* " " " " " " */ |
||
(pos(..0.. , run)\==0 & jok>=1) |, /* " " " " */ |
(pos(..0.. , run)\==0 & jok>=1) |, /* " " " " " " */ |
||
(pos(...0. , run)\==0 & jok>=1) |, /* " " " " */ |
(pos(...0. , run)\==0 & jok>=1) |, /* " " " " " " */ |
||
(pos(.0... , run)\==0 & jok>=1) |, /* " " " " */ |
(pos(.0... , run)\==0 & jok>=1) |, /* " " " " " " */ |
||
(pos(... , run)\==0 & jok>=2) |, /* " " " " */ |
(pos(... , run)\==0 & jok>=2) |, /* " " " " " " */ |
||
(pos(..0. , run)\==0 & jok>=2) |, /* " " " " */ |
(pos(..0. , run)\==0 & jok>=2) |, /* " " " " " " */ |
||
(pos(.0.. , run)\==0 & jok>=2) |, /* " " " " */ |
(pos(.0.. , run)\==0 & jok>=2) |, /* " " " " " " */ |
||
(pos(.00.. , run)\==0 & jok>=2) |, /* " " " " */ |
(pos(.00.. , run)\==0 & jok>=2) |, /* " " " " " " */ |
||
(pos(..00. , run)\==0 & jok>=2) |, /* " " " " */ |
(pos(..00. , run)\==0 & jok>=2) |, /* " " " " " " */ |
||
(pos(.0.0. , run)\==0 & jok>=2) /* " " " " */ |
(pos(.0.0. , run)\==0 & jok>=2) /* " " " " " " */ |
||
pairs=countstr(2,pips) /*count |
pairs=countstr(2, pips) /*count number of pairs (2s in PIPS). */ |
||
if jok\==0 then pairs=pairs-1 /*adjust |
if jok\==0 then pairs=pairs-1 /*adjust number of pairs with jokers. */ |
||
if kinds>=5 then return 'five-of-a-kind' |
|||
if flush>=5 & straight then return 'straight-flush' |
|||
if kinds>=4 then return 'four-of-a-kind' |
|||
if kinds>=3 & pairs>=1 then return 'full-house' |
|||
if flush>=5 then return 'flush' |
|||
if straight then return 'straight' |
|||
if kinds>=3 then return 'three-of-a-kind' |
|||
if kinds==2 & pairs==2 then return 'two-pair' |
|||
if kinds==2 then return 'one-pair' |
|||
return 'high-card'</lang> |
|||
when kinds==2 then return 'one-pair' |
|||
otherwise return 'high-card' |
|||
end /*select*/</lang> |
|||
Programming note: the method used for analyzing hands that contain jokers are limited to a maximum of two jokers. |
Programming note: the method used for analyzing hands that contain jokers are limited to a maximum of two jokers. |
||
A different methodology would be needed for a generic number of jokers (and/or wild cards [such as deuces and one-eyed jacks]). |
<br>A different methodology would be needed for a generic number of jokers (and/or wild cards [such as deuces and one-eyed jacks]). |
||
'''input file''': |
'''input file''': |
||
Line 1,924: | Line 1,922: | ||
J♥ Q♦ K♠ A♠ jok |
J♥ Q♦ K♠ A♠ jok |
||
</pre> |
</pre> |
||
'''output''' when using the (above) input file: |
|||
<pre> |
<pre> |
||
joker 2♦ 2♠ k♠ q♦ ◄─── three-of-a-kind |
joker 2♦ 2♠ k♠ q♦ ◄─── three-of-a-kind |