
    Xi+                        S r SSKJrJr  SSKrSSK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rSr\ " S S\5      5       r\ " S S\5      5       r " S S5      rSSSSS.rSSSSSS S!S"S#S$S%S&S'S(.rSS)SS*SS+S	S,S-S.S/S0S1S2S3S4S5S6\S7\S8\S9\S:\S;\S<0rSGS=\S>\S?\4S@ jjrSGS=\S>\S?\4SA jjrS=\S?\4SB jrSGSC\\   S>\S?\4SD jjrSHSC\\   SE\ S?\\   4SF jjr!g)Iz
Reusable card and deck utilities for card games.

Provides Card, Deck, and DeckFactory classes that can be used by any card game.
    )	dataclassfieldN)DataClassJSONMixin   )Localization                           c                   X    \ rS rSr% Sr\\S'   \\S'   \\S'   S\4S jrS\S\	4S	 jr
S
rg)Card   zPlaying card model.

Attributes:
    id: Unique identifier.
    rank: Card rank (1-13 standard, 1-10 Italian, 14-19 RS Games special).
    suit: Suit number (0=none, 1=diamonds, 2=clubs, 3=hearts, 4=spades).
idranksuitreturnc                     U R                   $ )z+Hash cards by stable id for set/dict usage.)r   selfs    6C:\Users\dbart\PlayPalace11\server\game_utils\cards.py__hash__Card.__hash__-   s    ww    otherc                 `    [        U[        5      (       d  gU R                  UR                  :H  $ )zCompare cards by id equality.F)
isinstancer   r   )r   r   s     r   __eq__Card.__eq__1   s%    %&&ww%((""r    N)__name__
__module____qualname____firstlineno____doc__int__annotations__r   objectboolr"   __static_attributes__r$   r   r   r   r      s7     	G
I
I# #F #t #r   r   c                       \ rS rSr% Sr\" \S9r\\   \	S'   SS jr
SS\S\\   4S	 jjrS\S-  4S
 jrS\\   SS4S jrS\\   SS4S jrS\4S jrS\4S jrS\\   4S jrSrg)Deck8   zgDeck of cards with draw/shuffle operations.

Attributes:
    cards: Ordered list of cards in the deck.
)default_factorycardsr   Nc                 D    [         R                  " U R                  5        g)zShuffle the deck in place.N)randomshuffler3   r   s    r   r6   Deck.shuffleB   s    tzz"r   countc                 L    U R                   SU nU R                   US U l         U$ )z$Draw cards from the top of the deck.Nr3   )r   r8   drawns      r   draw	Deck.drawF   s)    

6E"ZZ'
r   c                 \    U R                   (       a  U R                   R                  S5      $ g)z,Draw a single card from the top of the deck.r   N)r3   popr   s    r   draw_oneDeck.draw_oneL   s    ::::>>!$$r   c                 :    U R                   R                  U5        g)z$Add cards to the bottom of the deck.N)r3   extendr   r3   s     r   addDeck.addR   s    

% r   c                 *    XR                   -   U l         g)z!Add cards to the top of the deck.Nr:   rD   s     r   add_topDeck.add_topV   s    ZZ'
r   c                 ,    [        U R                  5      $ )z'Return the number of cards in the deck.lenr3   r   s    r   size	Deck.sizeZ   s    4::r   c                 2    [        U R                  5      S:H  $ )zCheck if the deck is empty.r   rK   r   s    r   is_emptyDeck.is_empty^   s    4::!##r   c                 ,    U R                   n/ U l         U$ )z*Remove and return all cards from the deck.r:   rD   s     r   clear
Deck.clearb   s    


r   r:   )r   Nr   )r%   r&   r'   r(   r)   r   listr3   r   r+   r6   r*   r<   r@   rE   rH   rM   r-   rP   rS   r.   r$   r   r   r0   r0   8   s     d3E4:3## d4j $+ !d ! !(T$Z (D (c $$ $tDz r   r0   c            
           \ rS rSrSr\SS\S\\\	\\
4   4   4S jj5       r\SS\S\\\	\\
4   4   4S jj5       r\S\\\	\\
4   4   4S j5       r\S\\\	\\
4   4   4S j5       rS	rg
)DeckFactoryi   z'Factory for creating common deck types.	num_decksr   c           	          / n0 nSn[        U 5       HM  n[        SS5       H:  n[        SS5       H'  n[        X6US9nUR                  U5        XrU'   US-  nM)     M<     MO     [        US9nUR	                  5         X4$ )z
Create Italian 40-card deck (4 suits x 10 ranks).

Args:
    num_decks: Number of decks to combine.

Returns:
    Tuple of (shuffled deck, card lookup dict mapping id -> Card)
r   r         r   r   r   r:   ranger   appendr0   r6   	rZ   r3   card_lookupcard_id_r   r   carddecks	            r   italian_deckDeckFactory.italian_deckl        ')y!Aa!!RLD7DADLL&+/(qLG	 ) $ " %   r   c           	          / n0 nSn[        U 5       HM  n[        SS5       H:  n[        SS5       H'  n[        X6US9nUR                  U5        XrU'   US-  nM)     M<     MO     [        US9nUR	                  5         X4$ )z
Create standard 52-card deck (4 suits x 13 ranks).

Args:
    num_decks: Number of decks to combine.

Returns:
    Tuple of (shuffled deck, card lookup dict mapping id -> Card)
r   r   r\   r   r^   r:   r_   rb   s	            r   standard_deckDeckFactory.standard_deck   rj   r   c                     / n 0 nSn[        SS5       H=  n[        S5       H+  n[        X#[        S9nU R                  U5        XQU'   US-  nM-     M?     [        [
        [        [        [        [        4 H=  n[        S5       H+  n[        X#[        S9nU R                  U5        XQU'   US-  nM-     M?     [        U S9nUR                  5         Xa4$ )a	  
Create RS Games 60-card deck for Ninety-Nine variant.

Contains:
- Number cards 1-9: 4 of each (36 cards)
- Special cards: +10, -10, Pass, Reverse, Skip, Ninety-Nine (4 of each, 24 cards)

Returns:
    Tuple of (shuffled deck, card lookup dict mapping id -> Card)
r   r   
   r
   r^   r:   )r`   r   	SUIT_NONEra   RS_RANK_PLUS_10RS_RANK_MINUS_10RS_RANK_PASSRS_RANK_REVERSERS_RANK_SKIPRS_RANK_NINETY_NINEr0   r6   )r3   rc   rd   r   re   rf   rg   s          r   rs_games_deckDeckFactory.rs_games_deck   s     ') !RLD1Xw	BT"'+G$1	  ! 
D 1Xw	BT"'+G$1	 
 %   r   c            	         / n 0 nSn[        S5       HM  n[        SS5       H:  n[        SS5       H'  n[        X%US9nU R                  U5        XaU'   US-  nM)     M<     MO     [        S5       H,  n[        US[        S9nU R                  U5        XaU'   US-  nM.     [        S5       H,  n[        US	[        S9nU R                  U5        XaU'   US-  nM.     [	        U S
9nUR                  5         Xq4$ )a  
Create Phase 10 108-card deck.

Contains:
- 2 copies of each number 1-12 in 4 colors (suit 1=Red, 2=Blue, 3=Green, 4=Yellow) = 96 cards
- 8 Wild cards (rank=13, suit=0)
- 4 Skip cards (rank=14, suit=0)

Returns:
    Tuple of (shuffled deck, card lookup dict mapping id -> Card)
r   r   r   r\      r^      r
   r   r:   )r`   r   ra   rp   r0   r6   )r3   rc   rd   re   r   r   rf   rg   s           r   phase10_deckDeckFactory.phase10_deck   s     ') qAa!!RLD7DADLL&+/(qLG	 ) $  qA7)<DLL#' qLG	  qA7)<DLL#' qLG	  %   r   r$   NrU   )r%   r&   r'   r(   r)   staticmethodr*   tupler0   dictr   rh   rl   rw   r|   r.   r$   r   r   rX   rX   i   s    1! !E$S$Y2G,H ! !0 ! !U4c4i3H-I ! !0 )!5tCI!67 )! )!V )!%d39o 56 )! )!r   rX   zsuit-diamondsz
suit-clubszsuit-heartszsuit-spadesr   r   r	   r
   zrank-acezrank-twoz
rank-threez	rank-fourz	rank-fivezrank-sixz
rank-sevenz
rank-eightz	rank-ninezrank-tenz	rank-jackz
rank-queenz	rank-king)r   r   r	   r
   r\         r{   	   ro   r]      rz   1234r\   5r   6r   7r{   8r   910z-10PassReverseSkipzNinety Ninerf   localer   c                     U R                   [        :X  a3  [        R                  U R                  [        U R                  5      5      $ [        R                  U R                  5      n[        R                  U R                   5      nU(       a  [        R                  " X5      O[        U R                  5      nU(       a  [        R                  " X5      O[        U R                   5      n[        R                  " USXES9$ )z
Get localized card name (e.g., 'Seven of Diamonds').

For RS Games cards (suit == SUIT_NONE), returns the special card name directly.

Args:
    card: The card to name.
    locale: Locale for localization.

Returns:
    Localized card name string.
z	card-namer   r   )	r   rp   RS_GAMES_RANK_NAMESgetr   str	RANK_KEYS	SUIT_KEYSr   )rf   r   rank_keysuit_key	rank_name	suit_names         r   	card_namer   $  s     yyI"&&tyy#dii.AA}}TYY'H}}TYY'H6>  2C		NI6>  2C		NIFKiPPr   c                 Z    [        X5      nUS   R                  5       S;   a  SU 3$ SU 3$ )z
Get card name with article (a/an).

Args:
    card: The card to name.
    locale: Locale for localization.

Returns:
    Card name with appropriate article (e.g., 'an Ace of Hearts').
r   aeiou8zan za )r   lower)rf   r   names      r   card_name_with_articler   >  s8     T"DAw}}("TF|v;r   c                 N   U R                   [        :X  a3  [        R                  U R                  [        U R                  5      5      $ SSSSS.nSSSS	S
.nUR                  U R                  [        U R                  5      5      nUR                  U R                   S5      nU U 3$ )z
Get short card name (e.g., '7D' for Seven of Diamonds).

Args:
    card: The card to name.

Returns:
    Short card name string.
DCHSr   AJQK)r   r]   r   rz   ?)r   rp   r   r   r   r   )rf   
suit_chars
rank_charsrank_strsuit_strs        r   card_name_shortr   P  s     yyI"&&tyy#dii.AASSS1Jcs4J~~diiTYY8H~~dii-HZz""r   r3   c                     U (       d  [         R                  " US5      $ U  Vs/ s H  n[        X!5      PM     nn[         R                  " X5      $ s  snf )z
Format a list of cards for speech output.

Args:
    cards: List of cards to read.
    locale: Locale for localization.

Returns:
    Formatted string with card names joined by 'and'.
zno-cards)r   r   r   format_list_and)r3   r   cnamess       r   
read_cardsr   e  sI     
33+015aYq!5E1''66 2s   Aby_suitc                 <    U(       a  [        U S S9$ [        U S S9$ )z
Sort cards by suit then rank, or by rank then suit.

Args:
    cards: List of cards to sort.
    by_suit: If True, sort by suit first. Otherwise by rank first.

Returns:
    New sorted list of cards.
c                 2    U R                   U R                  4$ N)r   r   r   s    r   <lambda>sort_cards.<locals>.<lambda>      AFFAFF+;r   )keyc                 2    U R                   U R                  4$ r   r   r   s    r   r   r     r   r   )sorted)r3   r   s     r   
sort_cardsr   v  s#     e!;<<e!;<<r   )en)T)"r)   dataclassesr   r   r5   mashumaro.mixins.jsonr   messages.localizationr   rp   SUIT_DIAMONDS
SUIT_CLUBSSUIT_HEARTSSUIT_SPADESrq   rr   rs   rt   ru   rv   r   r0   rX   r   r   r   r   r   r   r   rV   r   r-   r   r$   r   r   <module>r      s   )  4 0 	
    # # #0 - - -`K! K!` 		 	$ sssssssssTe&Y& &QD Q# Q Q4 s c $#$ #3 #*7d4j 7# 7 7"=d4j =4 =4: =r   