
    IiL              
       D   S r SSKJrJr  SSKJr  SSKrSSKJr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SKJr  SSKJr  SSKJrJr  SSKJrJrJr  SSK J!r!  SSK"J#r#  \ " S S\5      5       r$\ " S S\5      5       r%\\
 " S S\\\\5      5       5       r&g)z
Threes Game Implementation for PlayPalace v11.

Low-score dice game: Roll 5 dice, keep at least one each roll.
Threes = 0 points. Lowest score wins!
    )	dataclassfield)datetimeN   )GamePlayer)register_game   )ActionGuardMixin)RoundBasedGameMixin)Action	ActionSet
Visibility)	BotHelperDiceSet)DiceGameMixin)
GameResultPlayerResult)	IntOptionoption_fieldGameOptions)Localization)KeybindStatec                   N    \ rS rSr% Sr\" S S9r\\S'   Sr	\
\S'   Sr\
\S'   S	rg
)ThreesPlayer   zPlayer state for Threes game.c                      [        SSS9$ )N      )num_dicesidesr        7c:\Users\dbart\PlayPalace11\server\games\threes\game.py<lambda>ThreesPlayer.<lambda>   s    '1A2Nr$   default_factorydicer   
turn_scoretotal_scorer#   N)__name__
__module____qualname____firstlineno____doc__r   r*   r   __annotations__r+   intr,   __static_attributes__r#   r$   r%   r   r      s)    '*NOD'OJKr$   r   c                   J    \ rS rSr% Sr\" \" SSSSSSS	S
S95      r\\	S'   Sr
g)ThreesOptions#   zOptions for Threes game.
         roundszthrees-set-roundszthrees-enter-roundszthrees-option-changed-roundszthrees-desc-rounds)defaultmin_valmax_val	value_keylabelprompt
change_msgdescriptiontotal_roundsr#   N)r-   r.   r/   r0   r1   r   r   rD   r3   r2   r4   r#   r$   r%   r6   r6   #   s6    "$%(5,		
L# r$   r6   c            	         ^  \ rS rSr% SrS/r\" \S9r\\	   \
S'   \" \S9r\\
S'   Sr\S\4S	 j5       r\S\4S
 j5       r\S\4S j5       r\S\4S j5       r\S\4S j5       rS3S\S\S\S\	4S jjr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\S-  4S jrS\S\4S jrS\S\S\S-  4S jr S\S\S\4S jr!S\	S\"4S jr#S4U 4S jjr$S\S\SS4S jr%S\S\SS4S  jr&S\S\SS4S! jr'S\	SS4S" jr(S\4S# jr)S4S$ jr*S4S% jr+S4S& jr,S4S' jr-S4S( jr.S4S) jr/S4S* jr0S\14S+ jr2S,\1S-\S\\   4S. jr3S4U 4S/ jjr4S\S\S-  4S0 jr5S\	SS4S1 jr6S2r7U =r8$ )5
ThreesGame5   aV  
Threes dice game.

Roll 5 dice, then keep at least one die each roll before rolling again.
Kept dice become locked and can't be rerolled.
Continue until all dice are locked or only 1 die remains.

Scoring:
- Threes = 0 points
- All other dice = face value
- Five sixes = "Shooting the moon" = -30 points

Lowest score wins after all rounds.
dice_keeping_styler(   playersoptionsNreturnc                     g)NThreesr#   clss    r%   get_nameThreesGame.get_nameN       r$   c                     g)Nthreesr#   rN   s    r%   get_typeThreesGame.get_typeR   rR   r$   c                     g)Nzcategory-dice-gamesr#   rN   s    r%   get_categoryThreesGame.get_categoryV   s    $r$   c                     g)Nr   r#   rN   s    r%   get_min_playersThreesGame.get_min_playersZ       r$   c                     g)N   r#   rN   s    r%   get_max_playersThreesGame.get_max_players^   r]   r$   	player_idnameis_botc                     [        XUS9$ )z/Create a new player with Threes-specific state.)idrc   rd   )r   )selfrb   rc   rd   s       r%   create_playerThreesGame.create_playerb   s    yFCCr$   playerc                    U R                  U5      nU(       a  U$ UnUR                  R                  (       d  gUR                  R                  S::  a  gUR                  R                  (       a  gUR                  R
                  S:X  a  gg)z Check if roll action is enabled.Nr9   zthrees-must-bankr   threes-must-keep)guard_turn_action_enabledr*   
has_rolledunlocked_countall_decidedkept_unlocked_countrg   rj   errorthrees_players       r%   _is_roll_enabledThreesGame._is_roll_enabledj   st    ..v6L&,!!,,,,1%))%11Q6%r$   c                     UnU R                  UUR                  R                  =(       a    UR                  R                  (       + S9$ )z/Roll is visible during play for current player.extra_condition)turn_action_visibilityr*   rn   rp   rg   rj   rt   s      r%   _is_roll_hiddenThreesGame._is_roll_hidden}   sE    &,**!.!3!3!>!>!a=CUCUCaCab + 
 	
r$   c                     U R                  U5      nU(       a  U$ UnUR                  R                  (       d  gUR                  R                  (       d  gg)z Check if bank action is enabled.zthrees-roll-firstzthrees-keep-all-firstN)rm   r*   rn   rp   rr   s       r%   _is_bank_enabledThreesGame._is_bank_enabled   sF    ..v6L&,!!,,&!!--*r$   c                 N    UnU R                  UUR                  R                  S9$ )z%Bank is hidden until dice are rolled.rx   rz   r*   rn   r{   s      r%   _is_bank_hiddenThreesGame._is_bank_hidden   1    &,**)..99 + 
 	
r$   c                 r    U R                  5       nU(       a  U$ UnUR                  R                  (       d  gg)z&Check if check_hand action is enabled.threes-no-dice-yetN)guard_game_activer*   rn   rr   s       r%   _is_check_hand_enabled!ThreesGame._is_check_hand_enabled   s2    &&(L&,!!,,'r$   c                 "    [         R                  $ )z+Check hand is always hidden (keybind only).)r   HIDDENrg   rj   s     r%   _is_check_hand_hidden ThreesGame._is_check_hand_hidden   s       r$   	die_indexc                     U R                  U5      nU(       a  U$ UnUR                  R                  (       d  gUR                  R                  U5      (       a  gUR                  R                  S::  a  gg)z4Check if toggling die at index is enabled in Threes.zdice-not-rolledzdice-lockedr9   zthrees-last-dieN)rm   r*   rn   	is_lockedro   )rg   rj   r   rs   rt   s        r%   _is_dice_toggle_enabled"ThreesGame._is_dice_toggle_enabled   se    ..v6L&,!!,,$''	22 ,,1$r$   c                 N    UnU R                  UUR                  R                  S9$ )z%Check if die toggle action is hidden.rx   r   )rg   rj   r   rt   s       r%   _is_dice_toggle_hidden!ThreesGame._is_dice_toggle_hidden   r   r$   c           
         U R                  U5      nU(       a  UR                  OSn[        SS9nU R                  U5        UR	                  [        S[        R                  " US5      SSSS	95        UR	                  [        S
[        R                  " US5      SSSS	95        UR	                  [        S[        R                  " US5      SSSS	95        U$ )z(Create the turn action set for a player.enturnrc   rollzthrees-roll_action_rollru   r|   )rf   r@   handler
is_enabled	is_hiddenbankzthrees-bank_action_bankr   r   
check_handzthrees-check-hand_action_check_handr   r   )get_userlocaler   add_dice_toggle_actionsaddr   r   get)rg   rj   userr   
action_sets        r%   create_turn_action_set!ThreesGame.create_turn_action_set   s    }}V$ $$F+
 	$$Z0"&&v}=&-+	
 	"&&v}=&-+	
 	"&&v/BC,31	
 r$   c                   > [         TU ]  5         U R                  SSS/[        R                  S9  U R                  SSS/[        R                  S9  U R                  5         U R                  SS	S
/[        R                  S9  g)z!Define all keybinds for the game.rz	Roll dicer   )statebzBank and end turnr   hz
Check handr   N)supersetup_keybindsdefine_keybindr   ACTIVEsetup_dice_keybindsrg   	__class__s    r%   r   ThreesGame.setup_keybinds   s~      	Cvhl>Q>QRC!4vhlFYFYZ 	  " 	C~\EXEXYr$   	action_idc                 $  ^ [        T[        5      (       d  gTR                  R                  (       aD  TR                  R                  S:X  a*  U R                  T5      nU(       a  UR                  S5        gTR                  R                  n[        TR                  R                  5      n[        TR                  R                  5      nU(       a>  [        TR                  R                  5       Vs/ s H  nXu;  d  M
  Xv;  d  M  UPM     nnO([        [        TR                  R                  5      5      nU R                  S5        TR                  R                  5         U R                  T5        SR!                  U4S jU 5       5      n	U R#                  TSSU	S	9  TR                  R$                  S
::  a  U R'                  T5        gTR(                  (       a*  SSKn
[,        R.                  " TU
R0                  " SS5      S9  U R3                  5         SnU R5                  T5       HE  nUR6                  R8                  R;                  S5      (       d  M/  UR6                  R8                  n  O   U(       a  U R=                  TUS9  ggs  snf )zHandle rolling dice.Nr   rl   zgame_pig/roll.ogg, c              3   h   >#    U  H'  n[        TR                  R                  U   5      v   M)     g 7fN)strr*   values).0irj   s     r%   	<genexpr>*ThreesGame._action_roll.<locals>.<genexpr>  s(     PAS!3!3A!677s   /2zthrees-you-rolledzthrees-player-rolledr*   r9         tickstoggle_die_)selection_id)
isinstancer   r*   rn   rq   r   speak_lsetlockedkeptranger!   list
play_soundr   _apply_dice_values_defaultsjoinbroadcast_personal_lro   _score_turnrd   randomr   jolt_botrandintrebuild_all_menusget_all_visible_actionsactionrf   
startswithupdate_player_menu)rg   rj   r   r   
had_rolledlocked_beforekept_beforer   rolled_indicesdice_strr   next_toggleresolveds    `           r%   r   ThreesGame._action_roll   s   &,// ;;!!{{..!3}}V,LL!34[[++
FKK../&++**+ v{{3344A) ./.B 4  N "%(<(<"=>N 	+,((0 99PPP!!')?h 	" 	

 ;;%%*V$ ==vV^^B-CD 44V<H!!,,];;&oo00 = ##F#E Is   3	J JJc                 R    [        U[        5      (       d  gU R                  U5        g)zBank score and end turn.N)r   r   r   )rg   rj   r   s      r%   r   ThreesGame._action_bank6  s     &,// r$   c                    [        U[        5      (       d  gU R                  U5      nU(       d  gUR                  R                  (       d  UR                  S5        gUR                  SUR                  R                  5       S9  g)zCheck current dice.Nr   zthrees-your-dicer   )r   r   r   r*   rn   r   
format_all)rg   rj   r   r   s       r%   r   ThreesGame._action_check_hand<  sa    &,//}}V${{%%LL-.'fkk.D.D.FGr$   c                    UR                   R                  SS9nUR                   R                  S5      nUS:X  a'  SnU R                  S5        U R	                  USS5        O#U R                  S	5        U R	                  US
SUS9  X!l        U=R                  U-  sl        U R                  R                  UR                  U5        U R                  5         g)zCalculate and apply turn score.r
   )exclude_valuer    r   igame_pig/win.oggzthrees-you-shot-moonzthrees-shot-moonzgame_pig/bank.oggzthrees-you-scoredzthrees-scored)scoreN)r*   
sum_valuescount_valuer   r   r+   r,   _team_manageradd_to_team_scorerc   _on_turn_end)rg   rj   r   	six_counts       r%   r   ThreesGame._score_turnK  s     &&Q&7KK++A.	 >EOO./%%f.DFXYOO/0%%f.A?Z_%`!e#,,V[[%@r$   c                     g)NTr#   rg   s    r%   should_reset_all_scores"ThreesGame.should_reset_all_scoresd  s    r$   c                 r    [        U[        5      (       a"  SUl        UR                  R	                  5         g g Nr   )r   r   r,   r*   resetr   s     r%   _reset_player_for_game!ThreesGame._reset_player_for_gameg  s,    fl++!"FKK ,r$   c                 r    [        U[        5      (       a"  UR                  R                  5         SUl        g g r   )r   r   r*   r   r+   r   s     r%   _reset_player_for_turn!ThreesGame._reset_player_for_turnl  s,    fl++KK !F ,r$   c                 "    U R                  SS9  g )Nzgame_3cardpoker/turn.ogg)
turn_sound)announce_turnr   s     r%   _announce_turn_startThreesGame._announce_turn_startq  s    &@Ar$   c                 |    UR                   (       a+  [        R                  " U[        R                  " SS5      S9  g g )Nr:   (   r   )rd   r   r   r   r   r   s     r%   _setup_bot_for_turnThreesGame._setup_bot_for_turnt  s)    ==vV^^B-CD r$   c                    U R                    Vs/ s H2  n[        U[        5      (       d  M  UR                  UR                  4PM4     nnUR                  S S9  SR                  S U 5       5      nU R                  SU R                  US9  U R                  U R                  R                  :  a  U R                  5         gU R                  5         gs  snf )zEnd the current round.c                     U S   $ Nr9   r#   xs    r%   r&   *ThreesGame._on_round_end.<locals>.<lambda>|  s    !A$r$   keyr   c              3   4   #    U  H  u  pU S U 3v   M     g7f): Nr#   )r   rc   r   s      r%   r   +ThreesGame._on_round_end.<locals>.<genexpr>}  s     LVkd$r%1Vs   zthrees-round-scores)roundscoresN)rI   r   r   rc   r,   sortr   broadcast_lr  rJ   rD   	_end_game_start_round)rg   pr  
scores_strs       r%   _on_round_endThreesGame._on_round_endx  s     48<<_<a:aQ]C^)1661==)<_'YYLVLL
.djjT ::222NN  `s
   CCc                     U =R                   S-  sl         U R                  U R                  5       5        U R                  SU R                   U R                  R
                  S9  U R                  5         g)zStart a new round.r9   zthrees-round-start)r  totalN)r  set_turn_playersget_active_playersr  rJ   rD   _start_turnr   s    r%   r  ThreesGame._start_round  s^    

a
d5578 **,,++ 	 	

 	r$   c                 R   U R                    Vs/ s H/  n[        U[        5      (       d  M  UR                  (       a  M-  UPM1     nnU(       d  gU Vs/ s H  oUR                  4PM     nnUR                  S S9  US   S   nU VVs/ s H  u  pXT:X  d  M  UPM     nnn[        U5      S:X  a0  U R                  S5        U R                  SUS   R                  US9  O(S	R                  S
 U 5       5      nU R                  SXtS9  U R                  5         gs  snf s  snf s  snnf )z!End the game and announce winner.Nc                     U S   $ r  r#   r  s    r%   r&   &ThreesGame._end_game.<locals>.<lambda>  s    qtr$   r  r   r9   r   zthrees-winner)rj   r   z and c              3   8   #    U  H  oR                   v   M     g 7fr   r   )r   ws     r%   r   'ThreesGame._end_game.<locals>.<genexpr>  s     '@1s   z
threes-tie)rI   r   )rI   r   r   is_spectatorr,   r  lenr   r  rc   r   finish_game)rg   r  active_playersplayers_with_scoreslowest_scoreswinnerswinner_namess           r%   r  ThreesGame._end_game  s    ||
#!z!\'BA1>>A| 	 
  <JJ>a1==1>J  ^ 4*1-a0!4J!48I1!4Jw<1OO./_WQZ__LY"<<'@'@@L\<T)
 K Ks!   DDDD	D#D#c                    [        U R                   Vs/ s H/  n[        U[        5      (       d  M  UR                  (       a  M-  UPM1     snS S9n0 nU H  nUR
                  X1R                  '   M     U(       a  US   OSn[        U R                  5       [        R                  " 5       R                  5       U R                  U Vs/ s H8  n[        UR                  UR                  UR                  [!        USS5      S9PM:     snU(       a  UR                  OSU(       a  UR
                  OSUU R"                  U R$                  R&                  SS	.S
9$ s  snf s  snf )z0Build the game result with Threes-specific data.c                     U R                   $ r   )r,   )r  s    r%   r&   .ThreesGame.build_game_result.<locals>.<lambda>  s    !--r$   r  r   Nis_virtual_botF)rb   player_namerd   r<  lowest_wins)winner_namewinner_scorefinal_scoresrounds_playedrD   scoring_mode)	game_type	timestampduration_ticksplayer_resultscustom_data)sortedrI   r   r   r/  r,   rc   r   rU   r   now	isoformatsound_scheduler_tickr   rf   rd   getattrr  rJ   rD   )rg   r  sorted_playersrA  winners        r%   build_game_resultThreesGame.build_game_result  s&     [1
1l(CQANNQ['
 A#$==L    '5"$mmolln..044 ( (A dd !88#*1.>#F	 ( /5v{{$6< 2 2! ,!% $ 9 9 -
 	
 \s   EEE?Eresultr   c                    [         R                  " US5      /nUR                  R                  S0 5      n[        UR	                  5       S5       H7  u  nu  pg[         R                  " USUS9nUR                  U SU SU 35        M9     U$ )z&Format the end screen for Threes game.zgame-final-scoresrA  r9   zgame-points)countz. r  )r   r   rH  	enumerateitemsappend)	rg   rR  r   linesrA  r   rc   r   
points_strs	            r%   format_end_screenThreesGame.format_end_screen  s    !!&*=>?))--nbA ),*<*<*> BA}%))&-uMJLLA3bb56 !C r$   c                 r   > [         TU ]  5         U R                  (       d  g[        R                  " U 5        g)z!Called every tick. Handle bot AI.N)r   on_tickgame_activer   r   s    r%   r]  ThreesGame.on_tick  s'    $r$   c                 .   [        U[        5      (       d  gUR                  R                  (       d  gUR                  R                  S::  a  gUR                  R
                  (       a  gU R                  U5        UR                  R                  S:  a  gg)zBot AI decision making.Nr   r9   r   r   )r   r   r*   rn   ro   rp   _bot_decide_keepersrq   r   s     r%   	bot_thinkThreesGame.bot_think  sy    &,// {{%% ;;%%* ;;"" 	  ( ;;**Q. r$   c                   ^ UR                   m[        TR                  5      Tl        0 n[	        S5       HM  nTR                  U5      (       a  M  TR                  U5      nUc  M1  XB;  a  / X$'   X$   R                  U5        MO     [        U4S jTR                   5       5      nUR                  S/ 5      nUS:  d  [        U5      U-   S:  a"  U H  nTR                  U5        M     U(       a  gSU;   a  US    H  nTR                  U5        M     gSU;   a  US    H  nTR                  U5        M     gSU;   a  US    H  nTR                  U5        M     gS	 H   nXB;   d  M
  TR                  X$   S
   5          g   g)z$Bot AI to decide which dice to keep.r   Nc              3   V   >#    U  H  nTR                  U5      S :X  d  M  Sv   M      g7f)r    r9   N)	get_value)r   r   r*   s     r%   r   1ThreesGame._bot_decide_keepers.<locals>.<genexpr>  s#     LkT^^A5F!5K11ks   )	)r    r
      r9   r   )rh  r   r    r   )r*   r   r   r   r   r   rf  rW  sumr   r0  keep)rg   rj   	availabler   valuelocked_sixesavailable_sixesr*   s          @r%   ra  ThreesGame._bot_decide_keepers  si   {{ %	 +-	qA>>!$$q)$-+-	($++A.  LdkkLL#--2. 1_!5!D!I$		! % 	>q\		! " 	>q\		! " 	>q\		! " E!		)*1-. r$   r#   )F)rK   N)9r-   r.   r/   r0   r1   relevant_preferencesr   r   rI   r   r2   r6   rJ   round_start_soundclassmethodr   rP   rU   rX   r3   r[   r`   boolrh   r   ru   r   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r!  r  r  r   rP  rZ  r]  rb  ra  r4   __classcell__)r   s   @r%   rF   rF   5   s    11"'"=GT,="=AG]A      %S % %      Ds D# Dt DP\ Dv #* &
f 
 

v 
#* 

f 
 
V d
 !F !z !
f  t 
V 
 

 
)\ )i )VZ6F6 6Fc 6Fd 6Ft!6 !c !d !H HC HD H, 4 2  
"
BE 	2$
: $
L	
 	C 	DI 	  3: 62, 24 2 2r$   rF   )'r1   dataclassesr   r   r   r   baser   r   registryr	   game_utils.action_guard_mixinr   !game_utils.round_based_game_mixinr   game_utils.actionsr   r   r   game_utils.bot_helperr   game_utils.dicer   game_utils.dice_game_mixinr   game_utils.game_resultr   r   game_utils.optionsr   r   r   messages.localizationr   server.core.ui.keybindsr   r   r6   rF   r#   r$   r%   <module>r     s    )    $ = D ? ? . & 7 > F F 1 0 6   K  " z!#6m z  zr$   