! Copyright (c) 2009 Aaron Schaefer. All rights reserved. ! The contents of this file are licensed under the Simplified BSD License ! A copy of the license is available at http://factorcode.org/license.txt USING: accessors arrays ascii binary-search combinators kernel locals math math.bitwise math.combinatorics math.order poker.arrays random sequences sequences.product splitting ; IN: poker ! The algorithm used is based on Cactus Kev's Poker Hand Evaluator with ! the Senzee Perfect Hash Optimization: ! http://www.suffecool.net/poker/evaluator.html ! http://www.senzee5.com/2006/06/some-perfect-hash.html ckf) ( rank suit -- n ) rank rank suit rank card-bitfield ; : >ckf ( str -- n ) #! Cactus Kev Format >upper 1 cut (>ckf) ; : parse-cards ( str -- seq ) " " split [ >ckf ] map ; : flush? ( cards -- ? ) HEX: F000 [ bitand ] reduce 0 = not ; : rank-bits ( cards -- q ) 0 [ bitor ] reduce -16 shift ; : lookup ( cards table -- value ) [ rank-bits ] dip nth ; : map-product ( seq quot -- n ) [ 1 ] 2dip [ dip * ] curry [ swap ] prepose each ; inline : prime-bits ( cards -- q ) [ HEX: FF bitand ] map-product ; : perfect-hash-find ( q -- value ) #! magic to convert a hand's unique identifying bits to the #! proper index for fast lookup in a table of hand values HEX: E91AAA35 + dup -16 shift bitxor dup 8 shift w+ dup -4 shift bitxor [ -8 shift HEX: 1FF bitand adjustments-table nth ] [ dup 2 shift w+ -19 shift ] bi bitxor values-table nth ; : hand-value ( cards -- value ) dup flush? [ flushes-table lookup ] [ dup unique5-table lookup dup 0 > [ nip ] [ drop prime-bits perfect-hash-find ] if ] if ; : >card-rank ( card -- str ) -8 shift HEX: F bitand RANK_STR nth ; : >card-suit ( card -- str ) { { [ dup 15 bit? ] [ drop "C" ] } { [ dup 14 bit? ] [ drop "D" ] } { [ dup 13 bit? ] [ drop "H" ] } [ drop "S" ] } cond ; : hand-rank ( hand -- rank ) value>> { { [ dup 6185 > ] [ drop HIGH_CARD ] } ! 1277 high card { [ dup 3325 > ] [ drop ONE_PAIR ] } ! 2860 one pair { [ dup 2467 > ] [ drop TWO_PAIR ] } ! 858 two pair { [ dup 1609 > ] [ drop THREE_OF_A_KIND ] } ! 858 three-kind { [ dup 1599 > ] [ drop STRAIGHT ] } ! 10 straights { [ dup 322 > ] [ drop FLUSH ] } ! 1277 flushes { [ dup 166 > ] [ drop FULL_HOUSE ] } ! 156 full house { [ dup 10 > ] [ drop FOUR_OF_A_KIND ] } ! 156 four-kind [ drop STRAIGHT_FLUSH ] ! 10 straight-flushes } cond ; : card>string ( card -- str ) [ >card-rank ] [ >card-suit ] bi append ; PRIVATE> TUPLE: hand { cards sequence } { value integer } ; M: hand <=> [ value>> ] compare ; M: hand equal? over hand? [ [ value>> ] bi@ = ] [ 2drop f ] if ; : ( str -- hand ) parse-cards dup hand-value hand boa ; : best-hand ( str -- hand ) parse-cards 5 all-combinations [ dup hand-value hand boa ] map infimum ; : >cards ( hand -- str ) cards>> [ card>string ] map " " join ; : >value ( hand -- str ) hand-rank VALUE_STR nth ; TUPLE: deck { cards sequence } ; : ( -- deck ) RANK_STR SUIT_STR 2array [ concat >ckf ] product-map deck boa ; : shuffle ( deck -- deck ) [ randomize ] change-cards ;