
    Ii:)                        S 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JrJrJr  \" SS9 " 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g)z5Legal move generation and application for Backgammon.    )annotations)	dataclass   )BackgammonGameStateall_checkers_in_home	bar_count
color_signopponent_colorpoint_countpoint_ownerremaining_diceset_barset_off	off_countT)frozenc                  T    \ rS rSr% SrS\S'   S\S'   S\S'   SrS\S	'   SrS\S
'   Srg)BackgammonMove   zA single sub-move (one die).intsourcedestination	die_valueFboolis_hitis_bear_off N)	__name__
__module____qualname____firstlineno____doc____annotations__r   r   __static_attributes__r       <c:\Users\dbart\PlayPalace11\server\games\backgammon\moves.pyr   r      s)    &KNFDKr$   r   c           
        [        U5      n[        U5      n/ n[        X5      nUS:  aa  US:X  a  SU-
  nOUS-
  nU R                  R                  U   n[        U5      n	X-  S::  a"  X-  S:H  n
UR                  [        SUUU
S95        U$ [        X5      n[        S5       GHa  nU R                  R                  U   nX-  S::  a  M'  US:X  a  X-
  nOX-   nUS:X  a_  US:  aY  U(       d  MK  US:X  a  UR                  [        USUSS95        O,[        XU5      (       a  UR                  [        USUSS95        M  US	:X  a`  US
:  aZ  U(       d  M  US:X  a  UR                  [        USUSS95        O,[        XU5      (       a  UR                  [        USUSS95        GM  US:  d  US
:  a  GM  U R                  R                  U   n[        U5      n	X-  S:  a  GM?  X-  S:H  n
UR                  [        UUUU
S95        GMd     U$ )zGenerate all legal moves for a single die value.

Args:
    state: Current game state.
    color: "red" or "white".
    die_value: The die value to use (1-6).

Returns:
    List of legal BackgammonMove objects.
r   red   r   )r   r   r   r   T)r   r   r   r   white   )
r	   r
   r   boardpointsappendr   r   range_is_highest_checker)statecolorr   signoppmoveson_bardest_idxdest_valopp_signr   can_bear_offivals                 r%   generate_legal_movesr=   !   sL    eD

C"$E u$Fz E>I~H 1}H;;%%h/c?!#(A-FLL ('!	  (5L2Ykk  #:? E>}H }H E>hl2~" $&"+$(	 'uQ77LL&#$(*&/(,	 G22~" $&"+$(	 'uQ77LL&#$(*&/(,	 a<8b= ;;%%h/c?"$)$#		
U f Lr$   c                   [        U5      nUS:X  a9  [        US-   S5       H%  nU R                  R                  U   U-  S:  d  M%    g   g[        SU5       H%  nU R                  R                  U   U-  S:  d  M%    g   g)zCheck if point_idx holds the furthest-from-off checker for bearing off.

For red (moving toward index 0): no checkers on indices > point_idx
For white (moving toward index 23): no checkers on indices < point_idx
r'   r      r   F   T)r	   r/   r,   r-   )r1   r2   	point_idxr3   r;   s        r%   r0   r0      s     eD~y1}a(A{{!!!$t+a/ )  r9%A{{!!!$t+a/ & r$   c                   [        U5      n[        U5      nUR                  S:X  a  [        X[	        X5      S-
  5        O+U R
                  R                  UR                  ==   U-  ss'   UR                  (       a  [        X[        X5      S-   5        OUR                  (       aN  [        U5      nU R
                  R                  UR                  ==   U-  ss'   [        X[	        X5      S-   5        U R
                  R                  UR                  ==   U-  ss'   U R                  R                  UR                  UR                  UR                  UR                  UR                  S.5        g)z2Apply a sub-move to the game state. Mutates state.r)   r   )r   r   r   r   r   N)r	   r
   r   r   r   r,   r-   r   r   r   r   r   moves_this_turnr.   r   r1   mover2   r3   r4   r9   s         r%   
apply_moverF      s   eD

C {{bi59:4;;'4/' i59: ;;!#HKKt//0H<0E	% 5 9:4++,4, 
  kk++kk++	
r$   c                   U R                   (       d  gU R                   R                  5       n[        S0 UD6n[        U5      n[	        U5      nUR
                  (       a  [        X[        X5      S-
  5        OU R                  R                  UR                  ==   U-  ss'   UR                  (       aN  [        U5      nU R                  R                  UR                  ==   U-  ss'   [        X[        X5      S-
  5        UR                  S:X  a  [        X[        X5      S-   5        U$ U R                  R                  UR                  ==   U-  ss'   U$ )z8Undo the last sub-move. Returns the undone move or None.Nr   r)   r   )rC   popr   r	   r
   r   r   r   r,   r-   r   r   r   r   r   )r1   r2   	move_dictrE   r3   r4   r9   s          r%   undo_last_moverJ      s     %%))+I&I&DeD

C i59:4++,4,;;!#HKKt//0H<0E	% 5 9: {{bi59: K 	4;;'4/'Kr$   c                   [        U5      S:w  d  US   US   :X  a  gUu  p4[        XU5      n[        XU5      nU(       d	  U(       d  / $ U(       d  U/$ U(       d  U/$ SnU H7  n[        XU5        [        XU5      (       a  Sn[        XU5        U(       d  M7    O   Sn	U H7  n
[        X
U5        [        XU5      (       a  Sn	[        X
U5        U	(       d  M7    O   U(       d  U	(       a  g[	        X45      /$ )zEnforce the "must use both dice" rule.

If both dice can be used, return None (no restriction).
If only one die can be used, return [larger_die] to enforce using the larger.
If neither can be used, return [].
   r   r   NFT)lenr=   _apply_temp
_undo_tempmax)r1   r2   dice_valuesd1d2moves_d1moves_d2can_use_both_d1_firstm1can_use_both_d2_firstm2s              r%   must_use_both_dicerZ      s     ;1A+a. @FB#E"5H#E"5HH	tt "Eu%b11$(!5e$    "Eu%b11$(!5e$     5 K=r$   c                @   [        U5      n[        U5      nUR                  S:X  a  [        X[	        X5      S-
  5        O+U R
                  R                  UR                  ==   U-  ss'   UR                  (       a  [        X[        X5      S-   5        gUR                  (       aN  [        U5      nU R
                  R                  UR                  ==   U-  ss'   [        X[	        X5      S-   5        U R
                  R                  UR                  ==   U-  ss'   g)z@Temporarily apply a move (without recording to moves_this_turn).r)   r   N)r	   r
   r   r   r   r,   r-   r   r   r   r   r   rD   s         r%   rN   rN   )  s    eD

C{{bi59:4;;'4/'i59:;;!#HKKt//0H<0E	% 5 9:4++,4,r$   c                @   [        U5      n[        U5      nUR                  (       a  [        X[	        X5      S-
  5        OU R
                  R                  UR                  ==   U-  ss'   UR                  (       aN  [        U5      nU R
                  R                  UR                  ==   U-  ss'   [        X[        X5      S-
  5        UR                  S:X  a  [        X[        X5      S-   5        gU R
                  R                  UR                  ==   U-  ss'   g)zUndo a temporary move.r   r)   N)r	   r
   r   r   r   r,   r-   r   r   r   r   r   rD   s         r%   rO   rO   =  s    eD

Ci59:4++,4,;;!#HKKt//0H<0E	% 5 9:{{bi59:4;;'4/'r$   c                N    [        U 5       H  n[        XU5      (       d  M    g   g)z5Check if any legal move exists for any remaining die.TF)r   r=   )r1   r2   die_vals      r%   has_any_legal_mover_   Q  s&    !%(g66 ) r$   N)r1   r   r2   strr   r   returnzlist[BackgammonMove])r1   r   r2   r`   rA   r   ra   r   )r1   r   rE   r   r2   r`   ra   None)r1   r   r2   r`   ra   zBackgammonMove | None)r1   r   r2   r`   rQ   z	list[int]ra   zlist[int] | None)r1   r   r2   r`   ra   r   )r!   
__future__r   dataclassesr   r1   r   r   r   r	   r
   r   r   r   r   r   r   r   r=   r0   rF   rJ   rZ   rN   rO   r_   r   r$   r%   <module>re      s    ; " !    $  @@'*@7:@@F$ F:00'*09B00f5(0(r$   