
    IiB                         S r SSKJr  SSKJr  SSKJrJr  SSKJ	r	  SSK
Jr  SSKJr  \	(       a   \ " S	 S
\5      5       r\ " S S\5      5       r " S S5      r/ SQrg)z
Reusable team management utility for team-based games.

Provides Team dataclass and TeamManager for handling team assignments,
scoring, and elimination (for inverse game modes).
    )OrderedDict)Mapping)	dataclassfield)TYPE_CHECKING)DataClassJSONMixin   )Localizationc                   j    \ rS rSr% Sr\\S'   \" \S9r	\\
   \S'   Sr\\S'   Sr\\S'   S	r\\S
'   Srg)Team   a  Team container for team-based games.

Attributes:
    index: Team index (0-based).
    members: Player names on the team.
    round_score: Points earned this round.
    total_score: Total points across rounds.
    eliminated: True if eliminated (inverse modes).
indexdefault_factorymembersr   round_scoretotal_scoreF
eliminated N)__name__
__module____qualname____firstlineno____doc__int__annotations__r   listr   strr   r   r   bool__static_attributes__r       6c:\Users\dbart\PlayPalace11\server\game_utils\teams.pyr   r      s?     Jt4GT#Y4KKJr!   r   c                   &   \ rS rSr% Sr\" \S9r\\   \	S'   Sr
\\	S'   \" \S9r\\\4   \	S'   S\\   S	S
4S jrS\S	\\   4S jrS\S	\S
-  4S jrS\S	\4S jrS\S	\\   4S jrS\S	\\   4S jrS\S\S	S
4S jrS\S\S	S
4S jrS4S jrS4S jrS4S jrS	\\   4S jrS\S	S
4S jrS\S	S
4S jrS\S	\4S jrS\S	\\   4S jrS	\S
-  4S  jr S5S\S!\S	\4S" jjr!S6S#\S$\S	\\   4S% jjr"\#S5S\S!\S	\4S& jj5       r$\#S'\S	\4S( j5       r%\#S)\S	\\   4S* j5       r&\#S5S)\S!\S	\\   4S+ jj5       r'\#S,\S-\S	\\   4S. j5       r(\# S5S,\S-\S!\S	\\)\\4      4S/ jj5       r*\#S\S)\S	\4S0 j5       r+S5S!\S	\4S1 jjr,S5S!\S	\\   4S2 jjr-S3r.g
)7TeamManager(   zManage team assignments and scoring for games.

Supports individual mode (teams of 1) and common team configurations
like 2v2, 3v3, 2v2v2, etc.
r   teams
individual	team_mode_player_to_teamplayer_namesreturnNc                 >   / U l         0 U l        U R                  S:X  aH  [        U5       H8  u  p#[	        X#/S9nU R                   R                  U5        X R                  U'   M:     gU R                  U R                  5      n[        U5      n[        U5       Vs/ s H  n/ PM     nn[        U5       H*  u  pX-  n
X   R                  U5        XR                  U'   M,     [        U5       H)  u  p[	        XS9nU R                   R                  U5        M+     gs  snf )zw
Create teams based on team_mode and assign players.

Args:
    player_names: List of player names to assign to teams.
r'   )r   r   N)	r&   r)   r(   	enumerater   append_parse_team_modelenrange)selfr*   inameteam
team_sizes	num_teams_team_members
player_idxteam_idxr   s               r"   setup_teamsTeamManager.setup_teams4   s	    
!>>\)$\2!V4

!!$'-.$$T* 3 ..t~~>JJI :?y9I,J9IAR9IL,J %.l$; 
%1&--d3-5$$T* %< &/|%<!(<

!!$' &= -Ks   Dmodec                     US:X  a  / $ UR                  5       R                  S5      nU Vs/ s H$  o3R                  5       (       d  M  [        U5      PM&     sn$ s  snf )z
Parse a team mode string into list of team sizes.

Examples:
    "2v2" -> [2, 2]
    "3v3" -> [3, 3]
    "2v2v2" -> [2, 2, 2]
    "2v3" -> [2, 3]
r'   v)lowersplitisdigitr   )r2   r>   partsps       r"   r/   TeamManager._parse_team_modeW   sK     <I

""3' %51A555s   AAplayer_namec                     U R                   R                  U5      nUb(  U[        U R                  5      :  a  U R                  U   $ g)z!Get the team a player belongs to.N)r)   getr0   r&   )r2   rG   r;   s      r"   get_teamTeamManager.get_teamf   s?    ''++K8Hs4::$>::h''r!   c                 :    U R                   R                  US5      $ )z1Get the team index for a player (0 if not found).r   )r)   rI   )r2   rG   s     r"   get_team_indexTeamManager.get_team_indexm   s    ##''Q77r!   c                     U R                  U5      nU(       a$  UR                   Vs/ s H  o3U:w  d  M
  UPM     sn$ / $ s  snf )z1Get names of player's teammates (excluding self).)rJ   r   )r2   rG   r5   ms       r"   get_teammatesTeamManager.get_teammatesq   s<    }}[)#||@|!K/?A|@@	 As   	??c                 b    U R                  U5      nU(       a  [        UR                  5      $ U/$ )z;Get names of all players on the same team (including self).)rJ   r   r   r2   rG   r5   s      r"   get_team_membersTeamManager.get_team_membersx   s*    }}[)%%}r!   pointsc                 `    U R                  U5      nU(       a  U=R                  U-  sl        gg)z*Add points to a player's team total score.N)rJ   r   r2   rG   rW   r5   s       r"   add_to_team_scoreTeamManager.add_to_team_score   )    }}[)& r!   c                 `    U R                  U5      nU(       a  U=R                  U-  sl        gg)z*Add points to a player's team round score.N)rJ   r   rY   s       r"   add_to_team_round_score#TeamManager.add_to_team_round_score   r\   r!   c                 v    U R                    H)  nU=R                  UR                  -  sl        SUl        M+     g)z<Add all round scores to total scores and reset round scores.r   N)r&   r   r   r2   r5   s     r"   commit_round_scoresTeamManager.commit_round_scores   s/    JJD 0 00 D r!   c                 8    U R                    H
  nSUl        M     g)z!Reset all team round scores to 0.r   N)r&   r   ra   s     r"   reset_round_scoresTeamManager.reset_round_scores   s    JJD D r!   c                 T    U R                    H  nSUl        SUl        SUl        M     g)zReset all team scores to 0.r   FN)r&   r   r   r   ra   s     r"   reset_all_scoresTeamManager.reset_all_scores   s'    JJD D D#DO r!   c                 j    U R                    Vs/ s H  oR                  (       a  M  UPM     sn$ s  snf )z,Get non-eliminated teams (for inverse mode).)r&   r   )r2   ts     r"   get_alive_teamsTeamManager.get_alive_teams   s"    ::::a\\::::s   00r5   c                     SUl         g)zMark a team as eliminated.TN)r   ra   s     r"   eliminate_teamTeamManager.eliminate_team   s	    r!   c                 D    U R                  U5      nU(       a  SUl        gg)z2Eliminate the team that contains the given player.TNrJ   r   rT   s      r"   eliminate_by_playerTeamManager.eliminate_by_player   s    }}[)"DO r!   c                 N    U R                  U5      nU(       a  UR                  $ S$ )z'Check if a player's team is eliminated.Frr   rT   s      r"   is_team_eliminatedTeamManager.is_team_eliminated   s!    }}[)"&t1E1r!   targetc                 h    U R                    Vs/ s H  o"R                  U:  d  M  UPM     sn$ s  snf )z=Get all teams that have reached or exceeded the target score.)r&   r   )r2   rx   rk   s      r"   get_teams_at_or_above_score'TeamManager.get_teams_at_or_above_score   s'    ::A:a&)@:AAAs   //c                 P    U R                   (       d  g[        U R                   S S9$ )z*Get the team with the highest total score.Nc                     U R                   $ Nr   rk   s    r"   <lambda>.TeamManager.get_leading_team.<locals>.<lambda>   s    Q]]r!   key)r&   max)r2   s    r"   get_leading_teamTeamManager.get_leading_team   s    zz4::#:;;r!   localec                     U R                   S:X  a   UR                  (       a  UR                  S   $ [        UR                  5      S:X  a  UR                  S   $ SUR                  S-    3$ )z
Get a display name for a team.

For individual mode, returns the player name.
For team mode, returns "Team N" or lists members.
r'   r      zTeam )r(   r   r0   r   )r2   r5   r   s      r"   get_team_nameTeamManager.get_team_name   sY     >>\)dll<<?"t||!<<?"tzzA~&''r!   by_score
descendingc                 D    U(       a  S OS n[        U R                  X2S9$ )z
Get teams sorted by score or index.

Args:
    by_score: If True, sort by total_score. Otherwise by index.
    descending: If True, highest first.
c                     U R                   $ r~   r   r   s    r"   r   .TeamManager.get_sorted_teams.<locals>.<lambda>   s    r!   c                     U R                   $ r~   )r   r   s    r"   r   r      s    AGGr!   )r   reverse)sortedr&   )r2   r   r   r   s       r"   get_sorted_teamsTeamManager.get_sorted_teams   s      ,4&:Kdjjc>>r!   c                    U S:X  a  [         R                  " US5      $ U R                  5       R                  S5      nU Vs/ s H$  o3R	                  5       (       d  M  [        U5      PM&     nnU(       d  U $ [        [        U5      5      S:X  a'  [        U5      nUS   n[         R                  " USUUS9$ SR                  S U 5       5      $ s  snf )	u  
Convert internal team mode format to user-friendly localized display format.

Examples:
    "individual" -> "Individual" (en) / "Individual" (pt) / "个人" (zh)
    "2v2" -> "2 teams of 2" (en) / "2 equipes de 2" (pt) / "2 个 2 人团队" (zh)
    "3v3" -> "2 teams of 3"
    "2v2v2" -> "3 teams of 2"
    "2v2v2v2" -> "4 teams of 2"

Args:
    mode: Internal team mode string.
    locale: Language code for localization (default: "en").

Returns:
    User-friendly localized display string.
r'   zgame-team-mode-individualr@   r   r   zgame-team-mode-x-teams-of-y)r7   	team_sizec              3   8   #    U  H  n[        U5      v   M     g 7fr~   )r   ).0ss     r"   	<genexpr>;TeamManager.format_team_mode_for_display.<locals>.<genexpr>   s     7JqCFFJs   )	r
   rI   rA   rB   rC   r   r0   setjoin)r>   r   rD   rE   r6   r7   r   s          r"   format_team_mode_for_display(TeamManager.format_team_mode_for_display   s    & <##F,GHH 

""3'&+;eyy{fc!fe
;K s:1$JI"1I##-##	  887J777% <s   CCdisplayc                    SSK nSU R                  5       ;   d  [        S U  5       5      (       d  gUR                  SU 5      n[	        U5      S:  a:  [        US   5      n[        US   5      nSR                  [        U5      /U-  5      $ U $ )	u  
Convert user-friendly display format to internal team mode format.

Works with localized strings by extracting numbers from patterns like:
- "Individual" / "个人" -> "individual"
- "2 teams of 2" / "2 equipes de 2" / "2 个 2 人团队" -> "2v2"
- "3 teams of 2" -> "2v2v2"
- "4 teams of 2" -> "2v2v2v2"

Args:
    display: User-friendly display string (possibly localized).

Returns:
    Internal team mode string.
r   Nr'   c              3   @   #    U  H  oR                  5       v   M     g 7fr~   )rC   )r   chars     r"   r   9TeamManager.parse_display_to_team_mode.<locals>.<genexpr>  s     5YQXllnnQXs   z\d+r	   r   r@   )rerA   anyfindallr0   r   r   r   )r   r   numbersr7   r   s        r"   parse_display_to_team_mode&TeamManager.parse_display_to_team_mode   s    " 	 7==?*#5YQX5Y2Y2Y   **VW-w<1GAJIGAJI88S^,y899 r!   num_playersc                     S/nU S:  a  U$ [        SU S-  S-   5       HH  nX-  nUS:  d  M  X2-  U :X  d  M  SR                  [        U5      /U-  5      nUR                  U5        MJ     U$ )z
Get valid team mode options for a given number of players.
Returns internal format strings.

Args:
    num_players: Number of players in the game.

Returns:
    List of valid team mode strings in internal format.
r'   r	   r   r@   )r1   r   r   r.   )r   modesr   r7   r>   s        r"   (get_team_modes_for_player_count_internal4TeamManager.get_team_modes_for_player_count_internal%  sz     ?L q+"2Q"67I#0IA~)"7;"FxxY 09 <=T"	 8 r!   c                     [         R                  U 5      nU Vs/ s H  n[         R                  X15      PM     sn$ s  snf )a#  
Get valid team mode options for a given number of players.
Returns localized display strings.

Args:
    num_players: Number of players in the game.
    locale: Language code for localization (default: "en").

Returns:
    List of valid team mode strings in user-friendly localized format.
)r$   r   r   )r   r   internal_modesr>   s       r"   get_team_modes_for_player_count+TeamManager.get_team_modes_for_player_countB  s9     %MMkZSabSa488FSabbbs   <min_playersmax_playersc                     [        5       n[        XS-   5       H)  n[        R                  U5      nUR	                  U5        M+     S[
        S[        4S jn[        X%S9$ )a  
Get all possible team mode options for a range of player counts.
Returns internal format strings.

Args:
    min_players: Minimum number of players.
    max_players: Maximum number of players.

Returns:
    Sorted list of unique team mode strings in internal format.
r   r>   r+   c                 ^    U S:X  a  gU R                  S5      n[        S U 5       5      nSX 4$ )z6Sort key for team modes (individual first, then size).r'   )r   r    r@   c              3   d   #    U  H&  oR                  5       (       d  M  [        U5      v   M(     g 7fr~   )rC   r   )r   rE   s     r"   r   CTeamManager.get_all_team_modes.<locals>.sort_key.<locals>.<genexpr>j  s     =1As   00r   )rB   sum)r>   rD   totals      r"   sort_key0TeamManager.get_all_team_modes.<locals>.sort_keye  s5    |#!JJsOE===Eu##r!   r   )r   r1   r$   r   updater   tupler   )r   r   	all_modescountr   r   s         r"   get_all_team_modesTeamManager.get_all_team_modesR  s\     E	;a8EHHOEU# 9
	$3 	$5 	$ i..r!   c                     [         R                  X5      nU Vs/ s H  n[         R                  XB5      U4PM     sn$ s  snf )a]  
Get all possible team mode options for a range of player counts.
Returns (display_string, internal_value) tuples for UI.

Args:
    min_players: Minimum number of players.
    max_players: Maximum number of players.
    locale: Language code for localization (default: "en").

Returns:
    List of (display, value) tuples sorted by internal value.
)r$   r   r   )r   r   r   r   r>   s        r"   get_all_team_modes_for_display*TeamManager.get_all_team_modes_for_displayo  sK      %77Q '
& 55dCTJ&
 	
 
s   !>c                 4    [         R                  U5      nX;   $ )a  
Check if a team mode is valid for the given number of players.

Args:
    team_mode: Internal team mode string (e.g., "individual", "2v2").
    num_players: Number of players in the game.

Returns:
    True if the team mode is valid for the player count, False otherwise.
)r$   r   )r(   r   valid_modess      r"   is_valid_team_modeTeamManager.is_valid_team_mode  s     "JJ;W''r!   c                     U R                  SSS9n/ nU H4  nU R                  XA5      nUR                  U SUR                   35        M6     SR	                  U5      S-   $ )zt
Format scores as a brief single-line string for speaking.

Returns something like: "Alice: 5. Bob: 3. Charlie: 1."
Tr   r   : . .)r   r   r.   r   r   )r2   r   sorted_teamsrD   r5   r4   s         r"   format_scores_briefTeamManager.format_scores_brief  sl     ,,dt,L D%%d3DLLD6D$4$4#567 ! yy#%%r!   c                     U R                  SSS9n/ nU HJ  nU R                  XA5      n[        R                  " USUR                  S9nUR                  U SU 35        ML     U$ )a	  
Format localized scores as a list of lines for a status box.

Returns something like (English):
["Alice: 5 points", "Bob: 3 points", ...]

The points label is localized via the "game-points" Fluent key.
No header needed - screen readers speak list items directly.
Tr   game-pointsr   r   )r   r   r
   rI   r   r.   )r2   r   r   linesr5   r4   rW   s          r"   format_scores_detailed"TeamManager.format_scores_detailed  sp     ,,dt,L D%%d3D!%%fm4CSCSTFLLD6F8,- ! r!   )r)   r&   )r+   N)en)TT)/r   r   r   r   r   r   r   r&   r   r   r(   r   dictr)   r   r<   r/   rJ   rM   rQ   rU   rZ   r^   rb   re   rh   rl   ro   rs   r   rv   rz   r   r   r   staticmethodr   r   r   r   r   r   r   r   r   r   r    r   r!   r"   r$   r$   (   s&    d3E4:3!Is!&+D&AOT#s(^A!(S	 !(d !(F6S 6T#Y 6C D4K 8# 8# 8 c C DI 'S '# '$ ''3 ' ' '!!
$;d ;4 D #s #t #2c 2d 2
B# B$t* B<$+ <($ ( (s (	? 	?$ 	?RVW[R\ 	? )83 )8 )8s )8 )8V #C #C # #J c d3i  8 cS c# cQUVYQZ c c / /# /$s) / /8 :>

'*
47
	eCHo	
 
* (c ( ( ( ($&# & &S DI  r!   r$   c                   `    \ rS rSrSr\S\4S j5       r\S\S\	\\
4   S\\   4S j5       rS	rg
)TeamResultBuilderi  z:Helpers for summarizing and formatting team-based results.team_managerc                     U R                  SSS9nU(       a  US   OSn[        5       nU H"  nU R                  U5      nUR                  X5'   M$     XU4$ )z9Return (sorted_teams, winner, ordered final_scores dict).Tr   r   N)r   r   r   r   )r   r   winnerfinal_scoresr5   r4   s         r"   	summarizeTeamResultBuilder.summarize  sb     $44dt4T$0ad.9m D--d3D!%!1!1L ! \11r!   r   r   r+   c                     [         R                  " U S5      /n[        UR                  5       S5       H7  u  nu  pE[         R                  " U SUS9nUR	                  U SU SU 35        M9     U$ )z#Format localized final score lines.zgame-final-scoresr   r   r   r   r   )r
   rI   r-   itemsr.   )r   r   r   r   r4   scorerW   s          r"   format_final_scores%TeamResultBuilder.format_final_scores  st     !!&*=>?$-l.@.@.BA$F E=D!%%fm5IFLLE7"TF"VH56 %G r!   r   N)r   r   r   r   r   r   r$   r   r   r   r   r   r   r    r   r!   r"   r   r     sU    D2 2 2 C wsCx7H TRUY  r!   r   )r   r$   r   N)r   collectionsr   collections.abcr   dataclassesr   r   typingr   mashumaro.mixins.jsonr   messages.localizationr
   r   r$   r   __all__r   r!   r"   <module>r      sq    $ # (   4 0   $ L$ L L^ 0 7r!   