
    hA                       S r SSKJr  SSKJr  SSKJr  SSKJr  SSK	r
SSKrSSKJrJr  SSKJrJr  SS	KJr  \(       a  SS
KJr   SSKrSSKJr  SSKJr   SSKr\R<                  " S5        SSKJ r!   " S S\#5      r$ " S S5      r%        SS jr&        S                 SS jjr' " S S5      r(g! \ a!  r\R8                  R'                  S5      \eSrCff = f! \ a    \RD                  " S5        Su  rr! Nf = f)z(Utilities of visualising an environment.    )annotations)deque)Callable)TYPE_CHECKINGN)Envlogger)ActTypeObsType)DependencyNotInstalled)Axes)Surface)EventzGpygame is not installed, run `pip install "gymnasium[classic_control]"`TkAggAmatplotlib is not installed, run `pip install "gymnasium[other]"`NNc                      \ rS rSrSrSrg)MissingKeysToAction(   zORaised when the environment does not have a default ``keys_to_action`` mapping. N)__name__
__module____qualname____firstlineno____doc____static_attributes__r       N/home/james-whalen/.local/lib/python3.13/site-packages/gymnasium/utils/play.pyr   r   (   s    Yr   r   c                  b    \ rS rSrSr  S	     S
S jjr S   SS jjrSSS jjrSS jrSr	g)PlayableGame,   zOWraps an environment allowing keyboard inputs to interact with the environment.Nc                P   UR                   S;  a  [        SUR                    S35      eXl        U R                  U5      U l        U R                  U5      U l        [        R                  R                  U R                  [        R                  5      U l        / U l        SU l        g)a  Wraps an environment with a dictionary of keyboard buttons to action and if to zoom in on the environment.

Args:
    env: The environment to play
    keys_to_action: The dictionary of keyboard tuples and action value
    zoom: If to zoom in on the environment render
>   	rgb_arrayrgb_array_listzsPlayableGame wrapper works only with rgb_array and rgb_array_list render modes, but your environment render_mode = .TN)render_mode
ValueErrorenv_get_relevant_keysrelevant_keys_get_video_size
video_sizepygamedisplayset_mode	RESIZABLEscreenpressed_keysrunning)selfr'   keys_to_actionzooms       r   __init__PlayableGame.__init__/   s     ??"AA669oo5FaI 
 !44^D ..t4nn--doov?O?OPr   c                   Uc  U R                   R                  S5      (       a!  U R                   R                  S5      " 5       nOEU R                   R                  c   e[	        U R                   R                  R
                   S35      e[        U[        5      (       d   e[        [        S UR                  5        5       / 5      5      nU$ )Nget_keys_to_actionzk does not have explicit key to action mapping, please specify one manually, `play(env, keys_to_action=...)`c              3  8   #    U  H  n[        U5      v   M     g 7fN)list.0ks     r   	<genexpr>2PlayableGame._get_relevant_keys.<locals>.<genexpr>X   s      H2GQa2Gs   )r'   has_wrapper_attrget_wrapper_attrspecr   id
isinstancedictsetsumkeys)r3   r4   r)   s      r   r(   PlayableGame._get_relevant_keysK   s     !xx(()=>>!%!:!:;O!P!Rxx}}000)xx}}''( )S S  .$////C H.2E2E2G H"MNr   c                <   U R                   R                  5       n[        U[        5      (       a  US   nUb  [        U[        R
                  5      (       d   eUR                  S   UR                  S   4nUb"  [        US   U-  5      [        US   U-  5      4nU$ )N   r   )r'   renderrF   r<   npndarrayshapeint)r3   r5   renderedr+   s       r   r*   PlayableGame._get_video_size[   s    88??$h%%|H#
8RZZ(H(HHHnnQ'):;
jmd23SA9M5NOJr   c                *   UR                   [        R                  :X  ag  UR                  U R                  ;   a&  U R
                  R                  UR                  5        gUR                  [        R                  :X  a  SU l        ggUR                   [        R                  :X  aA  UR                  U R                  ;   a&  U R
                  R                  UR                  5        ggUR                   [        R                  :X  a  SU l        gUR                   [        R                  :X  ak  UR                  U R                  S   -  nUR                  U R                  S   -  n[!        X25      nX@R                  S   -  X@R                  S   -  4U l        gg)zProcesses a PyGame event.

In particular, this function is used to keep track of which buttons are currently pressed
and to exit the :func:`play` function when the PyGame window is closed.

Args:
    event: The event to process
Fr   rN   N)typer,   KEYDOWNkeyr)   r1   appendK_ESCAPEr2   KEYUPremoveQUITWINDOWRESIZEDxr+   ymin)r3   eventscale_widthscale_heightscales        r   process_eventPlayableGame.process_eventg   s$    ::'yyD...!!((3foo-$ .ZZ6<<'yyD...!!((3 /ZZ6;;& DLZZ6///''DOOA$66K 77T__Q%77L2E$q'995??STCU;UVDO 0r   )r'   r1   r)   r2   r0   r+   r   )r'   r   r4   z!dict[tuple[int, ...], int] | Noner5   float | Noner;   )r4   zdict[tuple[int], int] | NonereturnrH   )r5   ri   rj   tuple[int, int])rc   r   )
r   r   r   r   r   r6   r(   r*   rg   r   r   r   r   r   r   ,   sU    Y
 =A!	 : 	: >B:	 
Wr   r   c                   [        U[        R                  5      (       a  UR                  [        R                  :X  d   e[
        R                  R                  U(       a  UR                  SS5      OU5      n[
        R                  R                  XB5      nU R                  5       nUS   US   -
  S-  nUS   US   -
  S-  nU R                  S5        U R                  XFU45        g)zDisplays a numpy array on screen.

Args:
    screen: The screen to show the array on
    arr: The array to show
    video_size: The video size of the screen
    transpose: If to transpose the array on the screen
r   rN      )r   r   r   N)rF   rP   rQ   dtypeuint8r,   	surfarraymake_surfaceswapaxes	transformrf   get_sizefillblit)r0   arrr+   	transposepyg_imgsurface_sizewidth_offsetheight_offsets           r   display_arrr}      s     c2::&&399+@@@++)CLLA,>QTUG$$W9G??$L Ojm3q8L!!_z!}49M
KK	
KK67r   c	           	        U R                  US9  Uc^  U R                  S5      (       a  U R                  S5      " 5       nO1U R                  c   e[	        U R                  R
                   S35      eUc   e[        U[        5      (       d   eUR                  5        Hs  u  p[        U	[        5      (       a+  [        U	5      S:  d   e[        S U	 5       5      (       d   eO[        U	[        [        45      (       d   eXR                  ;   a  Ms   e   0 nUR                  5        H<  u  p[        U[        5      (       a  U4n[        [        S U 5       5      5      nXU'   M>     [!        XU5      nUc  U R"                  R%                  SS	5      nS
u  nn[&        R(                  R+                  5       nUR,                  (       Ga  U(       a  SnU R                  US9nOUSL d  [        UR.                  5      S:  ac  UR%                  [        [        UR.                  5      5      U5      n
UnU R1                  U
5      u  nnnnnU=(       d    UnUb  U" UUU
UUUU5        Ubm  U R3                  5       n[        U[4        5      (       a  US   nUb  [        U[6        R8                  5      (       d   e[;        UR<                  UXR>                  S9  [&        R@                  R%                  5        H  nURC                  U5        M     [&        RD                  RG                  5         URI                  U5        UR,                  (       a  GM  [&        RJ                  " 5         g)a  Allows the user to play the environment using a keyboard.

If playing in a turn-based environment, set wait_on_player to True.

Args:
    env: Environment to use for playing.
    transpose: If this is ``True``, the output of observation is transposed. Defaults to ``True``.
    fps: Maximum number of steps of the environment executed every second. If ``None`` (the default),
        ``env.metadata["render_fps""]`` (or 30, if the environment does not specify "render_fps") is used.
    zoom: Zoom the observation in, ``zoom`` amount, should be positive float
    callback: If a callback is provided, it will be executed after every step. It takes the following input:

        * obs_t: observation before performing action
        * obs_tp1: observation after performing action
        * action: action that was executed
        * rew: reward that was received
        * terminated: whether the environment is terminated or not
        * truncated: whether the environment is truncated or not
        * info: debug info
    keys_to_action:  Mapping from keys pressed to action performed.
        Different formats are supported: Key combinations can either be expressed as a tuple of unicode code
        points of the keys, as a tuple of characters, or as a string where each character of the string represents
        one key.
        For example if pressing 'w' and space at the same time is supposed
        to trigger action number 2 then ``key_to_action`` dict could look like this:

            >>> key_to_action = {
            ...    # ...
            ...    (ord('w'), ord(' ')): 2
            ...    # ...
            ... }

        or like this:

            >>> key_to_action = {
            ...    # ...
            ...    ("w", " "): 2
            ...    # ...
            ... }

        or like this:

            >>> key_to_action = {
            ...    # ...
            ...    "w ": 2
            ...    # ...
            ... }

        If ``None``, default ``key_to_action`` mapping for that environment is used, if provided.
    seed: Random seed used when resetting the environment. If None, no seed is used.
    noop: The action used when no key input has been entered, or the entered key combination is unknown.
    wait_on_player: Play should wait for a user action

Example:
    >>> import gymnasium as gym
    >>> import numpy as np
    >>> from gymnasium.utils.play import play
    >>> play(gym.make("CarRacing-v3", render_mode="rgb_array"),  # doctest: +SKIP
    ...     keys_to_action={
    ...         "w": np.array([0, 0.7, 0], dtype=np.float32),
    ...         "a": np.array([-1, 0, 0], dtype=np.float32),
    ...         "s": np.array([0, 0, 1], dtype=np.float32),
    ...         "d": np.array([1, 0, 0], dtype=np.float32),
    ...         "wa": np.array([-1, 0.7, 0], dtype=np.float32),
    ...         "dw": np.array([1, 0.7, 0], dtype=np.float32),
    ...         "ds": np.array([1, 0, 1], dtype=np.float32),
    ...         "as": np.array([-1, 0, 1], dtype=np.float32),
    ...     },
    ...     noop=np.array([0, 0, 0], dtype=np.float32)
    ... )

    Above code works also if the environment is wrapped, so it's particularly useful in
    verifying that the frame-level preprocessing does not render the game
    unplayable.

    If you wish to plot real time statistics as you play, you can use
    :class:`PlayPlot`. Here's a sample code for plotting the reward
    for last 150 steps.

    >>> from gymnasium.utils.play import PlayPlot, play
    >>> def callback(obs_t, obs_tp1, action, rew, terminated, truncated, info):
    ...        return [rew,]
    >>> plotter = PlayPlot(callback, 150, ["reward"])             # doctest: +SKIP
    >>> play(gym.make("CartPole-v1"), callback=plotter.callback)  # doctest: +SKIP
)seedNr9   zJ does not have explicit key to action mapping, please specify one manuallyr   c              3  N   #    U  H  n[        U[        [        45      v   M     g 7fr;   )rF   strrS   r=   s     r   r@   play.<locals>.<genexpr>  s     >#Qz!c3Z00#s   #%c              3  f   #    U  H'  n[        U[        5      (       a  [        U5      OUv   M)     g 7fr;   )rF   r   ord)r>   rY   s     r   r@   r     s%     Xz#s333s8<s   /1
render_fps   )TNFrM   )rx   r+   )&resetrB   rC   rD   r   rE   rF   rG   itemstuplelenallr   rS   action_spacesortedr   metadatagetr,   timeClockr2   r1   steprO   r<   rP   rQ   r}   r0   r+   rc   rg   r-   fliptickquit)r'   rx   fpsr5   callbackr4   r   noopwait_on_playerrY   actionkey_code_to_actionkey_combinationkey_codegamedoneobsclockprev_obsrew
terminated	truncatedinforT   rc   s                            r   playr      s   @ II4I 455 112FGIN88'''%88;;-  . . 
 %%% nd++++%++-c5!!s8a<<>#>>>>>cC:....))))) . #1#7#7#9os++.0OXXX
 (.8$ $: 6D
{ll|R0ID#KKE
,,,D)))&Cu$D,=,=(>(B'++E&9J9J2K,LdSFH47HHV4D1Cj)T*D#3ZDQ?zz|H(D))#B<'Jx,L,LLLX
 \\%%'Eu% ( 	

33 ,,,4 KKMr   c                  T    \ rS rSrSr      SS jr              SS jrSrg)	PlayPloti?  a  Provides a callback to create live plots of arbitrary metrics when using :func:`play`.

This class is instantiated with a function that accepts information about a single environment transition:
    - obs_t: observation before performing action
    - obs_tp1: observation after performing action
    - action: action that was executed
    - rew: reward that was received
    - terminated: whether the environment is terminated or not
    - truncated: whether the environment is truncated or not
    - info: debug info

It should return a list of metrics that are computed from this data.
For instance, the function may look like this::

    >>> def compute_metrics(obs_t, obs_tp, action, reward, terminated, truncated, info):
    ...     return [reward, info["cumulative_reward"], np.linalg.norm(action)]

:class:`PlayPlot` provides the method :meth:`callback` which will pass its arguments along to that function
and uses the returned values to update live plots of the metrics.

Typically, this :meth:`callback` will be used in conjunction with :func:`play` to see how the metrics evolve as you play::

    >>> plotter = PlayPlot(compute_metrics, horizon_timesteps=200,                               # doctest: +SKIP
    ...                    plot_names=["Immediate Rew.", "Cumulative Rew.", "Action Magnitude"])
    >>> play(your_env, callback=plotter.callback)                                                # doctest: +SKIP
c                    Xl         X l        X0l        [        c  [	        S5      e[        U R                  5      n[        R                  " U5      u  U l        U l        US:X  a  U R                  /U l        [        U R                  U5       H  u  pVUR                  U5        M     SU l        [        U5       Vs/ s H  nSPM     snU l        [        U5       Vs/ s H  n[        US9PM     snU l        gs  snf s  snf )a  Constructor of :class:`PlayPlot`.

The function ``callback`` that is passed to this constructor should return
a list of metrics that is of length ``len(plot_names)``.

Args:
    callback: Function that computes metrics from environment transitions
    horizon_timesteps: The time horizon used for the live plots
    plot_names: List of plot titles

Raises:
    DependencyNotInstalled: If matplotlib is not installed
Nr   rN   r   )maxlen)data_callbackhorizon_timesteps
plot_namespltr   r   subplotsfigaxzip	set_titletrangecur_plotr   data)r3   r   r   r   	num_plotsaxisname_s           r   r6   PlayPlot.__init__[  s      &!2$;(S  (	LL3$'>wwiDGdggz2JDNN4  3:?	:J+K:JQD:J+K>CI>NO>NU"34>NO	 ,LOs   9C6C;c           	        U R                  XX4XVU5      n[        XR                  5       H  u  pU
R                  U	5        M     U =R                  S-  sl        [        SU R                  U R                  -
  5      U R                  p[        U R                  5       H  u  pUb  UR                  5         U R                  U   R                  [        X5      [        U R                  U   5      SS9U R                  U'   U R                  U   R                  X5        M     [        c  [!        S5      e[        R"                  " S5        g)al  The callback that calls the provided data callback and adds the data to the plots.

Args:
    obs_t: The observation at time step t
    obs_tp1: The observation at time step t+1
    action: The action
    rew: The reward
    terminated: If the environment is terminated
    truncated: If the environment is truncated
    info: The information from the environment
rN   r   Nblue)cr   gư>)r   r   r   rZ   r   maxr   	enumerater   r]   r   scatterr   r<   set_xlimr   r   pause)r3   obs_tobs_tp1r   r   r   r   r   pointspointdata_seriesxminxmaxiplots                  r   r   PlayPlot.callback~  s   * ##F
 #&fii"8Eu% #9!DFFT%;%;;<dffd /GA#wwqz11d!4		!#5  2  DMM! GGAJ+ 0 ;(S  			(r   )r   r   r   r   r   r   r   r   N)r   r   r   rS   r   z	list[str])r   r
   r   r
   r   r	   r   floatr   boolr   r   r   rG   )r   r   r   r   r   r6   r   r   r   r   r   r   r   ?  sr    6!P !P58!PFO!PF** * 	*
 * * * *r   r   )r0   r   rw   z
np.ndarrayr+   rk   rx   r   )TNNNNNr   F)r'   r   rx   zbool | Noner   
int | Noner5   ri   r   zCallable | Noner4   z7dict[tuple[str | int, ...] | str | int, ActType] | Noner   r   r   r	   r   r   ))r   
__future__r   collectionsr   collections.abcr   typingr   numpyrP   	gymnasiumgymr   r   gymnasium.corer	   r
   gymnasium.errorr   matplotlib.axesr   r,   r   pygame.eventr   ImportErroreerror
matplotlibusematplotlib.pyplotpyplotr   warn	Exceptionr   r   r}   r   r   r   r   r   <module>r      su   . "  $     ! + 2 $"!NN7#Z) ZSW SWl88$82A8NR80 " $NR d	dd 
d 	d
 d Ld d d dNi iM	  
))
*
*Q  !
KKST OJ!s*   C C+ C(C##C(+D
D