
    Ii?                       S r SSKJr  SSKJr  SSKJr  SSKr\(       a  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  SSKJrJrJrJrJrJrJrJr  \ " S S5      5       rS#S jrS$S jr              S%S jrS&S jr          S'S jr          S(S jr        S)S jr        S)S jr       S$S jr!S*S jr"        S+S jr#              S,S jr$S-S jr%S.S jr&        S/S jr' S0         S1S jjr(        S+S jr)          S2S  jr*        S3S! jr+        S4S" jr,g)5z
Bot AI Logic for Pirates of the Lost Seas.

Bots follow the exact same rules as human players - they use the same action
system and skill mechanics. This module provides intelligent decision-making
to determine which actions to take.
    )annotations)	dataclass)TYPE_CHECKINGN   )PiratesGame)PiratesPlayer)Skill)combat)skills)SWORD_FIGHTERPUSHSKILLED_CAPTAINPORTAL
GEM_SEEKER
BATTLESHIPDOUBLE_DEVASTATIONSKILLS_BY_IDc                  N    \ rS rSr% SrS\S'   SrS\S'   SrS\S	'   SrS\S
'   Sr	g)BotDecision!   z*Represents a bot's decision for this turn.str	action_idN'PiratesPlayer | None'target
str | None
skill_name	direction )
__name__
__module____qualname____firstlineno____doc____annotations__r   r   r   __static_attributes__r       7c:\Users\dbart\PlayPalace11\server\games\pirates\bot.pyr   r   !   s)    4N%)F")!J
! Iz r&   r   c                L    [        X5      nU(       a  X l        UR                  $ g)a
  
Determine what action a bot should take.

Bots follow the same rules as humans - they select from available actions
based on game state analysis.

Args:
    game: The game instance
    player: The bot player

Returns:
    Action ID to execute, or None if no action
N)_analyze_and_decide_bot_decisionr   )gameplayerdecisions      r'   	bot_thinkr.   +   s&     #40H%!!!r&   c                   [         R                  " X5      n[        X5      nUS:w  a  [        UR                  U-
  5      OSn[        XU5      n[        R                  " U5      =(       d    [        R                  " U5      n[        U UUUUU5      nU(       a  U$ [        XX45      nU(       a  U$ [        XU5      nU(       a  U$ [        XU5      nU(       a  U$ [        X5      nU(       a  U$ [        X5      $ )a  
Analyze game state and decide on the best action.

Decision priority:
1. If we have attack buff skills available and targets nearby, consider activating them
2. If targets have lots of gems and we can attack, prioritize attacking
3. If gems are nearby, move toward them
4. If no gems nearby but player is near one, consider portal
5. Default to moving toward nearest gem or random movement
  )r
   get_targets_in_range_find_closest_gemabsposition_find_valuable_targetr   	is_activer   _maybe_attack_target_maybe_move_toward_close_gem_maybe_use_portal_maybe_use_gem_seeker_maybe_use_double_devastation_decide_movement)r+   r,   targetsclosest_gemgem_distancevaluable_targethas_attack_buffr-   s           r'   r)   r)   A   s     ))$7G#D1K9D9J3v45PSL+D'BO#--f5Z9R9RSY9ZO#H +D+TH |<H$T<@H,T:HD))r&   c                   U(       a  U(       d  g [        U5      n[        U UUU5      nU(       a  U$ [        U UUUUU5      n[        R                  " 5       U:  an  [        R
                  " U5      (       aI  [        R                  " X5      u  pU	(       a*  [        U5      S:  d  UR                  S:  a  [        SSUS9$ [        SUS9$ g )N      	use_skill
battleship)r   r   r   
cannonball)r   r   )
_target_has_defense_maybe_activate_attack_buff_calculate_attack_chancerandomr   is_unlockedcan_performlenscorer   )r+   r,   r>   rA   rB   r@   target_has_defenser-   attack_chancecan_use_s              r'   r8   r8   p   s     ',_=*	H ,M }}&!!&))#//=JGCLA-1F1F!1K")+*  \/JJr&   c                h    [         R                  " U 5      =(       d    [        R                  " U 5      $ N)r   r7   r   )r   s    r'   rI   rI      s!    >>&!F_%>%>v%FFr&   c                   U(       d  U(       d  g [         R                  " U5      (       aB  [         R                  " X5      u  pEU(       a#  [        R                  " 5       S:  a
  [	        SSS9$ [
        R                  " U5      (       aB  [
        R                  " X5      u  pEU(       a#  [        R                  " 5       S:  a
  [	        SSS9$ g )N皙?rF   sword_fighterr   r   skilled_captain)r   rM   rN   rL   r   r   )r+   r,   rB   rQ   rS   rT   s         r'   rJ   rJ      s     0  (("..t<
v}},QQ""6**$00>
v}},ARSSr&   c                4    US:w  a  US::  a  [        XU5      $ g )Nr0      )_decide_movement_toward)r+   r,   r?   r@   s       r'   r9   r9      s#     b\Q.&t[AAr&   c                    US::  d  [         R                  " U5      (       d  g [         R                  " X5      u  p4U(       d  g [        X5      (       a#  [        R                  " 5       S:  a
  [        SSS9$ g )N
   333333?rF   portalrZ   )r   rM   rN   _is_other_player_near_gemrL   r   r+   r,   r@   rS   rT   s        r'   r:   r:      s_    
 r!3!3F!;!;##D1JG ..6==?S3H[XFFr&   c                    US::  d  [         R                  " U5      (       d  g [         R                  " X5      u  p4U(       a#  [        R                  " 5       S:  a
  [	        SSS9$ g )N   333333?rF   
gem_seekerrZ   )r   rM   rN   rL   r   rd   s        r'   r;   r;      sQ    
 r!7!7!?!?''5JG6==?S([\JJr&   c                F   [         R                  " U5      (       d  g [         R                  " X5      u  p#U(       d  g [        R                  " XSS9n[        R                  " XSS9n[        U5      [        U5      :  a#  [        R                  " 5       S:  a
  [        SSS9$ g )Nr`   )	max_ranger]         ?rF   double_devastationrZ   )r   rM   rN   r
   r2   rO   rL   r   )r+   r,   rS   rT   extended_targetscurrent_targetss         r'   r<   r<      s     ))&11#//=JG2242N11$!LO
s?33#8M[=QRRr&   c                    SnSnU R                   R                  5        H0  u  pEUS:w  d  M  [        UR                  U-
  5      nXc:  d  M,  UnUnM2     U$ )z1Find the position of the closest uncollected gem.r0   r1   )gem_positionsitemsr4   r5   )r+   r,   closest_posclosest_distanceposgem_typedistances          r'   r3   r3      s[    K++113r>6??S01H*#+ ! 4 r&   c                   U(       d  g/ nU HT  nSnU[        UR                  5      S-  -  nXTR                  S-  -  nXTR                  S-  -  nUR	                  XE45        MV     UR                  S SS9  U(       a  US   S	   S:  a  US   S   $ U(       a/  [        R                  " 5       S
:  a  [        R                  " U5      $ g)z
Find the most valuable target to attack.

Considers:
- Number of gems the target has
- Target's score
- Whether target is a threat (high level, high score)
Nr   rE   rD   r`   c                    U S   $ Nr   r   xs    r'   <lambda>'_find_valuable_target.<locals>.<lambda>  s    adr&   Tkeyreverser   rk   )rO   gemsrP   levelappendsortrL   choice)r+   r,   r>   scored_targetsr   rP   s         r'   r6   r6      s      N 	V[[!A%% 	!! 	##vo.  ND9 .+A.2a ## 6==?S(}}W%%r&   c                L   SnUR                  5       (       a*  US-  nU[        S[        UR                  5      S-  5      -  nU(       a  US-  nU(       a  US-  nUS:  a  US-  nOUS:  a  US-  nUR                  UR                  :  a  US-  n[        S[        SU5      5      $ )	a  
Calculate the probability that the bot should attack.

Factors:
- Target has gems: higher chance
- We have attack buff: higher chance
- Target has defense buff: lower chance
- Gems are far away: higher chance (nothing better to do)
- We need gems: higher chance
rg   皙?皙?g333333?r`   r]   g?g?)has_gemsminrO   r   rP   max)r+   r,   r   rB   rQ   r@   base_chances          r'   rK   rK   )  s    $ K ss3FKK 04 788 t s bt		t ||fll"s sC[)**r&   c                    U R                  5        Hi  nUR                  UR                  :X  a  M  U R                  R                  5        H,  u  p4US:w  d  M  [	        UR
                  U-
  5      S::  d  M+      g   Mk     g)z@Check if another player is within 5 tiles of an uncollected gem.r0   r]   TF)get_active_playersidrp   rq   r4   r5   )r+   r,   otherrt   ru   s        r'   rc   rc   Y  sh    ((*88vyy !//557MC2~u~~+,1 8	 + r&   c                    [        X5      nUS:w  a  [        XU5      $ [        R                  " SS/5      n[	        XU5      $ )zDecide on a movement action.r0   leftright)r3   r^   rL   r   _get_best_move_action)r+   r,   r?   r   s       r'   r=   r=   g  sC    #D1Kb&t[AA vw/0I y99r&   c                    UR                   U:  a  SnO7UR                   U:  a  SnO$[        R                  " SS/5      n[        XU5      $ [        XX25      $ )z)Decide movement toward a target position.r   r   )r5   rL   r   r   )r+   r,   
target_posr   s       r'   r^   r^   s  sU     #		:	%	 MM67"34	$T9== yEEr&   c                    UR                   S:  a  SnOUR                   S:  a  SnOSnUb#  [        UR                  U-
  5      n[        XE5      nUS:  a  SU 3nOUS:X  a  SU 3nOSU 3n[	        XbS	9$ )
z;Get the best available move action for the given direction.   rE   rf   rD   r   move_3_move_2_move_)r   r   )r   r4   r5   r   r   )r+   r,   r   r   	max_tilesrv   actions          r'   r   r     s    
 ||s					 v34	,	 A~9+&	a9+&$==r&   c                    U(       d  g[        U SS5      nU(       a-  UR                  (       a  UR                  U;   a  UR                  $ [        XU5      =(       d    [        R                  " U5      $ )zu
Select a target for the bot to attack.

Uses the pre-computed decision if available, otherwise picks intelligently.
Nr*   )getattrr   r6   rL   r   )r+   r,   r>   r-   s       r'   bot_select_targetr     sU      t_d3HHOO7(B !w7Q6==;QQr&   c                   U(       a  UR                  5       (       d  [        R                  " SS/5      $ [        R                  " U5      n[        R
                  " U5      nXE-
  nUS:  a  SnOUS:  a  SnOUS:  a  SnOS	nU[        S	[        UR                  5      S
-  5      -  n[        R                  " 5       U:  a  g[        R                  " SS/5      $ )z
Select a boarding action for the bot.

Considers:
- Whether stealing is possible and beneficial
- Our attack bonuses vs their defense bonuses
r   r   rD   rX   r   ra   g?r   r   steal)	r   rL   r   r   get_attack_bonusget_defense_bonusr   rO   r   )r+   r,   defender	can_stealattack_bonusdefense_bonus	advantagesteal_chances           r'   bot_select_boarding_actionr     s     H--//}}fg.// **62L,,X6M ,IA~	a	b CS/$677L}}%==&'*++r&   c                   U(       d  g/ nU H  u  pESnUS-  S-   nUS-   S-  n[        XxS-   5       H*  n	U R                  R                  U	S5      S:w  d  M%  US-  nM,     U R                  5        Hr  n
U
R                  UR                  :X  a  M  XzR
                  s=::  a  U::  d  M7  O  M;  U
R                  5       (       a  U[        U
R                  5      S-  -  nMm  US-  nMt     UR                  XF45        M     UR                  S S	S
9  U(       aJ  [        R                  " 5       S:  a  US   S   $ [        R                  " U Vs/ s H  oS   PM	     sn5      $ US   S   $ s  snf )zt
Select an ocean for the bot to portal to.

Prefers oceans where:
- A gem is nearby
- Players with gems are located
Nr   r`   r   r0   rE   rD   c                    U S   $ ry   r   rz   s    r'   r|   )bot_select_portal_ocean.<locals>.<lambda>  s    QqTr&   Tr~   rX   )rangerp   getr   r   r5   r   rO   r   r   r   rL   r   )r+   r,   ocean_optionsscored_oceans	ocean_num
ocean_namerP   ocean_start	ocean_endrt   r   os               r'   bot_select_portal_oceanr     s]    M!.	"nq(]b(	 !m4C!!%%c2."4
 5
 ,,.Exx699$nn9	99>>##S_q00EQJE / 	i/0) "/. >48 ==?S  #A&&==!>1A$!>??A "?s   	E&c                    [        U SS5      nU(       aP  UR                  (       a?  [        R                  " UR                  5      nU(       a  UR	                  U5      nXR;   a  U$ g)zS
Select a skill from the skill menu.

Uses the pre-computed decision if available.
r*   NBack)r   r   r   r   get_menu_label)r+   r,   skill_optionsr-   skilllabels         r'   bot_select_skill_choicer     sV     t_d3HH''  !4!45((0E% r&   )r+   'PiratesGame'r,   'PiratesPlayer'returnr   )r+   r   r,   r   r   BotDecision | None)r+   r   r,   r   r>   list['PiratesPlayer']rA   r   rB   boolr@   intr   r   )r   r   r   r   )
r+   r   r,   r   rB   r   rQ   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   )r+   r   r,   r   r>   r   r   r   )r+   r   r,   r   r   r   rB   r   rQ   r   r@   r   r   float)r+   r   r,   r   r   r   )r+   r   r,   r   r   r   )r+   r   r,   r   r   r   r   r   rV   )
r+   r   r,   r   r   r   r   
int | Noner   r   )
r+   r   r,   r   r   r   r   r   r   r   )r+   r   r,   r   r   zlist[tuple[int, str]]r   r   )r+   r   r,   r   r   z	list[str]r   r   )-r#   
__future__r   dataclassesr   typingr   rL   r+   r   r,   r   r   r	    r
   r   r   r   r   r   r   r   r   r   r.   r)   r8   rI   rJ   r9   r:   r;   r<   r3   r6   rK   rc   r=   r^   r   r   r   r   r   r   r&   r'   <module>r      s   # !   !%  	 	 	 ! ! !,,*^*
** #* ,	*
 * * *ZG
  	
 ,
  	
 
  	



 
 	

  )
)!0);P))X-+
-+-+ -+ 	-+
 -+ -+ -+`	:F
F!0F>AFF" \`>
>!0>=@>NX>>BR
R!0R;PRR(#,
#,!0#,<K#,X\#,#,L.
.!0.AV..b
!0AJr&   