
    h`t              	         S r SSKJr  SSKrSSKrSSKJr  SSKJr  SSK	J
r
JrJr  SSKrSSKrSSKJrJr  SSKJrJrJr  SS	KJrJr  / S
Qr " S S\R6                  \\\\4   \\\\4   \R8                  R:                  5      r " S S\R6                  \\\\4   \\\\4   \R8                  R:                  5      r " S S\R6                  \\\\4   \R8                  R:                  5      r  " S S\R6                  \\\\4   \R8                  R:                  5      r! " S S\R6                  \\\\4   \R8                  R:                  5      r"g)a  A collections of rendering-based wrappers.

* ``RenderCollection`` - Collects rendered frames into a list
* ``RecordVideo`` - Records a video of the environments
* ``HumanRendering`` - Provides human rendering of environments with ``"rgb_array"``
* ``AddWhiteNoise`` - Randomly replaces pixels with white noise
* ``ObstructView`` - Randomly places patches of white noise to obstruct the pixel rendering
    )annotationsN)Callable)deepcopy)AnyGenericSupportsFloat)errorlogger)ActTypeObsTypeRenderFrame)DependencyNotInstalledInvalidProbability)RenderCollectionRecordVideoHumanRenderingAddWhiteNoiseObstructViewc                     ^  \ rS rSrSr  S     SS jjr\S 5       r    SU 4S jjrSSS.     SU 4S jjjr	SS	 jr
S
rU =r$ )r   #   a  Collect rendered frames of an environment such ``render`` returns a ``list[RenderedFrame]``.

No vector version of the wrapper exists.

Example - Return the list of frames for the number of steps ``render`` wasn't called.
    >>> import gymnasium as gym
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> env = RenderCollection(env)
    >>> _ = env.reset(seed=123)
    >>> for _ in range(5):
    ...     _ = env.step(env.action_space.sample())
    ...
    >>> frames = env.render()
    >>> len(frames)
    6

    >>> frames = env.render()
    >>> len(frames)
    0

Example - Return the list of frames for the number of steps the episode was running.
    >>> import gymnasium as gym
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> env = RenderCollection(env, pop_frames=False)
    >>> _ = env.reset(seed=123)
    >>> for _ in range(5):
    ...     _ = env.step(env.action_space.sample())
    ...
    >>> frames = env.render()
    >>> len(frames)
    6

    >>> frames = env.render()
    >>> len(frames)
    6

Example - Collect all frames for all episodes, without clearing them when render is called
    >>> import gymnasium as gym
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> env = RenderCollection(env, pop_frames=False, reset_clean=False)
    >>> _ = env.reset(seed=123)
    >>> for _ in range(5):
    ...     _ = env.step(env.action_space.sample())
    ...
    >>> _ = env.reset(seed=123)
    >>> for _ in range(5):
    ...     _ = env.step(env.action_space.sample())
    ...
    >>> frames = env.render()
    >>> len(frames)
    12

    >>> frames = env.render()
    >>> len(frames)
    12

Change logs:
 * v0.26.2 - Initially added
c                "   [         R                  R                  R                  XUS9  [         R                  R                  X5        UR
                  c   eUR
                  R                  S5      (       a   e/ U l        X l        X0l	        [        U R                  R                  5      U l        U R                  R
                   S3U R                  S   ;  a6  U R                  S   R                  U R                  R
                   S35        gg)aV  Initialize a :class:`RenderCollection` instance.

Args:
    env: The environment that is being wrapped
    pop_frames (bool): If true, clear the collection frames after ``meth:render`` is called. Default value is ``True``.
    reset_clean (bool): If true, clear the collection frames when ``meth:reset`` is called. Default value is ``True``.
)
pop_framesreset_cleanN_listrender_modes)gymutilsRecordConstructorArgs__init__Wrapperrender_modeendswith
frame_listr   r   r   envmetadataappend)selfr$   r   r   s       V/home/james-whalen/.local/lib/python3.13/site-packages/gymnasium/wrappers/rendering.pyr   RenderCollection.__init__d   s     			''00[ 	1 	
 	T'***??++G4444-/$& !2!23hh""#5)~1NNMM.)00DHH4H4H3I1OP O    c                4    U R                   R                   S3$ )z(Returns the collection render_mode name.r   )r$   r!   r'   s    r(   r!   RenderCollection.render_mode   s     ((&&'u--r*   c                t   > [         TU ]  U5      nU R                  R                  [         TU ]  5       5        U$ )z;Perform a step in the base environment and collect a frame.)superstepr#   r&   render)r'   actionoutput	__class__s      r(   r0   RenderCollection.step   s1     f%uw~/0r*   Nseedoptionsc                  > [         TU ]  XS9nU R                  (       a  / U l        U R                  R	                  [         TU ]  5       5        U$ )zQReset the base environment, eventually clear the frame_list, and collect a frame.r6   )r/   resetr   r#   r&   r1   )r'   r7   r8   r3   r4   s       r(   r:   RenderCollection.reset   sC     D: DOuw~/0r*   c                N    U R                   nU R                  (       a  / U l         U$ )zFReturns the collection of frames and, if pop_frames = True, clears it.)r#   r   )r'   framess     r(   r1   RenderCollection.render   s    ?? DOr*   )r#   r%   r   r   )TT)r$   gym.Env[ObsType, ActType]r   boolr   r@   r2   r   returnz9tuple[ObsType, SupportsFloat, bool, bool, dict[str, Any]]r7   
int | Noner8   zdict[str, Any] | NonerB   ztuple[ObsType, dict[str, Any]])rB   zlist[RenderFrame])__name__
__module____qualname____firstlineno____doc__r   propertyr!   r0   r:   r1   __static_attributes____classcell__r4   s   @r(   r   r   #   s    
:~   	Q&Q Q 	Q: . .	B %)4
!
3H
	'
 
 r*   r   c                     ^  \ rS rSrSrSSSSSSS 4                 SS jjrS	 rSSS
.     SU 4S jjjr    SS jrSU 4S jjr	U 4S jr
SS jrS rS rSrU =r$ )r      aT  Records videos of environment episodes using the environment's render function.

.. py:currentmodule:: gymnasium.utils.save_video

Usually, you only want to record episodes intermittently, say every hundredth episode or at every thousandth environment step.
To do this, you can specify ``episode_trigger`` or ``step_trigger``.
They should be functions returning a boolean that indicates whether a recording should be started at the
current episode or step, respectively.

The ``episode_trigger`` should return ``True`` on the episode when recording should start.
The ``step_trigger`` should return ``True`` on the n-th environment step that the recording should be started, where n sums over all previous episodes.
If neither :attr:`episode_trigger` nor ``step_trigger`` is passed, a default ``episode_trigger`` will be employed, i.e. :func:`capped_cubic_video_schedule`.
This function starts a video at every episode that is a power of 3 until 1000 and then every 1000 episodes.
By default, the recording will be stopped once reset is called.
However, you can also create recordings of fixed length (possibly spanning several episodes)
by passing a strictly positive value for ``video_length``.

Examples - Run the environment for 50 episodes, and save the video every 10 episodes starting from the 0th:
    >>> import os
    >>> import gymnasium as gym
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> trigger = lambda t: t % 10 == 0
    >>> env = RecordVideo(env, video_folder="./save_videos1", episode_trigger=trigger, disable_logger=True)
    >>> for i in range(50):
    ...     termination, truncation = False, False
    ...     _ = env.reset(seed=123)
    ...     while not (termination or truncation):
    ...         obs, rew, termination, truncation, info = env.step(env.action_space.sample())
    ...
    >>> env.close()
    >>> len(os.listdir("./save_videos1"))
    5

Examples - Run the environment for 5 episodes, start a recording every 200th step, making sure each video is 100 frames long:
    >>> import os
    >>> import gymnasium as gym
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> trigger = lambda t: t % 200 == 0
    >>> env = RecordVideo(env, video_folder="./save_videos2", step_trigger=trigger, video_length=100, disable_logger=True)
    >>> for i in range(5):
    ...     termination, truncation = False, False
    ...     _ = env.reset(seed=123)
    ...     _ = env.action_space.seed(123)
    ...     while not (termination or truncation):
    ...         obs, rew, termination, truncation, info = env.step(env.action_space.sample())
    ...
    >>> env.close()
    >>> len(os.listdir("./save_videos2"))
    2

Examples - Run 3 episodes, record everything, but in chunks of 1000 frames:
    >>> import os
    >>> import gymnasium as gym
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> env = RecordVideo(env, video_folder="./save_videos3", video_length=1000, disable_logger=True)
    >>> for i in range(3):
    ...     termination, truncation = False, False
    ...     _ = env.reset(seed=123)
    ...     while not (termination or truncation):
    ...         obs, rew, termination, truncation, info = env.step(env.action_space.sample())
    ...
    >>> env.close()
    >>> len(os.listdir("./save_videos3"))
    2

Change logs:
 * v0.25.0 - Initially added to replace ``wrappers.monitoring.VideoRecorder``
Nr   zrl-videoTc                    g)NT )episodes    r(   <lambda>RecordVideo.<lambda>   s    4r*   c
           
        [         R                  R                  R                  U UUUUUUS9  [         R                  R                  X5        UR
                  S;   a  [        SUR
                   S3S5      eUc  Uc  SSKJn
  U
nX0l	        X@l
        Xl        Xl        [        R                  R                  U5      U l        [        R                  R#                  U R                   5      (       a$  [$        R&                  " S	U R                    S
35        [        R(                  " U R                   SS9  Uc  U R*                  R-                  SS5      nXpl        X`l        SU l        US:w  a  UO
[5        S5      U l        SU l        / U l        / U l        SU l        SU l          SSK!ng! [D         a  n[F        RH                  " S5      UeSnAff = f)a@  Wrapper records videos of rollouts.

Args:
    env: The environment that will be wrapped
    video_folder (str): The folder where the recordings will be stored
    episode_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this episode
    step_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this step
    video_length (int): The length of recorded episodes. If 0, entire episodes are recorded.
        Otherwise, snippets of the specified length are captured
    name_prefix (str): Will be prepended to the filename of the recordings
    fps (int): The frame per second in the video. Provides a custom video fps for environment, if ``None`` then
        the environment metadata ``render_fps`` key is used if it exists, otherwise a default value of 30 is used.
    disable_logger (bool): Whether to disable moviepy logger or not, default it is disabled
    gc_trigger: Function that accepts an integer and returns ``True`` iff garbage collection should be performed after this episode
)video_folderepisode_triggerstep_triggervideo_lengthname_prefixdisable_logger>   NansihumanzRender mode is z), which is incompatible with RecordVideo.zXInitialize your environment with a render_mode that returns an image, such as rgb_array.Nr   )capped_cubic_video_schedulezOverwriting existing videos at zh folder (try specifying a different `video_folder` for the `RecordVideo` wrapper if this is not desired)T)exist_ok
render_fps   infF>MoviePy is not installed, run `pip install "gymnasium[other]"`)%r   r   r   r   r    r!   
ValueErrorgymnasium.utils.save_videor^   rW   rX   r[   
gc_triggerospathabspathrV   isdirr
   warnmakedirsr%   getframes_per_secrZ   _video_namefloatrY   	recordingrecorded_framesrender_historystep_id
episode_idmoviepyImportErrorr	   r   )r'   r$   rV   rW   rX   rY   rZ   fpsr[   rg   r^   rw   es                r(   r   RecordVideo.__init__   s   6 			''00%+%%#) 	1 	
 	T'??55!#//!22[\j 
 "|';N9O.(,$GGOOL977==**++KK1$2C2C1D Es t 	D%%5;--##L"5C#& +'+1=1Be$2413	 	..P	s    F% %
G/GGc                   U R                   (       d   S5       eU R                  R                  5       n[        U[        5      (       a@  [        U5      S:X  a  [        R                  " S5        g U =R                  U-  sl        US   n[        U[        R                  5      (       a  U R                  R                  U5        g U R                  5         [        R                  " S[        U5       S35        g )Nz1Cannot capture a frame, recording wasn't started.r   zeTrying to capture render frame but 'env.render()' has just been called. The frame cannot be captured.rc   z^Recording stopped: expected type of frame returned by render to be a numpy array, got instead .)rr   r$   r1   
isinstancelistlenr
   rl   rt   npndarrayrs   r&   stop_recordingtype)r'   frames     r(   _capture_frameRecordVideo._capture_frame?  s    ~~RRR~!eT""5zQ{ 5("IEeRZZ((  ''.!KKpquv{q|p}}~r*   r6   c               $  > [         TU ]  XS9u  p4U =R                  S-  sl        U R                  (       a)  U R                  [        S5      :X  a  U R                  5         U R                  (       aJ  U R                  U R                  5      (       a*  U R                  U R                   SU R                   35        U R                  (       aC  U R                  5         [        U R                  5      U R                  :  a  U R                  5         X44$ )z<Reset the environment and eventually starts a new recording.r6      rb   z	-episode-)r/   r:   rv   rr   rY   rq   r   rW   start_recordingrZ   r   r   rs   )r'   r7   r8   obsinfor4   s        r(   r:   RecordVideo.resetT  s     GMtM=	1>>d//5<?!D$8$8$I$I  D$4$4#5Yt>O!PQ>>!4''(4+<+<<##%yr*   c                   U R                   R                  U5      u  p#pEnU =R                  S-  sl        U R                  (       aJ  U R                  U R                  5      (       a*  U R	                  U R
                   SU R                   35        U R                  (       aC  U R                  5         [        U R                  5      U R                  :  a  U R                  5         X#XEU4$ )z]Steps through the environment using action, recording observations if :attr:`self.recording`.r   z-step-)r$   r0   ru   rX   r   rZ   rr   r   r   rs   rY   r   )r'   r2   r   rew
terminated	truncatedr   s          r(   r0   RecordVideo.stepg  s     15f0E-*!2!24<<!@!@  D$4$4#5VDLL>!JK>>!4''(4+<+<<##%44r*   c                   > [         TU ]  5       nU R                  (       a*  [        U[        5      (       a  U =R
                  U-  sl        [        U R                  5      S:  a  U R                  n/ U l        X!-   $ U$ )ziCompute the render frames as specified by render_mode attribute during initialization of the environment.r   )r/   r1   rr   r~   r   rs   r   rt   )r'   
render_outtmp_historyr4   s      r(   r1   RecordVideo.renderx  sh    W^%
>>jT::  J. t""#a'--K"$D++r*   c                f   > [         TU ]  5         U R                  (       a  U R                  5         gg)z+Closes the wrapper then the video recorder.N)r/   closerr   r   )r'   r4   s    r(   r   RecordVideo.close  s$    >>! r*   c                `    U R                   (       a  U R                  5         SU l         Xl        g)zkStart a new recording. If it is already recording, stops the current recording before starting the new one.TN)rr   r   rp   )r'   
video_names     r(   r   RecordVideo.start_recording  s"    >>!%r*   c                   U R                   (       d   S5       e[        U R                  5      S:X  a  [        R                  " S5        O~ SSKJn  U" U R                  U R                  S9nU R                  (       a  SOSn[        R                  R                  U R                  U R                    S	35      nUR#                  XTS
9  AU ?/ U l        SU l         SU l        U R$                  (       a7  U R%                  U R&                  5      (       a  [(        R*                  " 5         ggg! [         a  n[        R                  " S5      UeSnAff = f)z+Stop current recording and saves the video.z7stop_recording was called, but no recording was startedr   z9Ignored saving a video as there were zero frames to save.)ImageSequenceCliprd   N)ry   barz.mp4)r
   F)rr   r   rs   r
   rl   "moviepy.video.io.ImageSequenceClipr   rx   r	   r   ro   r[   rh   ri   joinrV   rp   write_videofilerg   rv   gccollect)r'   r   rz   clipmoviepy_loggerri   s         r(   r   RecordVideo.stop_recording  s   ~~XXX~t##$)KKSTP %T%9%9t?R?RSD%)%8%8TeN77<< 1 1d6F6F5Gt3LMD   = !??tt??JJL  @?!  22Ts   
D' '
E1EEc                d    [        U R                  5      S:  a  [        R                  " S5        gg)z.Warn the user in case last video wasn't saved.r   z0Unable to save last video! Did you call close()?N)r   rs   r
   rl   r,   s    r(   __del__RecordVideo.__del__  s'    t##$q(KKJK )r*   )rp   r[   rv   rW   ro   rg   rZ   rs   rr   rt   ru   rX   rV   rY   )r$   r?   rV   strrW   Callable[[int], bool] | NonerX   r   rY   intrZ   r   ry   rD   r[   r@   rg   r   rC   rA   )rB   zRenderFrame | list[RenderFrame])r   r   )rE   rF   rG   rH   rI   r   r   r:   r0   r1   r   r   r   r   rK   rL   rM   s   @r(   r   r      s    
CR 9=59%#3GP&P P 6	P
 3P P P P P 1Pd, %)4!3H	' &55	B5""&8L Lr*   r   c                     ^  \ rS rSrSr/ SQrSS jr\S 5       rSU 4S jjr	SSS.     SU 4S	 jjjr
SS
 jrS rU 4S jrSrU =r$ )r   i  a  Allows human like rendering for environments that support "rgb_array" rendering.

This wrapper is particularly useful when you have implemented an environment that can produce
RGB images but haven't implemented any code to render the images to the screen.
If you want to use this wrapper with your environments, remember to specify ``"render_fps"``
in the metadata of your environment.

The ``render_mode`` of the wrapped environment must be either ``'rgb_array'`` or ``'rgb_array_list'``.

No vector version of the wrapper exists.

Example:
    >>> import gymnasium as gym
    >>> from gymnasium.wrappers import HumanRendering
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> wrapped = HumanRendering(env)
    >>> obs, _ = wrapped.reset()     # This will start rendering to the screen

    The wrapper can also be applied directly when the environment is instantiated, simply by passing
    ``render_mode="human"`` to ``make``. The wrapper will only be applied if the environment does not
    implement human-rendering natively (i.e. ``render_mode`` does not contain ``"human"``).

    >>> env = gym.make("phys2d/CartPole-v1", render_mode="human")      # CartPoleJax-v1 doesn't implement human-rendering natively
    >>> obs, _ = env.reset()     # This will start rendering to the screen

    Warning: If the base environment uses ``render_mode="rgb_array_list"``, its (i.e. the *base environment's*) render method
    will always return an empty list:

    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array_list")
    >>> wrapped = HumanRendering(env)
    >>> obs, _ = wrapped.reset()
    >>> env.render() # env.render() will always return an empty list!
    []

Change logs:
 * v0.25.0 - Initially added
)	rgb_arrayrgb_array_listdepth_arraydepth_array_listc                8   [         R                  R                  R                  U 5        [         R                  R                  X5        SU l        SU l        SU l        U R                  R                  U R                  ;   d"   SU R                   SUR                   S35       eSU R                  R                  ;   d   S5       eSU R                  S   ;  aC  [        U R                  R                  5      U l        U R                  S   R                  S5        gg)	zeInitialize a :class:`HumanRendering` instance.

Args:
    env: The environment that is being wrapped
Nz&Expected env.render_mode to be one of z
 but got ''r`   zYThe base environment must specify 'render_fps' to be used with the HumanRendering wrapperr]   r   )r   r   r   r   r    screen_sizewindowclockr$   r!   ACCEPTED_RENDER_MODESr%   r   r&   )r'   r$   s     r(   r   HumanRendering.__init__  s     			''006T'
 HH  D$>$>>	m3D4N4N3OzZ]ZiZiYjjkl	m> DHH---	gf	g- $--77$TXX%6%67DMMM.)009 8r*   c                    g)zAlways returns ``'human'``.r]   rQ   r,   s    r(   r!   HumanRendering.render_mode  s     r*   c                F   > [         TU ]  U5      nU R                  5         U$ )zHPerform a step in the base environment and render a frame to the screen.)r/   r0   _render_frame)r'   r2   resultr4   s      r(   r0   HumanRendering.step  s"    f%r*   Nr6   c               B   > [         TU ]  XS9nU R                  5         U$ )z<Reset the base environment and render a frame to the screen.r6   )r/   r:   r   )r'   r7   r8   r   r4   s       r(   r:   HumanRendering.reset  s&     D:r*   c                    g)z]This method doesn't do much, actual rendering is performed in :meth:`step` and :meth:`reset`.NrQ   r,   s    r(   r1   HumanRendering.render  s    r*   c                    SSK nU R                  R                  c   eU R                  R                  R                  S5      (       a7  U R                  R                  5       n[        U[        5      (       d   eUS   nOU R                  R                  5       n[        U[        R                  5      (       d   S[        U5       35       e[        R                  " USS9nU R                  c  UR                  SS	 U l        U R                  UR                  SS	 :X  d$   S
U R                   SUR                  SS	  35       eU R                  cT  UR!                  5         UR"                  R!                  5         UR"                  R%                  U R                  5      U l        U R&                  c  UR(                  R+                  5       U l        UR,                  R/                  U5      nU R                  R1                  US5        UR2                  R5                  5         U R&                  R7                  U R8                  S   5        UR"                  R;                  5         g! [         a    [        S5      ef = f)zKFetch the last frame from the base environment and render it to the screen.r   NzGpygame is not installed, run `pip install "gymnasium[classic-control]"`r   rc   zCExpected `env.render()` to return a numpy array, actually returned )r   r      )axesr   z,The shape of the rgb array has changed from z to )r   r   r`   )pygamerx   r   r$   r!   r"   r1   r~   r   r   r   r   	transposer   shaper   initdisplayset_moder   timeClock	surfarraymake_surfacebliteventpumptickr%   flip)r'   r   last_rgb_arrayr   surfs        r(   r   HumanRendering._render_frame  s   	
 xx##///88((11!XX__.Nnd3333+B/N!XX__.NBJJ
 
 	hPQUVdQePfg	h 
 LLi@	#(r2D 	 33	f9$:J:J9K4PYP_P_`babPcOde	f3 ;;KKMNN! ..11$2B2BCDK::**,DJ,,Y7v&

l34K  	(Y 	s   I$ $I:c                   > U R                   b.  SSKnUR                  R                  5         UR                  5         [        TU ]  5         g)zClose the rendering window.Nr   )r   r   r   quitr/   r   )r'   r   r4   s     r(   r   HumanRendering.close?  s2    ;;"NN!KKMr*   )r   r%   r   r   )r$   r?   )r2   r   rB   z/tuple[ObsType, SupportsFloat, bool, bool, dict]rC   )rB   None)rE   rF   rG   rH   rI   r   r   rJ   r!   r0   r:   r1   r   r   rK   rL   rM   s   @r(   r   r     sm    $L:0   %)4!3H	' )V r*   r   c                  J   ^  \ rS rSrSr S     SS jjrSU 4S jjrSrU =r$ )	r   iI  a9  Randomly replaces pixels with white noise.

If used with ``render_mode="rgb_array"`` and ``AddRenderObservation``, it will
make observations noisy.
The environment may also become partially-observable, turning the MDP into a POMDP.

Example - Every pixel will be replaced by white noise with probability 0.5:
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> env = AddWhiteNoise(env, probability_of_noise_per_pixel=0.5)
    >>> env = HumanRendering(env)
    >>> obs, _ = env.reset(seed=123)
    >>> obs, *_ = env.step(env.action_space.sample())
c                    SUs=::  a  S:  d  O  [        SU 35      e[        R                  R                  R	                  U UUS9  [        R
                  R	                  X5        X l        X0l        g)zWrapper replaces random pixels with white noise.

Args:
    env: The environment that is being wrapped
    probability_of_noise_per_pixel: the probability that a pixel is white noise
    is_noise_grayscale: if True, RGB noise is converted to grayscale
r   r   zIprobability_of_noise_per_pixel should be in the interval [0,1). Received )probability_of_noise_per_pixelis_noise_grayscaleN)r   r   r   r   r   r    r   r   )r'   r$   r   r   s       r(   r   AddWhiteNoise.__init__Z  ss     26Q6$[\z[{|  			''00+I1 	1 	

 	T'.L+"4r*   c                   > [         TU ]  5       nU R                  (       al  U R                  R	                  SS[
        R                  " / SQ5      -  UR                  [
        R                  S9R                  SSS9R                  SS5      nO4U R                  R	                  S	SUR                  [
        R                  S9nU R                  R                  UR                  S	S
 5      U R                  :  n[
        R                  " US   X!5      $ )zCompute the render frames as specified by render_mode attribute during initialization of the environment, then add white noise.r   r   r      gŏ1w-!?gbX9?gv/?sizedtyperc   Tkeepdims   r   r   .N)r/   r1   r   	np_randomintegersr   arrayr   uint8sumrepeatrandomr   where)r'   r   noisemaskr4   s       r(   r1   AddWhiteNoise.renderv  s    W^%
""''"((#;<<#))((	 (  R$'2  NN++%%hh	 , E NN!!*"2"21Q"78112 	
 xxY;;r*   )r   r   F)r$   r?   r   rq   r   r@   rB   r   	rE   rF   rG   rH   rI   r   r1   rK   rL   rM   s   @r(   r   r   I  s8    $ $)	5&5 ).5 !	58< <r*   r   c                  N   ^  \ rS rSrSr S       SS jjrSU 4S jjrSrU =r$ )	r   i  a  Randomly obstructs rendering with white noise patches.

If used with ``render_mode="rgb_array"`` and ``AddRenderObservation``, it will
make observations noisy.
The number of patches depends on how many pixels we want to obstruct.
Depending on the size of the patches, the environment may become
partially-observable, turning the MDP into a POMDP.

Example - Obstruct 50% of the pixels with patches of size 50x50 pixels:
    >>> env = gym.make("LunarLander-v3", render_mode="rgb_array")
    >>> env = ObstructView(env, obstructed_pixels_ratio=0.5, obstruction_width=50)
    >>> env = HumanRendering(env)
    >>> obs, _ = env.reset(seed=123)
    >>> obs, *_ = env.step(env.action_space.sample())
c                (   SUs=::  a  S:  d  O  [        SU 35      eUS:  a  [        SU 35      e[        R                  R                  R	                  U UUUS9  [        R
                  R	                  X5        X#S-  -  U l        X0l        X@l        g)a<  Wrapper obstructs pixels with white noise patches.

Args:
    env: The environment that is being wrapped
    obstructed_pixels_ratio: the percentage of pixels obstructed with white noise
    obstruction_width: the width of the obstruction patches
    is_noise_grayscale: if True, RGB noise is converted to grayscale
r   r   zBobstructed_pixels_ratio should be in the interval [0,1). Received z=obstruction_width should be larger or equal than 1. Received )obstructed_pixels_ratioobstruction_widthr   r   N)	re   r   r   r   r   r    obstruction_centers_ratior   r   )r'   r$   r   r   r   s        r(   r   ObstructView.__init__  s     +/a/TUlTmn  q OPaObc  			''00$;/1	 	1 	
 	T')@VWCW)W&!2"4r*   c           
       > [         TU ]  5       nUR                  nUS   US   -  n[        X0R                  -  5      nU R
                  R                  SX45      n[        R                  " XRS   US   45      n[        R                  " US   US   4[        S9nU R                  S-  nU R                  U-
  n[        U6  HF  u  pSU[        X-
  S5      [        X-   US   5      2[        X-
  S5      [        X-   US   5      24'   MH     U R                  (       al  U R
                  R                  SS[        R                   " / SQ5      -  UR                  [        R"                  S	9R%                  S
SS9R'                  SS
5      nO4U R
                  R                  SSUR                  [        R"                  S	9n[        R(                  " US   X5      $ )zCompute the render frames as specified by render_mode attribute during initialization of the environment, then add white noise patches.r   r   )r   r   Tr   r   r   r   rc   r   r   r   )r/   r1   r   r   r   r   r   r   unravel_indexzerosr@   r   zipmaxminr   r   r   r   r   r   )r'   r   render_shapen_pixelsn_obstructionscentersr   lowhighxyr   r4   s               r(   r1   ObstructView.render  s   W^%
!''?\!_4X(F(FFG..))!XF""7!_l1o,NOxxa,q/:$G$$)%%+MDA  AGQ#ahQ"@@AGQ#ahQ"@@B " ""''"((#;<<#))((	 (  R$'2  NN++%%hh	 , E xxY;;r*   )r   r   r   r   )r$   r?   r   rq   r   r   r   r@   r   r   rM   s   @r(   r   r     sC    * $)#5&#5 "'#5 	#5
 !#5J%< %<r*   r   )#rI   
__future__r   r   rh   collections.abcr   copyr   typingr   r   r   numpyr   	gymnasiumr   r	   r
   gymnasium.corer   r   r   gymnasium.errorr   r   __all__r    r   r   r   r   r   r   r   rQ   r*   r(   <module>r     sA   # 	 	 $  . .   # 8 8 F}KK'723GWk)*II##}@OLKK'723GWk)*II##OLdQKK'723SYY5T5TQhI<KK'723SYY5T5TI<X]<KK'723SYY5T5T]<r*   