
    Ii,|                        % S r SSKJrJr  SSKJr  SSKrSSK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JrJr  S	SKJr  S	SKJrJr  S	SKJrJrJrJr  S	SKJ r   SSK!J"r"  Sq#\$\%\$\%\&4   4   S-  \'S'   S\$\%\$\%\&4   4   4S jr(S\)\%   4S jr*\ " S S\5      5       r+\ " S S\5      5       r,\\ " S S\\
5      5       5       r-g)z
Rolling Balls Game Implementation for PlayPalace v11.

Take turns picking 1, 2, or 3 balls from a pipe. Watch out for negative balls!
The player with the most points when the pipe empties wins.
    )	dataclassfield)datetimeN)Path   )GamePlayerGameOptions)register_game   )ActionGuardMixin)Action	ActionSet
Visibility)	BotHelper)
GameResultPlayerResult)	IntOptionMultiSelectOptionmulti_select_fieldoption_field)Localization)KeybindState_ball_packsreturnc                      [         cL  [        [        5      R                  S-  n [	        U SSS9 n[
        R                  " U5      q SSS5        [         $ [         $ ! , (       d  f       [         $ = f)z3Load ball packs from JSON file. Results are cached.Nzball_packs.jsonrzutf-8)encoding)r   r   __file__parentopenjsonload)
packs_pathfs     =c:\Users\dbart\PlayPalace11\server\games\rollingballs\game.pyload_ball_packsr'      sY     (^**->>
*cG4))A,K 5; 54s   A
A-c                  D    [        [        5       R                  5       5      $ )zGet available pack IDs.)listr'   keys     r&   get_pack_namesr-   '   s    !&&())r,   c                   z    \ rS rSr% SrSr\\S'   Sr\	\S'   Sr
\\S'   Sr\\S'   S	r\\   S	-  \S
'   Sr\\S'   Srg	)RollingBallsPlayer,   z$Player state for Rolling Balls game.r   scoreFhas_reshuffledview_pipe_usesreshuffle_usesNlast_viewed_pipebot_pipe_memoryr+   )__name__
__module____qualname____firstlineno____doc__r1   int__annotations__r2   boolr3   r4   r5   r)   dictr6   __static_attributes__r+   r,   r&   r/   r/   ,   sJ    .E3N ND NCNC*.d4j4'.OSr,   r/   c                   F   \ rS rSr% Sr\" \" SSSSSSSS	95      r\\	S
'   \" \" SSSSSSSS	95      r
\\	S'   \" \" SSSSSSSS	95      r\\	S'   \" \" SSSSSSSS	95      r\\	S'   \" \" SSSSSSSS	9SS 4S9r\\	S '   \" \" \" 5       S   /\S!S"SS#95      r\\   \	S$'   S%rg&)'RollingBallsOptions8   zOptions for Rolling Balls game.      countzrb-set-min-takezrb-enter-min-takezrb-option-changed-min-take)defaultmin_valmax_val	value_keylabelprompt
change_msgmin_taker   zrb-set-max-takezrb-enter-max-takezrb-option-changed-max-takemax_taker   d   zrb-set-view-pipe-limitzrb-enter-view-pipe-limitz!rb-option-changed-view-pipe-limitview_pipe_limitzrb-set-reshuffle-limitzrb-enter-reshuffle-limitz!rb-option-changed-reshuffle-limitreshuffle_limitpointszrb-set-reshuffle-penaltyzrb-enter-reshuffle-penaltyz#rb-option-changed-reshuffle-penaltyc                     U S:  $ )Nr   r+   )vs    r&   <lambda>RollingBallsOptions.<lambda>r   s    1q5r,   )visible_whenreshuffle_penaltyzrb-set-ball-packszrb-option-changed-ball-packs)rG   choicesrK   rM   min_selected
ball_packsr+   N)r7   r8   r9   r:   r;   r   r   rN   r<   r=   rO   rQ   rR   rY   r   r   r-   r\   r)   strr@   r+   r,   r&   rB   rB   8   s7   ) #&3	

Hc 
 !#&3	

Hc 
 (*-:	

OS 
 (*-:	

OS 
 *,/<	
 (9s  /#%a()"%5	
JS	 r,   rB   c            	         ^  \ rS rSr% Sr\" \S9r\\   \	S'   \" \
S9r\
\	S'   \" \S9r\\   \	S'   \" \S9r\\   \	S'   Sr\\	S	'   S
r\\	S'   \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SES\S\S\S\4S jjrS\S\SS4U 4S jjrSFS jrS\\   4S jrS\4S jrS\S\4S jr SFU 4S jjr!S\"S \S\S-  4S! jr#S\"S\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 \S\4S' jr*S\"S \S\4S( jr+S\"S \SS4S) jr,S\"S*\SS4S+ jr-SFS, jr.SFS- jr/S\"S \SS4S. jr0S\"S \SS4S/ jr1S\"S\S-  4S0 jr2S\"S\S-  4S1 jr3S\"S \SS4S2 jr4S\"S \SS4S3 jr5SFS4 jr6SFS5 jr7SFS6 jr8SFU 4S7 jjr9S\S\\   4S8 jr:S\S\S-  4S9 jr;SFS: jr<SFS; jr=SFS< jr>S\?4S= jr@S>\?S?\S\\   4S@ jrASGSA\SB\SS4SC jjrBSDrCU =rD$ )HRollingBallsGame   z
Rolling Balls pipe game.

Players take turns picking 1, 2, or 3 balls from a pipe. Each ball has
a value from -5 to +5 with a flavor description. The player with the
highest score when the pipe empties wins.
)default_factoryplayersoptionspipe_ball_reveal_queuer   _ball_reveal_tick _ball_reveal_player_idr   c                     g)NzRolling Ballsr+   clss    r&   get_nameRollingBallsGame.get_name   s    r,   c                     g)Nrollingballsr+   rj   s    r&   get_typeRollingBallsGame.get_type   s    r,   c                     g)Nzcategory-uncategorizedr+   rj   s    r&   get_categoryRollingBallsGame.get_category   s    'r,   c                     g)Nr   r+   rj   s    r&   get_min_players RollingBallsGame.get_min_players       r,   c                     g)N   r+   rj   s    r&   get_max_players RollingBallsGame.get_max_players   rx   r,   	player_idnameis_botc                     [        XUS9$ )z-Create a new player with Rolling Balls state.)idr~   r   )r/   )selfr}   r~   r   s       r&   create_playerRollingBallsGame.create_player   s    !Y&IIr,   option_namevalueNc                   > [         TU ]  X5        US:X  ad  U R                  R                  U R                  R                  :  a%  U R                  R                  U R                  l        U R                  5         gUS:X  ad  U R                  R                  U R                  R                  :  a%  U R                  R                  U R                  l        U R                  5         gg)zHHandle option changes, rebuilding turn actions when min/max take change.rN   rO   N)super_handle_option_changerc   rO   rN   _rebuild_turn_actions)r   r   r   	__class__s      r&   r   &RollingBallsGame._handle_option_change   s    %k9*$||$$t||'<'<<(,(=(=%&&(J&||$$t||'<'<<(,(=(=%&&(	 'r,   c                    U R                    H  nU R                  US5      nU(       d  M  UR                  S5        U R                  U5      nU(       a  UR                  OSn[        U R                  R                  U R                  R                  S-   5       H6  nUR                  [        SU 3[        R                  " USUS9SSS	S
95        M8     M     U R                  5         g)zLRebuild the turn action set for all players to reflect min/max take changes.turntake_enrD   rb-takerF   _action_take_is_take_enabled_is_take_hiddenr   rK   handler
is_enabled	is_hiddenN)rb   get_action_setremove_by_prefixget_userlocalerangerc   rN   rO   addr   r   getrebuild_all_menus)r   playerturn_setuserr   ns         r&   r   &RollingBallsGame._rebuild_turn_actions   s    llF**66:Hx))'2}}V,(,$t||44dll6K6Ka6OPALL!&qc{"."2"269A"N$2'9&7 Q #$ 	 r,   c                 @    [        U R                  R                  5      $ )zGet list of active pack IDs.)r)   rc   r\   r   s    r&   _get_active_packs"RollingBallsGame._get_active_packs   s    DLL++,,r,   c                    [        U R                  5       5      nUS:  a  SnOUS:X  a  SnOSn[        5       n/ nU R                  5        H4  nUR	                  U0 5      nUR                  UR                  5       5        M6     / U l        [        U5       H8  n[        R                  " U5      u  pU R                  R                  XS.5        M:     U$ )z/Fill the pipe with balls based on player count.rz   2   r   #      )r   description)lenget_active_playersr'   r   r   extenditemsrd   r   randomchoiceappend)
r   player_counttotal_ballspacks	ball_poolpack_idpack_r   r   s
             r&   	fill_pipeRollingBallsGame.fill_pipe   s    422451KQKK  !+-	--/G99Wb)DTZZ\* 0 	{#A!'y!9KIIuIJ $ r,   r   c                     U R                  U5      nU(       a  UR                  OSn[        SS9nU R                  R                  S:  aU  U R                  R                  UR
                  -
  nUR                  [        S[        R                  " USUS9SS	S
SSS95        U R                  R                  S:  aT  U R                  R                  UR                  -
  nUR                  [        S[        R                  " USUS9SSSSS95        [        U R                  R                  U R                  R                  S-   5       H6  nUR                  [        SU 3[        R                  " USUS9SSSS95        M8     U$ )z(Create the turn action set for a player.r   r   )r~   r   	view_piperb-view-pipe-action	remaining_action_view_pipe_is_view_pipe_enabled_is_view_pipe_hidden_get_view_pipe_labelT)r   rK   r   r   r   	get_labelshow_in_actions_menu	reshufflerb-reshuffle-action_action_reshuffle_is_reshuffle_enabled_is_reshuffle_hidden_get_reshuffle_label)r   rK   r   r   r   r   rD   r   r   r   r   r   r   r   )r   r   r   rc   rQ   r3   r   r   r   r   rR   r4   r   rN   rO   )r   r   r   r   
action_setr   r   s          r&   create_turn_action_set'RollingBallsGame.create_turn_action_set   sa   }}V$ $$F+
 <<''!+44v7L7LLINN"&**63HT]^/644)-
 <<''!+44v7L7LLINN"&**63HT]^/644	 t||,,dll.C.Ca.GHANNqc{&**69AF*1/ I r,   c                 F  > [         TU ]  5         [        SS5       H@  nSU SUS:w  a  SOS 3nU R                  [	        U5      USU 3/[
        R                  S9  MB     U R                  S	S
S/[
        R                  S9  U R                  SSS/[
        R                  S9  g)z!Define all keybinds for the game.rD      zTake z ballsrg   r   )statedzReshuffle piper   pz	View piper   N)r   setup_keybindsr   define_keybindr]   r   ACTIVE)r   r   rK   r   s      r&   r   RollingBallsGame.setup_keybinds'  s     q!AA3e16Cr#:;EA%s}LDWDWX  	C!1K=H[H[\C{m<CVCVWr,   	action_idc                     U R                   (       a  gU R                  U5      nU(       a  U$ [        UR                  S5      5      n[	        U R
                  5      U:  a  gg )Naction-not-your-turnr   rb-not-enough-balls)rh   guard_turn_action_enabledr<   removeprefixr   rd   )r   r   r   errorrF   s        r&   r   !RollingBallsGame._is_take_enabled5  sQ    &&)..v6LI**734tyy>E!(r,   c                    U R                   (       a  gU R                  U5      nU(       a  U$ UnUR                  U R                  R                  :  a  gUR
                  (       a  g[        U R                  5      S:  a  gg )Nr   zrb-no-reshuffles-leftzrb-already-reshuffledr   r   )rh   r   r4   rc   rR   r2   r   rd   r   r   r   	rb_players       r&   r   &RollingBallsGame._is_reshuffle_enabled@  sh    &&)..v6L(.	##t||'C'CC*##*tyy>A(r,   c                     U R                  5       nU(       a  U$ UnUR                  U R                  R                  :  a  gg )Nzrb-no-views-left)guard_game_activer3   rc   rQ   r   s       r&   r   &RollingBallsGame._is_view_pipe_enabledO  s;    &&(L(.	##t||'C'CC%r,   c                     [        UR                  S5      5      nU R                  U[        U R                  5      U:  S9$ )Nr   extra_condition)r<   r   turn_action_visibilityr   rd   r   r   r   rF   s       r&   r    RollingBallsGame._is_take_hidden\  s;    I**734**63tyy>UZCZ*[[r,   c                    UnU R                   R                  S:  =(       aZ    UR                  U R                   R                  :  =(       a0    UR                  (       + =(       a    [	        U R
                  5      S:  nU R                  XS9$ )Nr   r   r   )rc   rR   r4   r2   r   rd   r   )r   r   r   can_reshuffles       r&   r   %RollingBallsGame._is_reshuffle_hidden`  sy    (.	LL((1, $((4<<+G+GG$,,,$ DII!#	 	 **6*QQr,   c                    UnU R                   R                  S:  =(       a9    UR                  U R                   R                  :  =(       a    U R                  S:H  nU(       a  [        R
                  $ [        R                  $ )Nr   playing)rc   rQ   r3   statusr   VISIBLEHIDDEN)r   r   r   can_views       r&   r   %RollingBallsGame._is_view_pipe_hiddenj  si    (.	LL((1, )((4<<+G+GG)y( 	
 %%%   r,   c                     U R                  U5      nU(       a  UR                  OSnUnU R                  R                  UR                  -
  n[
        R                  " USUS9$ )Nr   r   r   )r   r   rc   rR   r4   r   r   r   r   r   r   r   r   r   s          r&   r   %RollingBallsGame._get_reshuffle_labely  R    }}V$ $$(.	LL0093K3KK	(=SSr,   c                     U R                  U5      nU(       a  UR                  OSnUnU R                  R                  UR                  -
  n[
        R                  " USUS9$ )Nr   r   r   )r   r   rc   rQ   r3   r   r   r   s          r&   r   %RollingBallsGame._get_view_pipe_label  r   r,   c                 Z    [        UR                  S5      5      nU R                  X5        g )Nr   )r<   r   _take_ballsr   s       r&   r   RollingBallsGame._action_take  s%    I**734'r,   rF   c                    UnU R                  USSUS9  U R                  S[        R                  " SS5       S35        / n[	        U5       H@  nU R
                  (       d    O.UR                  U R
                  R                  S5      5        MB     [        U5      nU R                   H6  nUnUR                  (       d  M  [        SUR                  U-
  5      Ul        M8     U H  n	U=R                  U	S	   -  sl        M     [        US5       H	  u  pXS
'   M     X@l        UR                   U l        U R$                  S-   U l        g)z6Take balls from the pipe, queuing reveals for on_tick.zrb-you-takezrb-player-takesr   zgame_rollingballs/takerD   r   .oggr   r   num   N)broadcast_personal_l
play_soundr   randintr   rd   r   popr   rb   r   maxr6   r1   	enumeratere   r   rh   sound_scheduler_tickrf   )r   r   rF   r   ballsr   takenr   rb_pballis              r&   r  RollingBallsGame._take_balls  s   (.	!!&-9JRW!X011E0FdKL uA99LLq)*  E
A'(D{{{'*1d.B.BU.J'K$  DOOtG},O  !*GAK +"'&,ii#!%!:!:Q!>r,   c                    U R                   R                  S5      nUS   nUS   nUS   n[        U5      nUS::  a  UOSnU R                  S5        US:  a'  U R	                  SU S3S	S
S9  U R                  SX$US9  O<US:  a&  U R	                  SU S3S	S9  U R                  SX$US9  OU R                  SX$S9  U R                   (       a  U R                  S-   U l        gU R                  S-   U l        g)zGReveal the next ball from the queue with synchronized sound and speech.r   r  r   r   rE   zgame_rollingballs/takeball.oggzgame_rollingballs/plusr  rD   P   )delay_ticksvolumezrb-ball-plusr  r   r   zgame_rollingballs/minusr  zrb-ball-minuszrb-ball-zero)r  r         N)re   r  absr  schedule_soundbroadcast_lr  rf   )r   r  ball_numr   r   	abs_valuesound_values          r&   _reveal_next_ball"RollingBallsGame._reveal_next_ball  s#   &&**1-; W=)J	#,>iq 	8919(T:RT    ^ZcdQY"9+d KYZ[Xi   ^S""%)%>%>%CD" &*%>%>%CD"r,   c                     U R                  U R                  5      nSU l        U(       d  gUnU R                  SUR                  UR                  S9  U R                  5         g)z9Announce score and end turn after all balls are revealed.rg   Nzrb-new-score)r   r1   )get_player_by_idrh   r!  r~   r1   end_turn)r   r   r   s      r&   _finish_ball_reveals%RollingBallsGame._finish_ball_reveals  sQ    &&t'B'BC&(#(.	9??Sr,   c                 6   UnU R                  USS5        U R                  S[        R                  " SS5       S35        [	        [        U R                  5      S5      nU R                  SU n[        R                  " U5        XPR                  SU& U R                   H  nUnUR                  (       d  M  S	Ul
        M!     U R                  S
5        U R                  R                  S	:  aX  U=R                  U R                  R                  -  sl        U R                  SUR                  U R                  R                  S9  SUl        U=R"                  S-  sl        [$        R&                  " U[        R                  " SS5      S9  U R)                  5         g)z Reshuffle a portion of the pipe.zrb-you-reshufflezrb-player-reshuffleszgame_rollingballs/disruptrD   r   r  r  Nr   zrb-reshuffledzrb-reshuffle-penalty)r   rS   Tr	  r  ticks)r
  r  r   r  minr   rd   shufflerb   r   r6   r!  rc   rY   r1   r~   r2   r4   r   jolt_botr   )r   r   r   r   shuffle_countsectionr   r  s           r&   r   "RollingBallsGame._action_reshuffle  sQ   (.	!!&*<>TU'q!(<'=TB	

 C		NB/))N]+w$+		.=! A'(D{{{'($ 
 	) <<))A-OOt||===O&{{||55   $(	   A%  	62)>? 	 r,   c                 F   UnU R                  U5      nU(       d  gUR                  U R                  :w  aD  U=R                  S-  sl        U R                   Vs/ s H  oUR	                  5       PM     snUl        UR
                  n[        R                  " US[        U R                  5      S9/n[        U R                  S5       H2  u  pUR                  [        R                  " USUU	S   U	S   S95        M4     U R                  X5        U R                  5         gs  snf )	z:View the pipe contents (private to the requesting player).NrD   zrb-view-pipe-headerr   zrb-view-pipe-ballr   r   r  )r   r5   rd   r3   copyr   r   r   r   r  r   
status_boxr   )
r   r   r   r   r   br   linesr  r  s
             r&   r   "RollingBallsGame._action_view_pipe  s    (.	}}V$ %%2$$)$<@II)FIq&&(I)FI& !!&*?s499~VW A.GALL  ' $] 3w- / 	& 	 ' *Gs   Dc                 &    U R                   S:w  a  gg Nr   zaction-not-playingr   r   r   s     r&   _is_check_scores_enabled)RollingBallsGame._is_check_scores_enabled(      ;;)#'r,   c                 &    U R                   S:w  a  gg r<  r=  r>  s     r&   !_is_check_scores_detailed_enabled2RollingBallsGame._is_check_scores_detailed_enabled-  rA  r,   c                    U R                  U5      nU(       d  g [        U R                  5       S SS9nU Vs/ s H  oUR                   SUR                   3PM     nnUR                  SR                  U5      S-   5        g s  snf )Nc                     U R                   $ Nr1   r   s    r&   rV   7RollingBallsGame._action_check_scores.<locals>.<lambda>8      !''r,   Tkeyreverse: . .)r   sortedr   r~   r1   speakjoin)r   r   r   r   sorted_playersr   partss          r&   _action_check_scores%RollingBallsGame._action_check_scores2  sz    }}V$##%!

 2@@AFF82aggY'@

499U#c)* As   $Bc                     U R                  U5      nU(       d  g [        U R                  5       S SS9nU Vs/ s H  nUR                   SUR                   S3PM!     nnU R                  X5        g s  snf )Nc                     U R                   $ rG  rH  rI  s    r&   rV   @RollingBallsGame._action_check_scores_detailed.<locals>.<lambda>D  rK  r,   TrL  rO  z points)r   rR  r   r~   r1   r7  )r   r   r   r   rU  r   r9  s          r&   _action_check_scores_detailed.RollingBallsGame._action_check_scores_detailed>  s|    }}V$##%!
 $
# vvhb	)# 	 
 	&	
s   &A2c                    SU l         SU l        SU l        U R                  5       nU R	                  U5        U H/  nUnSUl        SUl        SUl        SUl        SUl	        SUl
        M1     U R                  5       nU R                  S5        U R                  SUS9  Sn[        S	5       H1  nU R                  S
[         R"                  " SS5       S3US9  US-  nM3     U R%                  5         g)zCalled when the game starts.r   Tr   FNzgame_pig/mus.oggzrb-pipe-filledr   
   zgame_uno/interceptrD   rz   r  r  r   )r   game_activeroundr   set_turn_playersr1   r2   r3   r4   r5   r6   r   
play_musicr!  r   r   r   r  _start_round)r   active_playersr   r  r   delayr   s          r&   on_startRollingBallsGame.on_startQ  s   
 002n-  A'(DDJ"'D"#D"#D$(D!#$D    nn& 	*+ 	)= rA$V^^Aq%9$:$?!    QJE  	r,   c                 &   U =R                   S-  sl         U R                  U R                  5       5        U R                  SSS9  U R	                  SU R                   S9  U R	                  S[        U R                  5      S9  U R                  5         g	)
zStart a new round.rD   zgame_pig/roundstart.ogg<   r  zgame-round-start)ra  zrb-balls-remainingr   N)ra  rb  r   r  r!  r   rd   _start_turnr   s    r&   rd  RollingBallsGame._start_roundz  sy    

a
 	d55781"=+4::>-S^Dr,   c                    U R                   nU(       d  gUnSUl        S[        U R                  5      s=:  a  U R                  R
                  :  a)  O  O&U R                  U[        U R                  5      5        gU R                  SSS9  U R                  5         UR                  (       a  [        R                  " US5        U R                   H+  nX1:X  a  U R                  USS9  M  U R                  U5        M-     g)	zStart a player's turn.NFr   zgame_3cardpoker/turn.oggF   rk  rD   )position)current_playerr2   r   rd   rc   rN   r  r  announce_turnr   r   
set_targetrb   rebuild_player_menu)r   r   r   r   s       r&   rl  RollingBallsGame._start_turn  s    $$(.	#(	  s499~5 5 55VS^4 	22> ==  + A{((Q(7((+	 r,   c                 .  > [         TU ]  5         U R                  (       d  gU R                  (       aM  U R                  U R
                  :  a2  U R                  (       a  U R                  5         gU R                  5         g[        R                  " U 5        g)zECalled every tick. Handle bot AI, ball reveals, and scheduled sounds.N)
r   on_tickr`  rh   r  rf   re   r%  r*  r   )r   r   s    r&   rw  RollingBallsGame.on_tick  sq     &&((D,B,BB****,  --/$r,   c           	      X   UR                   U R                  R                  :  a  UR                  U R                  :w  ax  U=R                   S-  sl         U R                   Vs/ s H  o"R                  5       PM     snUl        [        S[        U R                  5      5      Ul        U R                  5         / n[        U R                  5       HS  u  pEXAR                  :  a  UR                  U5        M'  UR                  0 UES[        R                  " SS5      0E5        MU     U$ s  snf )zGet the pipe as the bot perceives it, with limited information.

Bots auto-use view pipe charges and remember up to 6 balls.
Beyond their memory, ball values are randomized.
rD   r   r   rE   )r3   rc   rQ   r5   rd   r6  r/  r   r6   r   r  r   r   r  )r   r   r8  	perceivedr  r  s         r&   _get_bot_perceived_pipe(RollingBallsGame._get_bot_perceived_pipe  s     !!DLL$@$@@''4994!!Q&!9=&CAvvx&CF#%(C		N%;F"""$	 +GA)))  &  A!6	 ,  'Ds   "D'c                   ^	 U R                  U5      m	UR                  (       d  UR                  U R                  R                  :  a[  [        U R                  5      S:  aB  [        U	4S j[        [        S[        U R                  5      5      5       5       5      nUS:  a  gU R                  R                  n[        U R                  R                  [        U R                  5      5      nXC:  a  gUnSn[        X4S-   5       HN  n[        U	4S	 j[        U5       5       5      nX:  d$  X:X  d  M-  [        R                  " S
S5      S
:X  d  MJ  UnUnMP     SU 3$ )zBot AI decision making.r   c              3   D   >#    U  H  nTU   S    S::  d  M  Sv   M     g7f)r   rD   Nr+   .0r  perceived_pipes     r&   	<genexpr>-RollingBallsGame.bot_think.<locals>.<genexpr>  s)      !8aN1<Mg<VZ\<\8s    	 r   r   r   NirD   c              3   4   >#    U  H  nTU   S    v   M     g7f)r   Nr+   r  s     r&   r  r    s     RAQA^A.w7AQs   r   r   )r|  r2   r4   rc   rR   r   rd   sumr   r/  rN   rO   r   r  )
r   r   negative_countrN   rO   	best_take
best_value	test_take
cumulativer  s
            @r&   	bot_thinkRollingBallsGame.bot_think  s!   55f= %%%%(D(DDDII!# ! ! QDII!78! N "" <<((t||,,c$))n=	
xA6IRyAQRRJ&(V^^Aq-AQ-F'
%	 7 yk""r,   c                     U R                   (       d  U R                  5         gU R                  [        U R                  5      S-
  :  a  U R                  5         gU R                  SS9  U R                  5         g)zHandle end of a player's turn.NrD   F)announce)rd   _announce_winner
turn_indexr   turn_players_on_round_endadvance_turnrl  r   s    r&   _on_turn_endRollingBallsGame._on_turn_end  sa     yy!!# ??c$"3"34q88 u-r,   c                 h    U R                   (       d  U R                  5         gU R                  5         g)zHandle end of a round.N)rd   r  rd  r   s    r&   r  RollingBallsGame._on_round_end  s!    yy!!#r,   c                 `   U R                  S5        U R                  5       n[        S U 5       SS9nU Vs/ s H  nUR                  U:X  d  M  UPM     nn[	        U5      S:X  a5  US   nUnU R                  S5        U R                  USSUR                  S	9  OzU Vs/ s H  owR                  PM     nnU R                   HO  nU R                  U5      n	U	(       d  M  [        R                  " U	R                  U5      n
U	R                  S
XSS9  MQ     U R                  5         gs  snf s  snf )z(Announce the winner and finish the game.zrb-pipe-emptyc              3   8   #    U  H  oR                   v   M     g 7frG  rH  )r  r   s     r&   r  4RollingBallsGame._announce_winner.<locals>.<genexpr>  s     -nWWns   r   )rG   rD   zgame_rollingballs/wingame.oggz
rb-you-winz	rb-winnerrH  zrb-tietable)rb   r1   bufferN)r!  r   r  r1   r   r  r
  r~   rb   r   r   format_list_andr   speak_lfinish_game)r   re  
best_scorer   winnerswinner	rb_winnerwnamesr   	names_strs              r&   r  !RollingBallsGame._announce_winner  s)   )002 -n-

 $
#ww*$ # 	 
 w<1QZF,2IOO;<%%oo	 &  &--WVVWE-\\}}Q'4 , < <T[[% PILL9W^L_	 " 	3
$ .s   D&D&D+c                 D   [        U R                  5       S SS9n0 nU H  nUnUR                  X#R                  '   M     U(       a  US   OSnUn[	        U R                  5       [        R                  " 5       R                  5       U R                  U R                  5        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                  S	.S
9$ s  snf )zBuild the game result.c                     U R                   $ rG  rH  rI  s    r&   rV   4RollingBallsGame.build_game_result.<locals>.<lambda>6  rK  r,   TrL  r   Nis_virtual_botF)r}   player_namer   r  )winner_namewinner_scorefinal_scoresrounds_played)	game_type	timestampduration_ticksplayer_resultscustom_data)rR  r   r1   r~   r   rp   r   now	isoformatr  r   r   r   getattrra  )r   rU  r  r   r  r  r  s          r&   build_game_result"RollingBallsGame.build_game_result2  s   ##%!
 A'(D#'::L    '5"$(.	mmolln..044 002 3A dd !88#*1.>#F	 3 /5v{{$3<	! ,!%	
 	
s   #?Dresultr   c                     [         R                  " US5      /nUR                  R                  S0 5      n[        UR	                  5       S5       H!  u  nu  pgUR                  U SU SU 35        M#     U$ )zFormat the end screen.zgame-final-scores-headerr  rD   rP  rO  )r   r   r  r  r   r   )r   r  r   r9  r  r  r~   r1   s           r&   format_end_screen"RollingBallsGame.format_end_screenW  sv    !!&*DEF))--nbA ),*<*<*> BA}LLA3bb01 !C r,   jolt_minjolt_maxc                 v    [         R                  " U [        R                  " X5      S9  U R	                  5         g)zEnd the current player's turn.r-  N)r   	jolt_botsr   r  r  )r   r  r  s      r&   r)  RollingBallsGame.end_turna  s'    Dx(JKr,   )rh   re   rf   r`  rd   ra  r   )F)r   N)      )Er7   r8   r9   r:   r;   r   r)   rb   r/   r=   rB   rc   rd   r?   re   rf   r<   rh   r]   classmethodrl   rp   rs   rv   r{   r>   r   r   r   r   r   r   r   r   r	   r   r   r   r   r   r   r   r   r   r   r  r%  r*  r   r   r?  rC  rW  r\  rg  rd  rl  rw  r|  r  r  r  r  r   r  r  r)  r@   __classcell__)r   s   @r&   r_   r_      s    ).d(CGT$%C#(9L#MG MT2D$t*2%*4%@T
@s"$C$      (S ( (      Js J# Jt JPb J) )S )T )!4-49 -3 60-? 0I 0dX	v 	# 	#* 	F sTz F sTz \f \ \ \R6 Rj R	!6 	!j 	!T6 Tc Tc TT6 Tc Tc T(6 (c (d (?& ? ? ?@DB
'! '!3 '!4 '!R! !3 !4 !Fv #* 
 3: 

+6 
+c 
+d 
+'F 's 't '&'R,< $.@ T$Z :!# 2 !#sTz !#F $L#
: #
J
 C DI  S $  r,   r_   ).r;   dataclassesr   r   r   r"   r   pathlibr   baser   r	   r
   registryr   game_utils.action_guard_mixinr   game_utils.actionsr   r   r   game_utils.bot_helperr   game_utils.game_resultr   r   game_utils.optionsr   r   r   r   messages.localizationr   server.core.ui.keybindsr   r   r?   r]   r<   r=   r'   r)   r-   r/   rB   r_   r+   r,   r&   <module>r     s    )     , , $ = ? ? . > ` ` 1 0 15T#tCH~%&- 4c4S>12 *S	 *
    C+ C CL c' c  cr,   