
    Ii+                       S r SSKJr  SSKJr  SSKJr  SSKJr  SSK	J
r
JrJr  SS	KJr  SrSrSrS
rSrSrSrSrSrSS jrSS jrS S!S jjrS S"S jjrS S#S jjrS$S jrS%S jrS%S jrS&S'S jjr S(S jr!S)S jr"S*S jr#S+S jr$g),z
Poker hand evaluator for standard 52-card decks.

Provides helpers for scoring a 5-card hand and selecting the best 5-card hand
from a larger set (e.g., 7 cards in Hold'em).
    )annotations)Counter)combinations)Iterable   )Card	SUIT_NONE	RANK_KEYS   )Localization                  c                    [        U 5      S:  a  [        S5      eSnSn[        U S5       H.  n[        [	        U5      5      nUb  XA:  d  M!  Un[	        U5      nM0     X4$ )zReturn the best 5-card hand score and chosen 5 cards.

Args:
    cards: List of 5+ cards to evaluate.

Returns:
    Tuple of (score, best_five_cards).
r   z#best_hand requires at least 5 cardsN)len
ValueErrorr   score_5_cardslist)cards
best_score	best_fivehandscores        @c:\Users\dbart\PlayPalace11\server\game_utils\poker_evaluator.py	best_handr      sh     5zA~>??59J#'IUA&d4j)!3JT
I	 '       c                @   [        U 5      S:w  a  [        S5      eU  Vs/ s H  n[        UR                  5      PM     nnU  Vs/ s H  oR                  PM     nn[        U5      n[        S UR                  5        5       S SS9n[        U5      n[        U5      u  pxU(       a  U(       a	  [        U44$ US   S   S:X  a   US   S	   n	[        X)15      S   n
[        X44$ US   S   S
:X  a%  US	   S   S:X  a  US   S	   nUS	   S	   n[        X44$ U(       a  [        [        [        USS95      4$ U(       a	  [         U44$ US   S   S
:X  a   US   S	   n[        X+15      n["        U/UQ74$ US   S   S:X  aV  US	   S   S:X  aJ  [%        US   S	   US	   S	   5      n['        US   S	   US	   S	   5      n[        X.U15      S   n
[(        XU
44$ US   S   S:X  a   US   S	   n[        X,15      n[*        U/UQ74$ [,        [        [        USS95      4$ s  snf s  snf )zvScore exactly 5 cards.

Args:
    cards: Exactly five cards.

Returns:
    Comparable score tuple (higher is better).
r   z&score_5_cards requires exactly 5 cardsc              3  ,   #    U  H
  u  pX!4v   M     g 7fN ).0rankcounts      r   	<genexpr> score_5_cards.<locals>.<genexpr>G   s     >*=;4%*=   c                    U S   U S   4$ )Nr   r   r#   )xs    r   <lambda>score_5_cards.<locals>.<lambda>H   s    qtQqTlr   T)keyreverser   r   r   r   r   r/   )r   r   _rank_valuer%   suitr   sorteditems	_is_flush_is_straightSTRAIGHT_FLUSH_highest_of_excludingFOUR_OF_A_KIND
FULL_HOUSEFLUSHtupleSTRAIGHTTHREE_OF_A_KINDmaxminTWO_PAIRONE_PAIR	HIGH_CARD)r   cardrankssuitsrank_countscounts_sortedis_flushis_straightstraight_high	quad_rankkicker	trip_rank	pair_rankkickers	high_pairlow_pairs                   r   r   r   6   s    5zQABB056[#E6#()54YY5E)%.K>+*;*;*=>"M H!-e!4Kx 011Qa!!$Q'	&uk:1= 344QaM!$4Q$71$<!!$Q'	!!$Q'	Y233uVE489::=*++Qa!!$Q'	'{;)!6g!677QaM!$4Q$71$<a(+]1-=a-@A	}Q'*M!,<Q,?@&u(.CDQG9788Qa!!$Q'	'{;9/w/00uVE489::a 7)s   HHc                \   U u  p#U[         :X  a<  [        [        US   U5      5      n[        USS USS9n[        R
                  " USXES9$ U[        :X  a<  [        [        US   U5      5      n[        USS USS9n[        R
                  " USXeS	9$ U[        :X  a`  [        [        US   U5      5      n[        [        US   U5      5      n[        [        US
   U5      5      n	[        R
                  " USUUU	S9$ U[        :X  a<  [        [        US   U5      5      n
[        USS USS9n[        R
                  " USXS9$ U[        :X  a.  [        [        US   U5      5      n[        R
                  " USUS9$ U[        :X  a<  [        [        US   U5      5      n[        USS USS9n[        R
                  " USXES9$ U[        :X  aF  [        [        US   U5      5      n
[        [        US   U5      5      n[        R
                  " USXS9$ U[        :X  aF  [        [        US   U5      5      n[        [        US   U5      5      n	[        R
                  " USXS9$ U[        :X  a.  [        [        US   U5      5      n[        R
                  " USUS9$ [        R
                  " US5      $ )zReturn a human-friendly description for a scored hand.

Args:
    score: Hand score tuple.
    locale: Locale for localization.

Returns:
    Localized description of the hand.
r   r   NTcapzpoker-high-card-with)highrestpoker-pair-withpairrW   r   poker-two-pair-withrV   lowrM   poker-trips-withtripsrW   zpoker-straight-highrV   zpoker-flush-high-withzpoker-full-house)r`   rZ   zpoker-quads-with)quadsrM   zpoker-straight-flush-highpoker-unknown-hand)rC   _cap
_rank_name
_rank_listr   getrB   _rank_name_pluralrA   r>   r=   r;   r:   r9   r7   )r   localecategorytiebreakersrV   rP   rZ   rQ   rR   rM   r`   rb   s               r   describe_handrl   u   s    "H9J{1~v67[_f$?(>TXX8%k!nf=>[_f$?(9SS8*;q>6BC	)+a.&ABjQ89!
 	
 ?"&{1~v>?[_f$?(:%VV8J{1~v67(=DII5J{1~v67[_f$?(?dYY:&{1~v>?%k!nf=>(:%SS>!&{1~v>?jQ89(:%WW>!J{1~v67(C$OOF$899r   c                6    [        U 5      u  p#[        X!5      U4$ )zReturn the best hand description and the chosen 5 cards.

Args:
    cards: List of 5+ cards to evaluate.
    locale: Locale for localization.

Returns:
    Tuple of (description, best_five_cards).
)r   rl   )r   ri   r   bests       r   describe_best_handro      s      E"KE'--r   c           	        [        U 5      S:  a  [        U 5      u  p#[        X!5      $ U  Vs/ s H  n[        UR                  5      PM     nn[        U5      n[        S UR                  5        5       SS9nU(       d  [        R                  " US5      $ US   S   S:X  a1  [        [        US   S   U5      5      n[        R                  " US	US
9$ US   S   S:X  aw  [        [        US   S   U5      5      n	[        U V
s/ s H  oUS   S   :w  d  M  U
PM     sn
USS9nU(       a  [        R                  " USXS9$ [        R                  " USU	S9$ US   S   S:X  a  [        U5      S:  a  US   S   S:X  a  [        US   S   US   S   5      n[        US   S   US   S   5      n[        [        X5      5      n[        [        X5      5      n[        U V
s/ s H  oUS   S   US   S   4;  d  M  U
PM     sn
USS9nU(       a  [        R                  " USUUUS9$ [        R                  " USXS9$ US   S   S:X  ax  [        [        US   S   U5      5      n[        U V
s/ s H  oUS   S   :w  d  M  U
PM     sn
USS9nU(       a  [        R                  " USUUS9$ [        R                  " USUS9$ [        [        [        U5      U5      5      n[        R                  " USUS9$ s  snf s  sn
f s  sn
f s  sn
f )zDescribe a partial hand without inventing missing cards.

Args:
    cards: List of 0-4 cards.
    locale: Locale for localization.

Returns:
    Localized partial-hand description.
r   c              3  ,   #    U  H
  u  pX!4v   M     g 7fr"   r#   )r$   rcs      r   r'   (describe_partial_hand.<locals>.<genexpr>   s     9.$!v.r)   Tr0   rc   r   r   r   zpoker-quads)rb   r   rT   r^   r_   zpoker-trips)r`   r   r[   r\   zpoker-two-pair)rV   r]   rX   rY   z
poker-pair)rZ   zpoker-high-cardra   )r   r   rl   r1   r%   r   r3   r4   r   rg   rd   rh   rf   r?   r@   re   )r   ri   r   _rD   rE   countsby_countrb   r`   rr   rP   rQ   rR   high_pair_namelow_pair_namerZ   rV   s                     r   describe_partial_handrz      s    5zQU#U++056[#E6U^F9&,,.94HH(<=={1~&x{1~v>?UCC{1~&x{1~v>?FAx{1~2EaFTXY##F,>eZZUCC{1~s8}q0Xa[^q5HAA7	x{1~x{1~6/	BC.x@AK18A;q>8A;q>*J!JQK

 ##%#!  (8~aa{1~%hqk!nf=>FAx{1~2EaFTXY##F,=DwWW4@@
3u:v./DF$5DAAQ 7 G L Gs)   K2K7K7K<8K<*L=Lc                    U S:X  a  S$ U $ )z4Convert Card.rank to standard poker rank (Ace high).r      r#   )r%   s    r   r1   r1      s    2$$r   c                    U S:X  a  SOU n[         R                  " U5      nU(       a  [        R                  " X5      $ [        U 5      $ )z6Return the localized rank name for a poker rank value.r|   r   )r
   rg   r   str)r%   ri   
normalizedr.   s       r   re   re     s9    bjdJ
--

#C,/<F(>SY>r   c                    [        X5      nU S:X  a  SOU n[        R                  " U5      nU(       d  U$ U S3n[        R                  " X5      $ )z=Return the localized plural rank name for a poker rank value.r|   r   z-plural)re   r
   rg   r   )r%   ri   namer   r.   
plural_keys         r   rh   rh     sK    d#DbjdJ
--

#C5JF//r   c                    U  Vs/ s H  n[        X15      PM     nnU(       a  U Vs/ s H  n[        U5      PM     nn[        R                  " X5      $ s  snf s  snf )z=Format a list of ranks into a localized, human-readable list.)re   rd   r   format_list_and)rE   ri   rU   r%   namesr   s         r   rf   rf     sO    278%$Z%%E8
(-.d.''66 9.s
   AAc                L    U (       d  U $ U S   R                  5       nU U SS  3$ )z6Capitalize the first character of a string if present.r   r   N)upper)r   firsts     r   rd   rd     s.    GMMOEWT!"XJr   c                x    [        U 5      n[        U5      S:H  =(       a    [        [        U5      5      [        :g  $ )z8Return True if all suits are the same and not suit-less.r   )setr   nextiterr	   )rF   suit_sets     r   r5   r5   #  s-    5zHx=AC$tH~"6)"CCr   c                    [        [        U 5      SS9n[        U5      S:w  a  gUS   nUS   nX#-
  S:X  a  SU4$ U/ SQ:X  a  g	g)
z;Return True and the high card if the ranks form a straight.Tr0   r   )Fr   r   r   )r|   r   r   r   r   )Tr   )r3   r   r   )rE   uniquerV   r]   s       r   r6   r6   )  sW    CJ-F
6{a!9D
*CzQTz !!r   c                R    U  Vs/ s H  o"U;  d  M
  UPM     nn[        USS9$ s  snf )z:Return remaining ranks sorted high-to-low excluding a set.Tr0   )r3   )rE   excludedrr   	remainings       r   r8   r8   ;  s-    !7Eqh%6EI7)T** 8s   	$$N)r   
list[Card]returnz.tuple[tuple[int, tuple[int, ...]], list[Card]])r   r   r   tuple[int, tuple[int, ...]])en)r   r   ri   r~   r   r~   )r   r   ri   r~   r   ztuple[str, list[Card]])r   r   ri   r~   r   r~   )r%   intr   r   )r%   r   ri   r~   r   r~   )F)rE   Iterable[int]ri   r~   rU   boolr   r~   )r   r~   r   r~   )rF   r   r   r   )rE   	list[int]r   ztuple[bool, int])rE   r   r   zset[int]r   r   )%__doc__
__future__r   collectionsr   	itertoolsr   typingr   r   r   r	   r
   messages.localizationr   rC   rB   rA   r>   r=   r;   r:   r9   r7   r   r   rl   ro   rz   r1   re   rh   rf   rd   r5   r6   r8   r#   r   r   <module>r      s    #  "  - - 0 		
!2<;~>:B.5Bp%
?07 D$+r   