§
    E«jò ã                  ó  — U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlmZ ddlmZ ddlmZmZ ddlmZmZ ddlmZmZmZmZmZm Z  dd	l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/ dd
l0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6m7Z7 ddl8m9Z9  e
j:        e;¦  «        Z< e¦   «         Z=de>d<   d}d~d„Z?dd„Z@dZA G d„ d¦  «        ZB G d„ deB¦  «        ZC G d„ deB¦  «        ZD G d „ d!eB¦  «        ZE G d"„ d#¦  «        ZFd$ZGd€d(„ZHd�d5„ZId‚d7„ZJdƒd9„ZKd„d<„ZLd…d=„ZMd†d>„ZNd‡d?„ZOdˆdB„ZPd‰dH„ZQdŠdK„ZRd‹dM„ZSdŒdO„ZTd�dR„ZUdŽdT„ZVd�dU„ZWd�dX„ZXd‘dY„ZYd’d\„ZZd“d`„Z[d”dd„Z\d•df„Z]d–dh„Z^d—dj„Z_d˜dl„Z`d™dp„Zadšdu„Zbd›dy„Zcdœd|„ZddS )�z'Provides communication with the engine.é    )ÚannotationsN)ÚCounter)ÚCallable)ÚmodelÚlichess)ÚConfigurationÚchange_value_to_list)ÚTimerÚmsecÚsecondsÚmsec_strÚsec_strÚ
to_seconds)ÚReadableTypeÚChessDBMoveTypeÚLichessEGTBMoveTypeÚOPTIONS_GO_EGTB_TYPEÚOPTIONS_TYPEÚCOMMANDS_TYPEÚMOVEÚInfoStrDictÚInfoDictKeysÚInfoDictValueÚGO_COMMANDS_TYPEÚEGTPATH_TYPEÚENGINE_INPUT_ARGS_TYPEÚENGINE_INPUT_KWARGS_TYPE)Úgame_specific_options)Ú
itemgetter)ÚAnyÚLiteralÚcast)ÚTracebackTypezCounter[str]Ú out_of_online_opening_book_movesÚengine_configr   Úgameúmodel.Game | NoneÚreturnÚEngineWrapperc           	     ó‚  — | j         }t          j                             t          j                             |j        |j        ¦  «        ¦  «        }|j        }g }|j        r4| 	                    |j        ¦  «         | 
                    |j        ¦  «         | 	                    |¦  «         |j        rA|j                             ¦   «         D ]'\  }}| 	                    |�d|› d|› �nd|› �¦  «         Œ(|j        rt          j        nd}|dk    rt"          }	n<|dk    rt$          }	n.|dk    rt'          |j        ¦  «        }	nt)          d|› d�¦  «        ‚t+          |                     |› d	�¦  «        pt/          i ¦  «        ¦  «        }
t0                               d
|› �¦  «          |	||
||j        ||j        |j        ¬¦  «        S )a  
    Create the engine.

    Use in a with-block to automatically close the engine when exiting the game.

    :param engine_config: The options for the engine.
    :param game: The game to create the engine from.
    :return: An engine. Either UCI, XBoard, or Homemade.
    Nz--ú=ÚxboardÚuciÚhomemadez    Invalid engine type: z$. Expected xboard, uci, or homemade.Ú_optionszStarting engine: )Úcwd)ÚengineÚosÚpathÚabspathÚjoinÚdirÚnameÚprotocolÚinterpreterÚappendÚextendÚinterpreter_optionsÚengine_optionsÚitemsÚsilence_stderrÚ
subprocessÚDEVNULLÚXBoardEngineÚ	UCIEngineÚget_homemade_engineÚ
ValueErrorÚremove_managed_optionsÚlookupr   ÚloggerÚdebugÚdraw_or_resignÚworking_dir)r%   r&   ÚcfgÚengine_pathÚengine_typeÚcommandsÚkÚvÚstderrÚEngineÚoptionss              ú-/app/lichess-bot-master/lib/engine_wrapper.pyÚcreate_enginerV   #   s×  € ð Ô
€CÝ”'—/’/¥"¤'§,¢,¨s¬w¸¼Ñ"AÔ"AÑBÔB€KØ”,€KØ€HØ
„ð 1Ø�Š˜œÑ(Ô(Ð(Ø�Š˜Ô/Ñ0Ô0Ð0Ø‡O‚O�KÑ Ô Ð Ø
Ôð IØÔ&×,Ò,Ñ.Ô.ð 	Ið 	I‰DˆAˆqØ�OŠO¨A¨M˜L ˜L˜L Q˜L˜L˜L¸xÀA¸x¸xÑHÔHÐHÐHà#&Ô#5Ð?�ZÔÐ¸4€Fð �hÒÐÝˆˆØ	˜Ò	Ð	ÝˆˆØ	˜
Ò	"Ð	"Ý$ S¤XÑ.Ô.ˆˆåØY¨ÐYÐYÐYñ[ô [ð 	[å$ S§Z¢Z°;Ð0HÐ0HÐ0HÑ%IÔ%IÐ%^Í]Ð[]ÑM^ÔM^Ñ_Ô_€GÝ
‡L‚LÐ/ XÐ/Ð/Ñ0Ô0Ð0Øˆ6�(˜G V¨SÔ-?ÀÀsÄyØ”oð'ñ 'ô 'ð 'ó    Úconfigr   c                óL   ‡— dd„Šˆfd„|                       ¦   «         D ¦   «         S )z+Remove the options managed by python-chess.ÚkeyÚstrr(   Úboolc                ón   — t           j                             | dd d d d ¦  «                             ¦   «         S )NÚ )Úchessr1   ÚOptionÚ
is_managed©rZ   s    rU   ra   z*remove_managed_options.<locals>.is_managedM   s.   € ÝŒ|×"Ò" 3¨¨D°$¸¸dÑCÔC×NÒNÑPÔPÐPrW   c                ó2   •— i | ]\  }} ‰|¦  «        °||“ŒS © rd   )Ú.0r7   Úvaluera   s      €rU   ú
<dictcomp>z*remove_managed_options.<locals>.<dictcomp>P   s.   ø€ ÐTÐTÐT™M˜T 5À:À:ÈdÑCSÔCSÐTˆD�%ÐTÐTÐTrW   )rZ   r[   r(   r\   )r>   )rX   ra   s    @rU   rF   rF   K   s@   ø€ ðQð Qð Qð Qð UÐTÐTÐT¨V¯\ª\©^¬^ÐTÑTÔTÐTrW   é   c                  óÜ   — e Zd ZdZdRd„ZdSd„ZdTd„ZdUd„ZdVd#„ZdWd&„Z	dXd)„Z
dYd.„ZdZd1„Zd[d4„Zd\d6„Zd]d7„Zd]d8„Zd^d<„Zd_d?„Zd`dA„Zd`dB„ZdadF„ZdbdcdJ„ZdddK„ZdedL„ZdedM„Zd]dN„ZdfdO„Zd]dP„ZdQS )gr)   z6A wrapper used by all engines (UCI, XBoard, Homemade).rT   r   rJ   r   r(   ÚNonec           	     ó¼   — |  g | _         || _        t          t          t          |                     di ¦  «        ¦  «        pi ¦  «        | _        g | _        d| _        dS )z÷
        Initialize the values of the wrapper used by all engines (UCI, XBoard, Homemade).

        :param options: The options to send to the engine.
        :param draw_or_resign: Options on whether the bot should resign or offer draws.
        Úgo_commandséÿÿÿÿN)	ÚscoresrJ   r   r"   r   Úpoprl   Úmove_commentaryÚcomment_start_index)ÚselfrT   rJ   s      rU   Ú__init__zEngineWrapper.__init__Y   s_   € ð 	Ð=Ø35ˆŒØ,ˆÔÝ(­Õ.>ÀÇÂÈMÐ[]Ñ@^Ô@^Ñ)_Ô)_Ð)eÐceÑfÔfˆÔØ24ˆÔØ#%ˆÔ Ð Ð rW   r&   r'   c                óÞ   — 	 |€i nt          |¦  «        }| j                             t          t          ||z  ¦  «        ¦  «         dS # t
          $ r | j                             ¦   «          ‚ w xY w)z×
        Send configurations to the engine.

        :param options: A dictionary of strings to option values.

        Raises chess.engine.EngineError if an option is sent that the engine does not support.
        N)r   r1   Ú	configurer"   r   Ú	ExceptionÚclose)rr   rT   r&   Úextra_optionss       rU   ru   zEngineWrapper.configureg   sz   € ð	Ø"& ,˜B˜BÕ4IÈ$Ñ4OÔ4OˆMØŒK×!Ò!¥$¥|°W¸}Ñ5LÑ"MÔ"MÑNÔNÐNÐNÐNøÝð 	ð 	ð 	ØŒK×ÒÑÔÐØð	øøøs   ‚AA Á%A,c                ó8   — | j                              ¦   «          | S )z@Enter context so engine communication will be properly shutdown.)r1   Ú	__enter__©rr   s    rU   rz   zEngineWrapper.__enter__v   s   € àŒ×ÒÑÔÐØˆrW   Úexc_typeútype[BaseException] | NoneÚ	exc_valueúBaseException | NoneÚ	tracebackúTracebackType | Nonec                ó’   — |€(|                       ¦   «          |                      ¦   «          | j                             |||¦  «         dS )zKExit context and allow engine to shutdown nicely if there was no exception.N)ÚpingÚquitr1   Ú__exit__)rr   r|   r~   r€   s       rU   r…   zEngineWrapper.__exit__{   sD   € ð ÐØ�IŠI‰KŒKˆKØ�IŠI‰KŒKˆKØŒ×Ò˜X y°)Ñ<Ô<Ð<Ð<Ð<rW   Úboardúchess.Boardú
model.GameÚliúlichess.LichessÚsetup_timerr
   Úmove_overheadúdatetime.timedeltaÚ
can_ponderr\   Úis_correspondenceÚcorrespondence_move_timeÚ
engine_cfgÚmin_timec           	     ó®  ‡— |	j         }|	j        }|	j        }|	j        }t	          |||¦  «        }|j        €t          ||||¦  «        }t          |t          ¦  «        s|j        €t          |||||¦  «        }t          |t          ¦  «        s|j        �€t          |¦  «        }t          |||||||¦  «        \  }}	 |                      |||||¦  «        }nÁ# t          j        j        $ rª}t          j        t          j        fŠt%          ˆfd„|j        D ¦   «         ¦  «        s‚ t(                               d¦  «         t(                               |¦  «         |                     ¦   «         r|j        n|j        } ||j        ¦  «         Y d}~dS d}~ww xY w|                     ¦   «         }||
k     r$t7          j        t;          |
|z
  ¦  «        ¦  «         |                      ||¦  «         |                      ¦   «          |j         r4tC          |j"        ¦  «        dk    r|                     |j        ¦  «         dS | #                    |j        |¦  «         dS )aE  
        Play a move.

        :param board: The current position.
        :param game: The game that the bot is playing.
        :param li: Provides communication with lichess.org.
        :param start_time: The time that the bot received the move.
        :param move_overhead: The time it takes to communicate between the engine and lichess.org.
        :param can_ponder: Whether the engine is allowed to ponder.
        :param is_correspondence: Whether this is a correspondence or unlimited game.
        :param correspondence_move_time: The time the engine will think if `is_correspondence` is true.
        :param engine_cfg: Options for external moves (e.g. from an opening book), and for engine resignation and draw offers.
        :param min_time: Minimum time to spend, in seconds.
        :return: The move to play.
        Nc              3  ó8   •K  — | ]}t          |‰¦  «        V — Œd S ©N)Ú
isinstance)re   ÚeÚBadMoves     €rU   ú	<genexpr>z*EngineWrapper.play_move.<locals>.<genexpr>¾   s-   øè è € ÐFÐF°a�: a¨Ñ1Ô1ÐFÐFÐFÐFÐFÐFrW   z2Ending game due to bot attempting an illegal move.é   )$ÚpolyglotÚonline_movesrJ   Úlichess_bot_tbsÚget_book_moveÚmoveÚget_egtb_mover–   ÚlistÚget_online_moveÚcheck_for_draw_offerÚ	move_timeÚsearchr_   r1   ÚEngineErrorÚIllegalMoveErrorÚInvalidMoveErrorÚanyÚargsrH   ÚerrorÚis_abortableÚabortÚresignÚidÚtime_since_resetÚtimeÚsleepr   Úadd_commentÚprint_statsÚresignedÚlenÚ
move_stackÚ	make_move)rr   r†   r&   r‰   r‹   rŒ   rŽ   r�   r�   r‘   r’   Úpolyglot_cfgÚonline_moves_cfgÚdraw_or_resign_cfgr�   Ú	best_moveÚdraw_offeredÚ
time_limitr«   Ú
game_enderÚelapsedr˜   s                        @rU   Ú	play_movezEngineWrapper.play_move„   s}  ø€ ð4 "Ô*ˆØ%Ô2ÐØ'Ô6ÐØ$Ô4ˆõ " %¨¨|Ñ<Ô<ˆ	àŒ>Ð!Ý% eØ&*Ø&5Ø&8ñ:ô :ˆIõ
 ˜)¥TÑ*Ô*ð 	<¨y¬~Ð/EÝ'¨Ø(-Ø(,Ø(8Ø(:ñ	<ô <ˆIõ �i¥Ñ&Ô&ð 	¨)¬.Ñ*@Ý/°Ñ5Ô5ˆLå%.¨u°d¸JØ/:¸MØ/@ÐBZñ&\ô &\Ñ"ˆJ˜
ð
Ø ŸKšK¨¨z¸:À|ÐU^Ñ_Ô_�	�	øÝ”<Ô+ð ð ð Ý Ô1µ5Ô3IÐJ�ÝÐFÐFÐFÐF¸5¼:ÐFÑFÔFÑFÔFð ØÝ—’ÐQÑRÔRÐRÝ—’˜UÑ#Ô#Ð#Ø)-×):Ò):Ñ)<Ô)<ÐK˜RœX˜XÀ"Ä)�
Ø�
˜4œ7Ñ#Ô#Ð#Ø�����øøøøðøøøð ×.Ò.Ñ0Ô0ˆØ�XÒÐÝŒJ•z (¨WÑ"4Ñ5Ô5Ñ6Ô6Ð6à×Ò˜ EÑ*Ô*Ð*Ø×ÒÑÔÐØÔð 	-¥# eÔ&6Ñ"7Ô"7¸1Ò"<Ð"<Ø�IŠI�d”gÑÔÐÐÐà�LŠL˜œ )Ñ,Ô,Ð,Ð,Ð,s   Â<C ÃFÃ*BFÆFr¾   úchess.engine.Limitc                óê   — | j         j        }|�Bt          |¦  «        }|j        �t	          |j        ¦  «        |k    rt          |¦  «        |_        | j         j        |_        | j         j        |_        |S )zbAdd extra commands to send to the engine. For example, to search for 1000 nodes or up to depth 10.)rl   Úmovetimer   r±   r   r   ÚdepthÚnodes)rr   r¾   Úmovetime_cfgrÄ   s       rU   Úadd_go_commandszEngineWrapper.add_go_commandsÒ   sm   € àÔ'Ô0ˆØÐ#Ý˜LÑ)Ô)ˆHØŒÐ&­'°*´/Ñ*BÔ*BÀXÒ*MÐ*MÝ",¨XÑ"6Ô"6�
”ØÔ+Ô1ˆ
ÔØÔ+Ô1ˆ
ÔØÐrW   Úresultúchess.engine.PlayResultc           	     óÊ  ‡‡‡— dd„Š| j         j        }| j         j        }| j         j        Š| j         j        }t          j        |j        ¦  «        }||k    }|rst          | j	        ¦  «        |k    r[|rY| j	        | d…         }dˆˆfd„}	t          |¦  «        t          t          t          |	|¦  «        ¦  «        ¦  «        k    rd	|_        | j         j        }
| j         j        }| j         j        Š|
rqt          | j	        ¦  «        |k    rY| j	        | d…         }dˆˆfd
„}t          |¦  «        t          t          t          ||¦  «        ¦  «        ¦  «        k    rd	|_        |S )z:Offer draw or resign depending on the score of the engine.Úscoreúchess.engine.PovScorer(   Úintc                ó8   — | j                              d¬¦  «        S )Ni@œ  )Ú
mate_score)ÚrelativerÌ   ©rÌ   s    rU   Úactualz2EngineWrapper.offer_draw_or_resign.<locals>.actualß   s   € Ø”>×'Ò'°5Ð'Ñ9Ô9Ð9rW   Nr\   c                ó<   •— t           ‰| ¦  «        ¦  «        ‰k    S r•   )Úabs)rÌ   rÓ   Údraw_score_ranges    €€rU   Úscore_near_drawz;EngineWrapper.offer_draw_or_resign.<locals>.score_near_drawë   s   ø€ Ý˜6˜6 %™=œ=Ñ)Ô)Ð-=Ò=Ð=rW   Tc                ó"   •—  ‰| ¦  «        ‰k    S r•   rd   )rÌ   rÓ   Úresign_scores    €€rU   Úscore_near_lossz;EngineWrapper.offer_draw_or_resign.<locals>.score_near_lossö   s   ø€ Ø�v˜e‘}”}¨Ò4Ð4rW   )rÌ   rÍ   r(   rÎ   )rÌ   rÍ   r(   r\   )rJ   Úoffer_draw_enabledÚoffer_draw_movesÚoffer_draw_scoreÚoffer_draw_piecesr_   ÚpopcountÚoccupiedr¶   rn   r¡   Úfilterr½   Úresign_enabledÚresign_movesrÙ   rµ   )rr   rÉ   r†   Úcan_offer_drawÚdraw_offer_movesÚdraw_max_piece_countÚpieces_on_boardÚenough_pieces_capturedrn   r×   râ   Úmin_moves_for_resignrÚ   rÓ   rÖ   rÙ   s                @@@rU   Úoffer_draw_or_resignz"EngineWrapper.offer_draw_or_resignÝ   s¥  øøø€ ð	:ð 	:ð 	:ð 	:ð Ô,Ô?ˆØÔ.Ô?ÐØ $Ô 3Ô DÐØ#Ô2ÔDÐÝœ.¨¬Ñ8Ô8ˆØ!0Ð4HÒ!HÐØð 	+�c $¤+Ñ.Ô.Ð2BÒBÐBÐG]ÐBØ”[Ð"2Ð!2Ð!3Ð!3Ô4ˆFð>ð >ð >ð >ð >ð >ð >å�6‰{Œ{�c¥$¥v¨o¸vÑ'FÔ'FÑ"GÔ"GÑHÔHÒHÐHØ&*�Ô#àÔ,Ô;ˆØ#Ô2Ô?ÐØ Ô/Ô<ˆØð 	'�c $¤+Ñ.Ô.Ð2FÒFÐFØ”[Ð"6Ð!6Ð!7Ð!7Ô8ˆFð5ð 5ð 5ð 5ð 5ð 5ð 5å�6‰{Œ{�c¥$¥v¨o¸vÑ'FÔ'FÑ"GÔ"GÑHÔHÒHÐHØ"&�”ØˆrW   Úponderr½   Ú
root_movesr   c                óÎ  — |                       |¦  «        }| j                             ||t          j        j        ||t          |t          ¦  «        r|nd¬¦  «        }t          j                             t          j                             d¦  «        |j	        ¦  «        }| j
                             |j                             d|¦  «        ¦  «         |                      ||¦  «        S )a×  
        Tell the engine to search.

        :param board: The current position.
        :param time_limit: Conditions for how long the engine can search (e.g. we have 10 seconds and search up to depth 10).
        :param ponder: Whether the engine can ponder.
        :param draw_offered: Whether the bot was offered a draw.
        :param root_moves: If it is a list, the engine will only play a move that is in `root_moves`.
        :return: The move to play.
        N)Úinforë   r½   rì   é   rÌ   )rÈ   r1   Úplayr_   ÚINFO_ALLr–   r¡   ÚPovScoreÚMateÚturnrn   r:   rî   Úgetrê   )rr   r†   r¾   rë   r½   rì   rÉ   Ú
null_scores           rU   r¥   zEngineWrapper.searchü   sÇ   € ð ×)Ò)¨*Ñ5Ô5ˆ
Ø”×!Ò! %Ø",Ý',¤|Ô'<Ø)/Ø/;Ý;EÀjÕRVÑ;WÔ;WÐ-a¨Z¨ZÐ]að "ñ cô cˆõ ”\×*Ò*­5¬<×+<Ò+<¸QÑ+?Ô+?ÀÄÑLÔLˆ
ØŒ×Ò˜6œ;Ÿ?š?¨7°JÑ?Ô?Ñ@Ô@Ð@Ø×(Ò(¨°Ñ7Ô7Ð7rW   Úmove_stack_indexrÎ   c                ó0   — | j         dk     rdS || j         z
  S )zÄ
        Get the index of a move for use in `comment_for_board_index`.

        :param move_stack_index: The move number.
        :return: The index of the move in `self.move_commentary`.
        r   rm   )rq   )rr   r÷   s     rU   Úcomment_indexzEngineWrapper.comment_index  s%   € ð Ô# aÒ'Ð'Ø�2Ø $Ô":Ñ:Ð:rW   Úindexr   c                ó˜   — i }|                       |¦  «        }|dk     s	|dz  dk    r|S 	 | j        |dz           S # t          $ r |cY S w xY w)zŠ
        Get the engine comments for a specific move.

        :param index: The move number.
        :return: The move comments.
        r   rš   )rù   rp   Ú
IndexError)rr   rú   Úno_inforù   s       rU   Úcomment_for_board_indexz%EngineWrapper.comment_for_board_index  sw   € ð  "ˆØ×*Ò*¨5Ñ1Ô1ˆØ˜1ÒÐ °Ñ 1°QÒ 6Ð 6ØˆNð	ØÔ'¨¸Ñ(:Ô;Ð;øÝð 	ð 	ð 	ØˆNˆNˆNð	øøøs   ª: ºA	ÁA	rŸ   c                óð  — | j         dk     rt          |j        ¦  «        | _         t          t          t          |j        r|j                             ¦   «         ni ¦  «        ¦  «        }d|v r#|                     |j        d         ¦  «        |d<   d|v r#|                     |j        d         ¦  «        |d<   d|v r#| 	                    |j        d         ¦  «        |d<   | j
                             |¦  «         dS )zž
        Store the move's comments.

        :param move: The move. Contains the comments in `move.info`.
        :param board: The current position.
        r   ÚpvÚponderpvÚ
refutationÚcurrmoveN)rq   r¶   r·   r"   r   Údictrî   ÚcopyÚvariation_sanÚsanrp   r:   )rr   rŸ   r†   Ú	move_infos       rU   r³   zEngineWrapper.add_comment0  sì   € ð Ô# aÒ'Ð'Ý'*¨5Ô+;Ñ'<Ô'<ˆDÔ$Ý�¥d¸t¼yÐ+P¨4¬9¯>ª>Ñ+;Ô+;Ð+;ÈbÑ&QÔ&QÑRÔRˆ	Ø�9ÐÐØ$)×$7Ò$7¸¼	À$¼Ñ$HÔ$HˆI�jÑ!Ø˜9Ð$Ð$Ø&+×&9Ò&9¸$¼)ÀLÔ:QÑ&RÔ&RˆI�lÑ#Ø˜Ð"Ð"Ø$)§I¢I¨d¬i¸
Ô.CÑ$DÔ$DˆI�jÑ!ØÔ×#Ò# IÑ.Ô.Ð.Ð.Ð.rW   c                óœ   — t          j        t          ¦  «        5  | j                             ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )z€
        Remove the commentary for the last move, if any.

        Used after allowing an opponent to take back a move.
        N)Ú
contextlibÚsuppressrü   rp   ro   r{   s    rU   Údiscard_last_move_commentaryz*EngineWrapper.discard_last_move_commentaryB  sŽ   € õ Ô ¥Ñ,Ô,ð 	'ð 	'ØÔ ×$Ò$Ñ&Ô&Ð&ð	'ð 	'ð 	'ñ 	'ô 	'ð 	'ð 	'ð 	'ð 	'ð 	'ð 	'ð 	'øøøð 	'ð 	'ð 	'ð 	'ð 	'ð 	's   šAÁAÁAc                óh   — |                       ¦   «         D ]}t                               |¦  «         ŒdS )zPrint the engine stats.N)Ú	get_statsrH   rî   )rr   Úlines     rU   r´   zEngineWrapper.print_statsK  s:   € à—N’NÑ$Ô$ð 	ð 	ˆDÝ�KŠK˜ÑÔÐÐð	ð 	rW   Úrelative_scorerÍ   r[   c                ó°   — |j         }|                     ¦   «         }|€d|                     ¦   «         › �}n t          t	          |dz  d¦  «        ¦  «        }|S )z2Convert the score to a more human-readable format.Nú#éd   rš   )rÑ   rÌ   Úmater[   Úround)rr   r  rÌ   Úcp_scoreÚ	str_scores        rU   Úreadable_scorezEngineWrapper.readable_scoreP  sU   € àÔ'ˆØ—;’;‘=”=ˆØÐØ*˜EŸJšJ™LœLÐ*Ð*ˆIˆIå�E (¨S¡.°!Ñ4Ô4Ñ5Ô5ˆIØÐrW   Úwdlúchess.engine.PovWdlc                ó`   — t          |j                             ¦   «         dz  d¦  «        }|› d�S )zDConvert the WDL score to a percentage, so it is more human-readable.r  rï   ú%)r  rÑ   Úexpectation)rr   r  Úwdl_percentages      rU   Úreadable_wdlzEngineWrapper.readable_wdlZ  s3   € å˜sœ|×7Ò7Ñ9Ô9¸CÑ?ÀÑCÔCˆØ Ð#Ð#Ð#Ð#rW   Únumberc                óT   — t          |d¦  «        \  }}|dk    r
|d›d|d›d�S |d›d�S )ziConvert time given as a number into minutes and seconds, so it is more human-readable. e.g. 123 -> 2m 3s.é<   rï   z0.0fzm z0.1fÚs)Údivmod)rr   r   Úminutesr   s       rU   Úreadable_timezEngineWrapper.readable_time_  sN   € å! &¨"Ñ-Ô-Ñˆ�Ø�aŠ<ˆ<ØÐ5Ð5Ð5 gÐ5Ð5Ð5Ð5Ð5àÐ%Ð%Ð%Ð%Ð%rW   c                óÈ   — |dk    rt          |dz  d¦  «        › d�S |dk    rt          |dz  d¦  «        › d�S |dk    rt          |dz  d¦  «        › d�S t          |¦  «        S )zGConvert number to a more human-readable format. e.g. 123456789 -> 123M.g    eÍÍArï   ÚBg    €„.AÚMg     @�@ÚK)r  r[   )rr   r   s     rU   Úreadable_numberzEngineWrapper.readable_numberg  s€   € à�SŠ=ˆ=Ý˜F S™L¨!Ñ,Ô,Ð/Ð/Ð/Ð/Ø�SŠ=ˆ=Ý˜F S™L¨!Ñ,Ô,Ð/Ð/Ð/Ð/Ø�SŠ=ˆ=Ý˜F S™L¨!Ñ,Ô,Ð/Ð/Ð/Ð/Ý�6‰{Œ{ÐrW   Ústatr   rî   c           	     ó  ‡ — ‰ j         ‰ j        d„ ‰ j        ˆ fd„‰ j        d„ ‰ j        dœ}d
d	„}t	          t
          t          gt          f         |                     ||¦  «        ¦  «        }t           |||         ¦  «        ¦  «        S )z/Change a value to a more human-readable format.c                ó.   — t          | dz  d¦  «        › d�S ©Né
   rï   r  ©r  ©Úxs    rU   ú<lambda>z1EngineWrapper.to_readable_value.<locals>.<lambda>t  s   € ½5ÀÀRÁÈÑ;KÔ;KÐ8NÐ8NÐ8N€ rW   c                ó4   •— ‰                      | ¦  «        › d�S )NÚnps)r+  )r3  rr   s    €rU   r4  z1EngineWrapper.to_readable_value.<locals>.<lambda>u  s   ø€ ¸×8LÒ8LÈQÑ8OÔ8OÐ5TÐ5TÐ5T€ rW   c                ó.   — t          | dz  d¦  «        › d�S r/  r1  r2  s    rU   r4  z1EngineWrapper.to_readable_value.<locals>.<lambda>v  s   € ½%ÀÀBÁÈÑ:JÔ:JÐ7MÐ7MÐ7M€ rW   )Ú
EvaluationÚWinrateÚHashfullÚNodesÚSpeedÚTbhitsÚCpuloadÚMovetimer3  r   r(   r[   c                ó    — t          | ¦  «        S r•   )r[   r2  s    rU   Úidentityz1EngineWrapper.to_readable_value.<locals>.identityx  s   € Ý�q‘6”6ˆMrW   )r3  r   r(   r[   )	r  r  r+  r&  r"   r   r   r[   rõ   )rr   r,  rî   ÚreadablerA  Úfuncs   `     rU   Úto_readable_valuezEngineWrapper.to_readable_valueq  s¢   ø€ à04Ô0CÐPTÔPaØ.NÐ.NÐY]ÔYmØ+TÐ+TÐ+TÐ+TÐ`dÔ`tØ-MÐ-MÐ[_Ô[mð"oð "oˆð
	ð 	ð 	ð 	õ •H�m˜_­cÐ1Ô2°H·L²LÀÀxÑ4PÔ4PÑQÔQˆÝ�4�4˜˜Tœ
Ñ#Ô#Ñ$Ô$Ð$rW   FÚfor_chatú	list[str]c                óÌ  ‡ ‡‡— ‰ j         o‰ j         d         }|r‰ j         d                              ¦   «         ni Šdd„Št          t          t	          ˆfd	„‰                     ¦   «         D ¦   «         ¦  «        ¦  «        Šd
‰vrd‰d
<   g d¢}|�rHd‰v �rCˆˆ fd„|D ¦   «         }t          d                     |¦  «        ¦  «        t          z   }‰d          	                    ¦   «         }	 t          d                     |¦  «        ¦  «        |z   t          j        k    rG|                     ¦   «          t          d                     |¦  «        ¦  «        |z   t          j        k    °G|d                              d¦  «        r|                     ¦   «          d                     |¦  «        ‰d<   n# t          $ r Y nw xY w‰d         s‰                     d¦  «         ˆˆ fd„|D ¦   «         S )z£
        Get the stats returned by the engine.

        :param for_chat: Whether the stats will be sent to the game chat, which has a 140 character limit.
        rm   r,  r   rf   r   r(   ú"tuple[InfoDictKeys, InfoDictValue]c                óR  — ddddddœ}t          t          |                     | | ¦  «        ¦  «        } | dk    rHt          |t          ¦  «        r3|                     d¦  «        rd	} |                     d
d¦  «        d         }t          t          |                      ¦   «         ¦  «        |fS )NÚwinrateÚPVÚspeedÚ
evaluationrÄ   )r  r  r6  rÌ   r±   Ústringzlichess-bot-source:ÚSourceú:rï   )r"   r   rõ   r–   r[   Ú
startswithÚsplitÚtitle)r,  rf   rB  s      rU   Úto_readable_itemz1EngineWrapper.get_stats.<locals>.to_readable_item‡  sœ   € Ø(°dÀ7ÐUaÐkuÐvÐvˆHÝ� h§l¢l°4¸Ñ&>Ô&>Ñ?Ô?ˆDØ�xÒÐ¥J¨uµcÑ$:Ô$:Ð¸u×?OÒ?OÐPeÑ?fÔ?fÐØ�ØŸš C¨Ñ+Ô+¨AÔ.�Ý� d§j¢j¡l¤lÑ3Ô3°UÐ:Ð:rW   c              3  ó‚   •K  — | ]9\  }} ‰t          t          |¦  «        t          t          |¦  «        ¦  «        V — Œ:d S r•   )r"   r   r   )re   rZ   rf   rT  s      €rU   r™   z*EngineWrapper.get_stats.<locals>.<genexpr>�  sg   øè è € ð &Hð &HÙ*6¨3°ð '7Ð&6µt½LÈ#Ñ7NÔ7NÕPTÕUbÐdiÑPjÔPjÑ&kÔ&kð &Hð &Hð &Hð &Hð &Hð &HrW   rO  rS   )rO  r8  r9  ÚDepthr;  r<  ÚPvrW  c           
     ó€   •— g | ]:}|‰v ¯|d k    ¯|› d‰                      t          t          |¦  «        ‰¦  «        › �‘Œ;S )rW  ú: ©rD  r"   r   ©re   r,  rî   rr   s     €€rU   ú
<listcomp>z+EngineWrapper.get_stats.<locals>.<listcomp>–  s]   ø€ ð Mð Mð MØ!¨d°d¨l¨l¸tÀtº|¸|ð !Ð\Ð\ D×$:Ò$:½4ÅÈdÑ;SÔ;SÐUYÑ$ZÔ$ZÐ\Ð\Ø?K¸|¸|rW   ú, ú ú.c           
     ót   •— g | ]4}|‰v ¯|› d ‰                      t          t          |¦  «        ‰¦  «        › �‘Œ5S )rY  rZ  r[  s     €€rU   r\  z+EngineWrapper.get_stats.<locals>.<listcomp>¤  sN   ø€ ÐvÐvÐvÐX\ÐimÐquÐiuÐiu�4ÐSÐS˜4×1Ò1µ$µ|ÀTÑ2JÔ2JÈDÑQÔQÐSÐSÐiuÐiuÐiurW   )r,  r   rf   r   r(   rH  )rp   r  r"   r   r  r>   r¶   r5   ÚPONDERPV_CHARACTERSrR  r   ÚMAX_CHAT_MESSAGE_LENro   Úendswithrü   )	rr   rE  Ú	can_indexÚstatsÚ	bot_statsÚlen_bot_statsÚ	ponder_pvrî   rT  s	   `      @@rU   r  zEngineWrapper.get_stats~  s<  øøø€ ð Ô(ÐE¨TÔ-AÀ"Ô-Eˆ	Ø?HÐP˜DÔ0°Ô4×9Ò9Ñ;Ô;Ð;Èbˆð	;ð 	;ð 	;ð 	;õ •K¥ð &Hð &Hð &Hð &HØ:>¿*º*¹,¼,ð&Hñ &Hô &Hñ "Hô "Hñ Iô Iˆà˜4ÐÐØ%ˆD�‰NàTÐTÐTˆØñ 	˜ ˜™ðMð Mð Mð Mð MØ%*ðMñ Mô MˆIå §	¢	¨)Ñ 4Ô 4Ñ5Ô5Õ8KÑKˆMØ˜Tœ
×(Ò(Ñ*Ô*ˆIðÝ˜#Ÿ(š( 9Ñ-Ô-Ñ.Ô.°Ñ>ÅÔA]Ò]Ð]Ø—M’M‘O”O�Oõ ˜#Ÿ(š( 9Ñ-Ô-Ñ.Ô.°Ñ>ÅÔA]Ò]Ð]à˜R”=×)Ò)¨#Ñ.Ô.ð $Ø—M’M‘O”O�OØ ŸXšX iÑ0Ô0��T‘
�
øÝð ð ð Ø�ðøøøà˜”:ð Ø—’˜‘”�ØvÐvÐvÐvÐvÐ`eÐvÑvÔvÐvs   Ã(CF* Æ*
F7Æ6F7c                óè   — t           j                             |j        j        |j        j        |j        j        |j        j        ¬¦  «        }| j                             ||j	        j        ¬¦  «         dS )z:Get the opponent's information and sends it to the engine.)r7   rS  ÚratingÚ	is_engine)ÚopponentÚengine_ratingN)
r_   r1   ÚOpponentrl  r7   rS  rj  Úis_botÚsend_opponent_informationÚme)rr   r&   rl  s      rU   Úget_opponent_infozEngineWrapper.get_opponent_info¦  sf   € å”<×(Ò(¨d¬mÔ.@Ø/3¬}Ô/BØ04´Ô0DØ37´=Ô3Gð )ñ Iô Iˆð 	Œ×-Ò-°xÈtÌwÌ~Ð-Ñ^Ô^Ð^Ð^Ð^rW   c                ó&   — | j         j        d         S )zGet the name of the engine.r7   )r1   r¯   r{   s    rU   r7   zEngineWrapper.name®  s   € àŒ{Œ~˜fÔ%Ð%rW   c                óx   — d}| j         j        �+t          | j         j                             ¦   «         ¦  «        }|S )zGet the pid of the engine.ú?)r1   Ú	transportr[   Úget_pid)rr   Úpids     rU   rw  zEngineWrapper.get_pid²  s5   € àˆØŒ;Ô Ð,Ý�d”kÔ+×3Ò3Ñ5Ô5Ñ6Ô6ˆCØˆ
rW   c                ó8   — | j                              ¦   «          dS )zPing the engine.N)r1   rƒ   r{   s    rU   rƒ   zEngineWrapper.ping¹  ó   € àŒ×ÒÑÔÐÐÐrW   c                ól  — |j                              d¦  «        }|j                              d¦  «        }|dk    rt          j        nt          j        }|t
          j        j        k    r| j         	                    |¦  «         dS |t
          j        j
        k    r+|dk    rdnd}| j         	                    |||› d�¦  «         dS |t
          j        j        k    r| j         	                    |dd	d
¦  «         dS |t
          j        j        k    r8|                     d¬¦  «        rdnd}| j         	                    |d|¦  «         dS |t
          j        j        k    r>|r| j         	                    ||d¦  «         dS | j         	                    |dd¦  «         dS | j         	                    |d|¦  «         dS )z™
        Inform engine of the game ending.

        :param game: The final game state from lichess.
        :param board: The final board state.
        ÚstatusÚwinnerÚwhiteÚblackÚWhiteÚBlackz	 resignedNzGame abortedFT)Ú
claim_drawzDraw by agreementzTime forfeiturez#Time out with insufficient material)Ústaterõ   r_   ÚWHITEÚBLACKr   ÚTerminationÚMATEr1   Úsend_game_resultÚRESIGNÚABORTÚDRAWÚis_game_overÚTIMEOUT)rr   r&   r†   Úterminationr}  Úwinning_colorÚresignerÚdraw_reasons           rU   rˆ  zEngineWrapper.send_game_result½  s»  € ð ”j—n’n XÑ.Ô.ˆØ”—’ Ñ)Ô)ˆØ'-°Ò'8Ð'8�œ˜½e¼kˆà�%Ô+Ô0Ò0Ð0ØŒK×(Ò(¨Ñ/Ô/Ð/Ð/Ð/Ø�EÔ-Ô4Ò4Ð4Ø"(¨GÒ"3Ð"3�w�w¸ˆHØŒK×(Ò(¨°À(Ð?UÐ?UÐ?UÑVÔVÐVÐVÐVØ�EÔ-Ô3Ò3Ð3ØŒK×(Ò(¨°°nÀeÑLÔLÐLÐLÐLØ�EÔ-Ô2Ò2Ð2Ø"'×"4Ò"4ÀÐ"4Ñ"EÔ"EÐ^˜$˜$ÐK^ˆKØŒK×(Ò(¨°°kÑBÔBÐBÐBÐBØ�EÔ-Ô5Ò5Ð5Øð aØ”×,Ò,¨U°MÐCTÑUÔUÐUÐUÐUà”×,Ò,¨U°DÐ:_Ñ`Ô`Ð`Ð`Ð`àŒK×(Ò(¨°°kÑBÔBÐBÐBÐBrW   c                ó8   — | j                              ¦   «          dS )zTell the engine to shut down.N)r1   r„   r{   s    rU   r„   zEngineWrapper.quitÚ  rz  rW   N)rT   r   rJ   r   r(   rj   )rT   r   r&   r'   r(   rj   )r(   r)   )r|   r}   r~   r   r€   r�   r(   rj   )r†   r‡   r&   rˆ   r‰   rŠ   r‹   r
   rŒ   r�   rŽ   r\   r�   r\   r�   r�   r‘   r   r’   r�   r(   rj   )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(   rj   )r(   rj   )r  rÍ   r(   r[   )r  r  r(   r[   )r   rÎ   r(   r[   )r,  r   rî   r   r(   r[   )F)rE  r\   r(   rF  )r&   rˆ   r(   rj   ©r(   r[   )r&   rˆ   r†   r‡   r(   rj   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rs   ru   rz   r…   rÁ   rÈ   rê   r¥   rù   rþ   r³   r  r´   r  r  r&  r+  rD  r  rr  r7   rw  rƒ   rˆ  r„   rd   rW   rU   r)   r)   V   s&  € € € € € Ø@Ð@ð&ð &ð &ð &ðð ð ð ðð ð ð ð
=ð =ð =ð =ðL-ð L-ð L-ð L-ð\	ð 	ð 	ð 	ðð ð ð ð>8ð 8ð 8ð 8ð0	;ð 	;ð 	;ð 	;ðð ð ð ð"/ð /ð /ð /ð$'ð 'ð 'ð 'ðð ð ð ð
ð ð ð ð$ð $ð $ð $ð
&ð &ð &ð &ðð ð ð ð%ð %ð %ð %ð&wð &wð &wð &wð &wðP_ð _ð _ð _ð&ð &ð &ð &ðð ð ð ðð ð ð ðCð Cð Cð Cð:ð ð ð ð ð rW   c                  ó$   ‡ — e Zd ZdZdˆ fd„Zˆ xZS )rC   z/The class used to communicate with UCI engines.rO   r   rT   r   rR   ú
int | NonerJ   r   r&   r'   rI   r\   Ú
popen_argsr[   r(   rj   c                óÄ   •— t          ¦   «                              ||¦  «         t          j        j        j        |fd|d|dœ|¤Ž| _        |                      ||¦  «         dS )a   
        Communicate with UCI engines.

        :param commands: The engine path and commands to send to the engine. e.g. ["engines/engine.exe", "--option1=value1"]
        :param options: The options to send to the engine.
        :param stderr: Whether we should silence the stderr.
        :param draw_or_resign: Options on whether the bot should resign or offer draws.
        :param game: The first Game message from the game stream.
        :param debug: Whether to debug or not.
        :param popen_args: The cwd of the engine.
        ç      N@T©ÚtimeoutrI   ÚsetpgrprR   N)Úsuperrs   r_   r1   ÚSimpleEngineÚ	popen_uciru   ©	rr   rO   rT   rR   rJ   r&   rI   r›  Ú	__class__s	           €rU   rs   zUCIEngine.__init__â  sv   ø€ õ 	‰Œ×Ò˜ .Ñ1Ô1Ð1Ý”lÔ/Ô9¸(ð HÈCÐW\ÐfjÐsyð Hð HØ<FðHð HˆŒà�Š�w Ñ%Ô%Ð%Ð%Ð%rW   ©rO   r   rT   r   rR   rš  rJ   r   r&   r'   rI   r\   r›  r[   r(   rj   ©r•  r–  r—  r˜  rs   Ú__classcell__©r¥  s   @rU   rC   rC   ß  sC   ø€ € € € € Ø9Ð9ð&ð &ð &ð &ð &ð &ð &ð &ð &ð &rW   rC   c                  ó$   ‡ — e Zd ZdZdˆ fd„Zˆ xZS )rB   z2The class used to communicate with XBoard engines.rO   r   rT   r   rR   rš  rJ   r   r&   r'   rI   r\   r›  r[   r(   rj   c                ó~  •— t          ¦   «                              ||¦  «         t          j        j        j        |fd|d|dœ|¤Ž| _        t          t          |                     di ¦  «        pi ¦  «        }t          t          j        j	        | j        j
        ¦  «        }	|	j                             dd¦  «        }
t          |
t          ¦  «        rY|
                     d¦  «        }t!          d|¦  «        D ]3}||v r||         |d	|› �<   Œt"                               d
|› d�¦  «         Œ4|                      ||¦  «         dS )a#  
        Communicate with XBoard engines.

        :param commands: The engine path and commands to send to the engine. e.g. ["engines/engine.exe", "--option1=value1"]
        :param options: The options to send to the engine.
        :param stderr: Whether we should silence the stderr.
        :param draw_or_resign: Options on whether the bot should resign or offer draws.
        :param game: The first Game message from the game stream.
        :param debug: Whether to debug or not.
        :param popen_args: The cwd of the engine.
        r�  Trž  ÚegtpathÚegtr^   ú,Nzegtpath zNo paths found for egt type: r_  )r¡  rs   r_   r1   r¢  Úpopen_xboardr"   r   ro   ÚXBoardProtocolr8   Úfeaturesrõ   r–   r[   rR  rá   rH   rI   ru   )rr   rO   rT   rR   rJ   r&   rI   r›  Ú	egt_pathsr8   Úegt_featuresÚegt_types_from_engineÚegt_typer¥  s                €rU   rs   zXBoardEngine.__init__ù  sS  ø€ õ 	‰Œ×Ò˜ .Ñ1Ô1Ð1Ý”lÔ/Ô<¸Xð ZÈsÐZ_ÐimØDJðZð ZØNXðZð ZˆŒå� w§{¢{°9¸bÑ'AÔ'AÐ'GÀRÑHÔHˆ	Ý�œÔ3°T´[Ô5IÑJÔJˆØÔ(×,Ò,¨U°BÑ7Ô7ˆÝ�l¥CÑ(Ô(ð 	NØ$0×$6Ò$6°sÑ$;Ô$;Ð!Ý" 4Ð)>Ñ?Ô?ð Nð N�Ø˜yÐ(Ð(Ø5>¸xÔ5H�GÐ1 xÐ1Ð1Ñ2Ð2å—L’LÐ!LÀÐ!LÐ!LÐ!LÑMÔMÐMÐMØ�Š�w Ñ%Ô%Ð%Ð%Ð%rW   r¦  r§  r©  s   @rU   rB   rB   ö  sC   ø€ € € € € Ø<Ð<ð&ð &ð &ð &ð &ð &ð &ð &ð &ð &rW   rB   c                  ó<   ‡ — e Zd ZdZd%ˆ fd„Zd&d„Zd'd„Zd(d$„Zˆ xZS ))ÚMinimalEnginea  
    Subclass this to prevent a few random errors.

    Even though MinimalEngine extends EngineWrapper,
    you don't have to actually wrap an engine.

    At minimum, just implement `search`,
    however you can also change other methods like
    `notify`, etc.
    rO   r   rT   r   rR   rš  rJ   r   r&   r'   rI   r\   r›  r[   r(   rj   c                ó¤   •— t          ¦   «                              ||¦  «         | j        j        | _        t          | | j        ¬¦  «        | _        dS )zì
        Initialize the values of the engine that all homemade engines inherit.

        :param options: The options to send to the engine.
        :param draw_or_resign: Options on whether the bot should resign or offer draws.
        )r7   N)r¡  rs   r¥  r•  Úengine_nameÚFillerEnginer1   r¤  s	           €rU   rs   zMinimalEngine.__init__#  sG   ø€ õ 	‰Œ×Ò˜ .Ñ1Ô1Ð1Øœ>Ô2ˆÔÝ" 4¨dÔ.>Ð?Ñ?Ô?ˆŒˆˆrW   c                ó   — dS )z@Homemade engines don't have a pid, so we return a question mark.ru  rd   r{   s    rU   rw  zMinimalEngine.get_pid0  s   € àˆsrW   r†   r‡   r¾   rÂ   rë   r½   rì   r   rÊ   c                ó    — t          d¦  «        ‚)z®
        Choose a move.

        The method to be implemented in your homemade engine.
        NOTE: This method must return an instance of "chess.engine.PlayResult"
        z$The search method is not implemented)ÚNotImplementedError)rr   r†   r¾   rë   r½   rì   s         rU   r¥   zMinimalEngine.search4  s   € õ "Ð"HÑIÔIÐIrW   Úmethod_namerª   r   Úkwargsr   r    c                ó   — dS )aÔ  
        Enable the use of `self.engine.option1`.

        The EngineWrapper class sometimes calls methods on "self.engine".

        "self.engine" is a filler property that notifies <self>
        whenever an attribute is called.

        Nothing happens unless the main engine does something.

        Simply put, the following code is equivalent
        self.engine.<method_name>(<*args>, <**kwargs>)
        self.notify(<method_name>, <*args>, <**kwargs>)
        Nrd   )rr   r¾  rª   r¿  s       rU   ÚnotifyzMinimalEngine.notify>  s   € € € rW   r¦  r”  r“  )r¾  r[   rª   r   r¿  r   r(   r    )	r•  r–  r—  r˜  rs   rw  r¥   rÁ  r¨  r©  s   @rU   r·  r·    s�   ø€ € € € € ð	ð 	ð@ð @ð @ð @ð @ð @ðð ð ð ðJð Jð Jð Jðð ð ð ð ð ð ð rW   r·  c                  ó$   — e Zd ZdZddd	„Zdd„ZdS )rº  z�
    Not meant to be an actual engine.

    This is only used to provide the property "self.engine"
    in "MinimalEngine" which extends "EngineWrapper"
    r^   Úmain_enginer·  r7   r[   r(   rj   c                ó4   — d|i| _         || _        || _        dS )z*:param name: The name to send to the chat.r7   N)r¯   r7   rÃ  )rr   rÃ  r7   s      rU   rs   zFillerEngine.__init__X  s"   € à˜4�.ˆŒØˆŒ	Ø&ˆÔÐÐrW   r¾  r    c                ó&   ‡‡— | j         Šdˆˆfd„}|S )	z#Provide the property `self.engine`.rª   r   r¿  r   r(   r    c                 ó&   •—  ‰j         ‰g| ¢R i |¤ŽS r•   )rÁ  )rª   r¿  rÃ  r¾  s     €€rU   Úmethodz(FillerEngine.__getattr__.<locals>.methodc  s(   ø€ ð &�;Ô% kÐC°DÐCÐCÐC¸FÐCÐCÐCrW   )rª   r   r¿  r   r(   r    )rÃ  )rr   r¾  rÇ  rÃ  s    ` @rU   Ú__getattr__zFillerEngine.__getattr__^  s=   øø€ àÔ&ˆð	Dð 	Dð 	Dð 	Dð 	Dð 	Dð 	Dð
 ˆrW   N)r^   )rÃ  r·  r7   r[   r(   rj   )r¾  r[   r(   r    )r•  r–  r—  r˜  rs   rÈ  rd   rW   rU   rº  rº  P  sK   € € € € € ðð ð'ð 'ð 'ð 'ð 'ð
ð 
ð 
ð 
ð 
ð 
rW   rº  z-for-lichess-bot-testing-onlyr7   r[   útype[MinimalEngine]c                óÀ   — ddl }ddlm } |                      t          ¦  «        r)t	          ||                      t          ¦  «        ¦  «        }nt	          || ¦  «        }|S )zØ
    Get the homemade engine with name `name`. e.g. If `name` is `RandomMove` then we will return `homemade.RandomMove`.

    :param name: The name of the homemade engine.
    :return: The engine with this name.
    r   N)r.   )r.   Útest_botrc  Útest_suffixÚgetattrÚremovesuffix)r7   r.   Útest_homemader1   s       rU   rD   rD   n  sf   € ð €O€O€OØ2Ð2Ð2Ð2Ð2Ð2à‡}‚}•[Ñ!Ô!ð )Ý˜¨×(9Ò(9½+Ñ(FÔ(FÑGÔGˆˆå˜ 4Ñ(Ô(ˆØ€MrW   r†   r‡   rˆ   rŽ   r\   r‹   r
   rŒ   r�   r�   r�   útuple[chess.engine.Limit, bool]c                óª   — t          | j        ¦  «        dk     rt          |¦  «        dfS |rt          | ||||¦  «        |fS t	          | |||¦  «        |fS )a¥  
    Determine the game clock settings for the current move.

    :param Board: The current position.
    :param game: Information about the current game.
    :param setup_timer: How much time has passed since receiving the opponent's move.
    :param move_overhead: How much time it takes to communicate with lichess.
    :param can_ponder: Whether the bot is allowed to ponder after choosing a move.
    :param is_correspondence: Whether the current game is a correspondence game.
    :param correspondence_move_time: How much time to use for this move it it is a correspondence game.
    :return: The time to choose a move and whether the bot can ponder after the move.
    rš   F)r¶   r·   Úfirst_move_timeÚsingle_move_timeÚgame_clock_time)r†   r&   rŽ   r‹   rŒ   r�   r�   s          rU   r¤   r¤     sm   € õ& ˆ5ÔÑÔ˜qÒ Ð Ý˜tÑ$Ô$ eÐ+Ð+Øð oÝ  tÐ-EÀ{ÐTaÑbÔbÐdnÐnÐnÝ˜5 $¨°]ÑCÔCÀZÐOÐOrW   úLiteral['wtime', 'btime']c                ó4   — | j         t          j        k    rdndS )z:Return `wtime` if it is white's turn to move else `btime`.ÚwtimeÚbtime©rô   r_   r„  ©r†   s    rU   ÚwbtimerÛ  ™  s   € à”j¥E¤KÒ/Ð/ˆ7ˆ7°WÐ<rW   úLiteral['winc', 'binc']c                ó4   — | j         t          j        k    rdndS )z8Return `winc` if it is white's turn to move else `binc`.ÚwincÚbincrÙ  rÚ  s    rU   Úwbincrà  ž  s   € à”Z¥5¤;Ò.Ð.ˆ6ˆ6°FÐ:rW   Úsearch_timerÂ   c           	     óž  — |                      ¦   «         }||z   }t          t          d¦  «        t          |j        t	          | ¦  «                 ¦  «        |z
  ¦  «        }t          ||¦  «        }t                               dt          |¦  «        › d|j	        › �¦  «         t          j                             t          |¦  «        d¬¦  «        S )a°  
    Calculate time to search in correspondence games.

    :param board: The current positions.
    :param game: The game that the bot is playing.
    :param search_time: How long the engine should search.
    :param setup_timer: How much time has passed since receiving the opponent's move.
    :param move_overhead: The time it takes to communicate between the engine and lichess-bot.
    :return: The time to choose a move.
    rï   úSearching for time ú seconds for game Úcorrespondence©r±   Úclock_id)r°   Úmaxr   rƒ  rÛ  ÚminrH   rî   r   r¯   r_   r1   ÚLimitr   )r†   r&   rá  r‹   rŒ   Úpre_move_timeÚoverheadÚ
clock_times           rU   rÓ  rÓ  £  s®   € ð  ×0Ò0Ñ2Ô2€MØ˜}Ñ,€HÝ•T˜!‘W”W�d 4¤:­f°U©m¬mÔ#<Ñ=Ô=ÀÑHÑIÔI€JÝ�k :Ñ.Ô.€KÝ
‡K‚KÐW¥g¨kÑ&:Ô&:ÐWÐWÈdÌgÐWÐWÑXÔXÐXÝŒ<×Ò¥:¨kÑ#:Ô#:ÐEUÐÑVÔVÐVrW   c                óà   — t          d¦  «        }t                               dt          |¦  «        › d| j        › �¦  «         t
          j                             t          |¦  «        d¬¦  «        S )z¢
    Determine time limit for the first move in the game.

    :param game: The game that the bot is playing.
    :return: The time to choose the first move.
    r0  rã  rä  z
first moveræ  )	r   rH   rî   r   r¯   r_   r1   rê  r   )r&   rá  s     rU   rÒ  rÒ  ·  s_   € õ ˜"‘+”+€KÝ
‡K‚KÐW¥g¨kÑ&:Ô&:ÐWÐWÈdÌgÐWÐWÑXÔXÐXÝŒ<×Ò¥:¨kÑ#:Ô#:À\ÐÑRÔRÐRrW   c                óÒ  — |                      ¦   «         }||z   }t          |j        d         ¦  «        t          |j        d         ¦  «        dœ}t          | ¦  «        }t	          t          d¦  «        ||         |z
  ¦  «        ||<   t
                               dt          |d         ¦  «        › dt          |d         ¦  «        › d|j        › �¦  «         t          j
                             t          |d         ¦  «        t          |d         ¦  «        t          t          |j        d         ¦  «        ¦  «        t          t          |j        d	         ¦  «        ¦  «        d
¬¦  «        S )aw  
    Get the time to play by the engine in realtime games.

    :param board: The current positions.
    :param game: The game that the bot is playing.
    :param setup_timer: How much time has passed since receiving the opponent's move.
    :param move_overhead: The time it takes to communicate between the engine and lichess-bot.
    :return: The time to play a move.
    r×  rØ  )r×  rØ  rï   zSearching for wtime z btime ú
 for game rÞ  rß  z	real time)Úwhite_clockÚblack_clockÚ	white_incÚ	black_incrç  )r°   r   rƒ  rÛ  rè  rH   rî   r   r¯   r_   r1   rê  r   )r†   r&   r‹   rŒ   rë  rì  ÚtimesÚsides           rU   rÔ  rÔ  Ä  s4  € ð  ×0Ò0Ñ2Ô2€MØ˜}Ñ,€HÝ˜4œ: gÔ.Ñ/Ô/½$¸t¼zÈ'Ô?RÑ:SÔ:SÐTÐT€EÝ�%‰=Œ=€DÝ•d˜1‘g”g˜u Tœ{¨XÑ5Ñ6Ô6€Eˆ$�KÝ
‡K‚KÐu¥x°°g´Ñ'?Ô'?ÐuÐuÍÐQVÐW^ÔQ_ÑH`ÔH`ÐuÐuÐlpÔlsÐuÐuÑvÔvÐvÝŒ<×Ò­*°U¸7´^Ñ*DÔ*DÝ*4°U¸7´^Ñ*DÔ*DÝ(2µ4¸¼
À6Ô8JÑ3KÔ3KÑ(LÔ(LÝ(2µ4¸¼
À6Ô8JÑ3KÔ3KÑ(LÔ(LØ'2ð	 ñ 4ô 4ð 4rW   c                ól   — t          | j                             | j        d         › d�¦  «        ¦  «        S )z$Check if the bot was offered a draw.r   Údraw)r\   rƒ  rõ   Úopponent_color)r&   s    rU   r£   r£   Þ  s/   € å�”
—’ $Ô"5°aÔ"8Ð>Ð>Ð>Ñ?Ô?Ñ@Ô@Ð@rW   r¹   rÊ   c           	     óD  — t           j                             dd¦  «        }|j        }|j        dz  dz
  }|rt          | j        ¦  «        |k    r|S | j        rd}n!| j        dk    rdnt          | j        ¦  «        }t          |j        d|¬¦  «         |j                             |¦  «        }|D �]o}t           j                             |¦  «        5 }		 |j        }
|j        }|j        }d	„ |	                     | ¦  «        D ¦   «         }|d
k    r|rt)          |¦  «        n|dk    r|rt+          |¦  «        nd}||z  dz  }|
dk    r|	                     | ¦  «        j        }nE|
dk    r|	                     | |¬¦  «        j        }n"|
dk    r|	                     | |¬¦  «        j        }n# t4          $ r d}Y nw xY wddd¦  «         n# 1 swxY w Y   |�Mt6                               d|› d|› d|j        › �¦  «         t           j                             |dddi¦  «        c S �Œq|S )z Get a move from an opening book.Nrš   rï   Úchess960r_   ÚstandardÚbookrb   c                ó   — g | ]	}|j         ‘Œ
S rd   )Úweight)re   Úentrys     rU   r\  z!get_book_move.<locals>.<listcomp>ú  s   € ÐLÐLÐL¨E˜5œ<ÐLÐLÐLrW   Úsumrè  r  Úweighted_randomÚuniform_random)Úminimum_weightr¼   ú	Got move z from book rð  rN  zlichess-bot-source:Opening Book)r_   r1   Ú
PlayResultÚenabledÚ	max_depthr¶   r·   rû  Úuci_variantr[   r	   rX   rý  rG   r›   Úopen_readerÚ	selectionÚ
min_weightÚnormalizationÚfind_allr  rè  Úweighted_choicerŸ   ÚchoiceÚfindrü   rH   rî   r¯   )r†   r&   r¹   Úno_book_moveÚuse_bookÚmax_game_lengthÚvariantÚbooksrý  Úreaderr  r  r  ÚweightsÚscalarrŸ   s                   rU   rž   rž   ã  s³  € õ ”<×*Ò*¨4°Ñ6Ô6€LØÔ#€HØ"Ô,¨qÑ0°1Ñ4€OØð •s˜5Ô+Ñ,Ô,¨Ò>Ð>ØÐà„~ð YØˆˆà %Ô 1°WÒ <Ð <�*�*Å#ÀeÔFWÑBXÔBXˆå˜Ô,¨f¸'ÐBÑBÔBÐBØÔ×$Ò$ WÑ-Ô-€Eàð fñ fˆÝŒ^×'Ò'¨Ñ-Ô-ð 	°ðØ(Ô2�	Ø)Ô4�
Ø ,Ô :�ØLÐL°V·_²_ÀUÑ5KÔ5KÐLÑLÔL�Ø*7¸5Ò*@Ð*@ÀWÐ*@�#˜g™,œ,˜,Ø*7¸5Ò*@Ð*@ÀWÐ*@�#˜g™,œ,˜,ÐRUð à'¨&Ñ0°3Ñ6�
àÐ 1Ò1Ð1Ø!×1Ò1°%Ñ8Ô8Ô=�D�DØÐ"2Ò2Ð2Ø!Ÿ=š=¨¸z˜=ÑJÔJÔO�D�DØ +Ò-Ð-Ø!Ÿ;š; u¸Z˜;ÑHÔHÔM�DøøÝð ð ð à���ðøøøð!	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð( ÐÝ�KŠKÐN DÐNÐN°TÐNÐNÀTÄWÐNÐNÑOÔOÐOÝ”<×*Ò*¨4°¸ÐBcÐ7dÑeÔeÐeÐeÐeñ ð Ðs7   ÃGÃCF&Æ%GÆ&F5Æ2GÆ4F5Æ5GÇG	ÇG	r‰   rŠ   rº   r»   ú*chess.engine.PlayResult | list[chess.Move]c                óö  — |j         }t          | |||¦  «        \  }}}|�å|j        }	|j        }
|	o|
o|dk    }|j        }|j        }|o|o|dk    }ddddddœ}t          j                             t          j         	                    ||         ¦  «        |j
        ¦  «        |d	<   t          |t          ¦  «        rAt          j                             t          j                             |¦  «        d|||¬
¦  «        S d„ |D ¦   «         S |j        }|j        dz  dz
  }t%          |j        ¦  «        }||k    st(          |j                 |k    r t          j                             dd¦  «        S |j        }|j        }|j        }t2          |ft4          |ft6          |ffD ]X\  }} || |||¦  «        \  }}|r@t          j                             t          j                             |¦  «        d|¦  «        c S ŒYt(          |j        xx         dz  cc<   |j        p|j        p|j        }t(          |j                 |k    r%|r#t:                               d|j        › d�¦  «         t          j                             dd¦  «        S )z“
    Get a move from an online source.

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    Nr   éþÿÿÿé¬&  éô  éþÿÿéTÙÿÿ©rš   rï   r   rm   r  rÌ   ©r½   rµ   c                óL   — g | ]!}t           j                             |¦  «        ‘Œ"S rd   )r_   ÚMoveÚfrom_uci©re   rŸ   s     rU   r\  z#get_online_move.<locals>.<listcomp>*  s(   € Ð@Ð@Ð@¨d•”
×#Ò# DÑ)Ô)Ð@Ð@Ð@rW   rš   rï   z.Will stop using online opening books for game r_  )Úonline_egtbÚget_online_egtb_moverÛ   Úoffer_draw_for_egtb_zerorâ   Úresign_for_egtb_minus_twor_   r1   rò   ÚCprô   r–   r[   r  r$  r%  Úmax_out_of_book_movesr  r¶   r·   r$   r¯   Úchessdb_bookÚlichess_cloud_analysisÚlichess_opening_explorerÚget_chessdb_moveÚget_lichess_cloud_moveÚget_opening_explorer_mover  rH   rî   )r‰   r†   r&   rº   r»   Úonline_egtb_cfgr¼   r  Úcommenträ   Úoffer_draw_for_zeroÚ
offer_drawÚ
can_resignÚresign_on_egtb_lossr®   Úwdl_to_scorer,  Úmax_opening_movesÚ
game_movesÚchessdb_cfgÚlichess_cloud_cfgÚopening_explorer_cfgÚonline_sourcerL   Úused_opening_bookss                            rU   r¢   r¢     sº  € ð 'Ô2€OÝ2°2°u¸dÀOÑTÔTÑ€Iˆs�GØÐØ+Ô>ˆØ0ÔIÐØ#ÐHÐ(;ÐHÀÀqÂˆ
à'Ô6ˆ
Ø0ÔJÐØÐAÐ 3ÐA¸¸rº	ˆà C¨A°4¸UÐCÐCˆÝ œ<×0Ò0µ´·²ÀÈcÔARÑ1SÔ1SÐUZÔU_Ñ`Ô`ˆ�ÑÝ�i¥Ñ%Ô%ð 	<Ý”<×*Ò*­5¬:×+>Ò+>¸yÑ+IÔ+IØ+/Ø+2Ø8BØ4:ð	 +ñ <ô <ð <ð
 AÐ@°iÐ@Ñ@Ô@Ð@à,ÔBÐØ(Ô2°QÑ6¸Ñ:ÐÝ�UÔ%Ñ&Ô&€JØÐ%Ò%Ð%Õ)IÈ$Ì'Ô)RÐVkÒ)kÐ)kÝŒ|×&Ò& t¨TÑ2Ô2Ð2à"Ô/€KØ(Ô?ÐØ+ÔDÐå 0°+Ð>Ý 6Ð8IÐJÝ 9Ð;OÐPðRð Zð ZÑˆ�sð +˜]¨2¨u°d¸CÑ@Ô@Ñˆ	�7Øð 	ZÝ”<×*Ò*­5¬:×+>Ò+>¸yÑ+IÔ+IÈ4ÐQXÑYÔYÐYÐYÐYð	Zõ % T¤WÐ-Ð-Ô-°Ñ2Ð-Ð-Ñ-Ø$Ô,ÐiÐ0AÔ0IÐiÐMaÔMiÐÝ'¨¬Ô0Ð4IÒIÐIÐN`ÐIÝ�ŠÐOÀTÄWÐOÐOÐOÑPÔPÐPÝŒ<×"Ò" 4¨Ñ.Ô.Ð.rW   r<  ú(tuple[str | None, chess.engine.InfoDict]c                ó*  — |j         }t          |j        t          |¦  «                 ¦  «        }t	          |j        ¦  «        }t	          |j        ¦  «        }|r||k     s|j        |k    s|j        dk    rdi fS d}i }	d}
|j	        }ddddœ}t          j        t          ¦  «        5  ||         |                     ¦   «         dd	œ}|                      |
|¬
¦  «        }|d         dk    �r|dk    rß|d         }||j        k    rË|d         }|d         d         }t           j                             t           j                             |¦  «        |j        ¦  «        |	d<   |d         |	d<   t+          t-          t           j        j        |d         ¦  «        ¦  «        |	d<   d|	d<   t2                               d|› d|› d|› d|j        › �¦  «         n-|d         }t2                               d|› d|j        › �¦  «         ddd¦  «         n# 1 swxY w Y   ||	fS )z*Get a move from chessdb.cn's opening book.r_   Núhttps://www.chessdb.cn/cdb.phpÚquerypvÚ	querybestÚquery)ÚbestÚgoodÚallrï   ©Úactionr†   Újson©Úparamsr|  ÚokrG  rÅ   rÌ   r   r   zlichess-bot-source:ChessDBrN  r  z from chessdb.cn (depth: ú	, score: ú) for game rŸ   z from chessdb.cn for game )r  r   rƒ  rÛ  r   r’   Úmax_timeÚclock_initialr	  Úmove_qualityr
  r  rv   ÚfenÚonline_book_getÚ	min_depthr_   r1   rò   r+  rô   r¡   Úmapr$  r%  rH   rî   r¯   )r‰   r†   r&   r<  Úuse_chessdbÚ	time_leftr’   rR  rŸ   r4  ÚsiteÚqualityrK  rN  ÚdatarÅ   rÌ   s                    rU   r0  r0  D  sz  € ð Ô%€KÝ�T”Z¥ u¡¤Ô.Ñ/Ô/€IÝ�{Ô+Ñ,Ô,€HÝ�{Ô+Ñ,Ô,€HØð ˜) hÒ.Ð.°$Ô2DÀxÒ2OÐ2OÐSXÔSdÐhoÒSoÐSoØ�Rˆxˆà€DØ%'€GØ+€DØÔ&€GØØ!Øðð €Fõ 
Ô	�YÑ	'Ô	'ð Sð SØ28¸´/ÈEÏIÊIÉKÌKÐabÐ'cÐ'cˆØ×!Ò! $¨vÐ!Ñ6Ô6ˆØ�Œ>˜TÒ!Ñ!Ø˜&Ò Ð Ø˜Wœ�Ø˜KÔ1Ò1Ð1Ø  œM�EØ œ: aœ=�DÝ',¤|×'<Ò'<½U¼\¿_º_ÈUÑ=SÔ=SÐUZÔU_Ñ'`Ô'`�G˜GÑ$Ø'+¨G¤}�G˜GÑ$Ý$(­­U¬ZÔ-@À$ÀtÄ*Ñ)MÔ)MÑ$NÔ$N�G˜D‘MØ(D�G˜HÑ%Ý—K’KÐ v¨DÐ vÐ vÈ5Ð vÐ vÐ[`Ð vÐ vÐmqÔmtÐ vÐ vÑwÔwÐwøà˜F”|�Ý—’ÐQ¨ÐQÐQÈÌÐQÐQÑRÔRÐRð!Sð Sð Sñ Sô Sð Sð Sð Sð Sð Sð Søøøð Sð Sð Sð Sð$ �ˆ=Ðs   Â%EHÈH
ÈH
r=  c                óÀ  ‡‡— t          |¦  «        }t          |j        |         ¦  «        }t          |j        ¦  «        }t          |j        ¦  «        }|j        }|r||k     s|j        |k    rdi fS d}	i }
|j        }|dk    rdnd}|j	        dk    rdnt          |j	        ¦  «        }t          j        t          ¦  «        5  |                      d|                     ¦   «         ||dœd	¬
¦  «        }d|v�rÐ|d         }|d         }|j        }|j        }||k    �r«||k    �r¤|dk    r|d         d         }n€|d         d         d         Š|d         }|j        Š|dk    r"t'          t)          ˆˆfd„|¦  «        ¦  «        }n!t'          t)          ˆˆfd„|¦  «        ¦  «        }t+          j        |¦  «        }|d                              ¦   «         d         }	|dk    r|d         n|d          }t0          j                             t0          j                             |¦  «        |j        ¦  «        |
d<   |d         |
d<   |d         dz  |
d<   t'          t;          t0          j        j        |d                              ¦   «         ¦  «        ¦  «        |
d<   d|
d<   t@           !                    d|	› d|› d|› d|› d|j"        › �
¦  «         ddd¦  «         n# 1 swxY w Y   |	|
fS ) z-Get a move from the lichess's cloud analysis.NrG  rï   é   r_   rü  z"https://lichess.org/api/cloud-eval)rU  ÚmultiPvr  T©rN  Úauthenticatedr«   rÅ   ÚknodesÚpvsr   Úcpr×  c                ó"   •— | d         ‰‰z
  k    S ©Nre  rd   ©r   Ú	best_evalÚmax_differences    €€rU   r4  z(get_lichess_cloud_move.<locals>.<lambda>�  ó   ø€ °R¸´XÀÈ^ÑA[Ò5[€ rW   c                ó"   •— | d         ‰‰z   k    S rg  rd   rh  s    €€rU   r4  z(get_lichess_cloud_move.<locals>.<lambda>�  rk  rW   ÚmovesrÌ   iè  rÆ   r   z)lichess-bot-source:Lichess Cloud AnalysisrN  r  z% from lichess cloud analysis (depth: rP  z
, knodes: rQ  )#rÛ  r   rƒ  r   r’   rR  r  rS  rT  r	  r[   r
  r  rv   rV  rU  rW  Ú
min_knodesÚmax_score_differencer¡   rá   Úrandomr  rR  r_   r1   rò   r+  rô   rX  r$  r%  rH   rî   r¯   )r‰   r†   r&   r=  rö  rZ  r’   rR  Úuse_lichess_cloudrŸ   r4  r\  Úmultipvr  r]  rÅ   rc  rW  rn  r   rd  rÌ   ri  rj  s                         @@rU   r1  r1  j  sf  øø€ õ �%‰=Œ=€DÝ�T”Z Ô%Ñ&Ô&€IÝÐ(Ô1Ñ2Ô2€HÝÐ(Ô1Ñ2Ô2€HØ)Ô1ÐØð  	¨HÒ 4Ð 4¸Ô8JÈXÒ8UÐ8UØ�Rˆxˆà€DØ%'€GàÔ,€GØ˜fÒ$Ð$ˆaˆa¨!€GØ!Ô-°Ò8Ð8ˆjˆj½cÀ%ÔBSÑ>TÔ>T€Gå	Ô	�YÑ	'Ô	'ð 4ð 4Ø×!Ò!Ð"FØ16·²±´ÈÐ]dÐ)eÐ)eØ04ð "ñ 6ô 6ˆð ˜$ÐÑØ˜”MˆEØ˜(”^ˆFØ)Ô3ˆIØ*Ô5ˆJØ˜	Ò!Ñ! f°
Ò&:Ñ&:Ø˜fÒ$Ð$Ø˜eœ Qœ�B�Bà $ U¤¨A¤¨tÔ 4�IØ˜uœ+�CØ%6Ô%K�NØ˜w’�Ý"¥6Ð*[Ð*[Ð*[Ð*[Ð*[Ð]`Ñ#aÔ#aÑbÔb˜˜å"¥6Ð*[Ð*[Ð*[Ð*[Ð*[Ð]`Ñ#aÔ#aÑbÔb˜Ýœ sÑ+Ô+�BØ˜'”{×(Ò(Ñ*Ô*¨1Ô-�Ø$(¨G¢O O˜˜4œ˜¸"¸T¼(¸�Ý#(¤<×#8Ò#8½¼¿ºÈÑ9OÔ9OÐQVÔQ[Ñ#\Ô#\�˜Ñ Ø#'¨¤=�˜Ñ Ø#'¨¤>°DÑ#8�˜Ñ Ý $¥S­¬Ô)<¸bÀ¼k×>OÒ>OÑ>QÔ>QÑ%RÔ%RÑ SÔ S�˜‘Ø$O�˜Ñ!Ý—’ð 3¨ð 3ð 3ÐSXð 3ð 3Ðchð 3ð 3Ðtzð 3ð 3Ø)-¬ð3ð 3ñ 4ô 4ð 4ð94ð 4ð 4ñ 4ô 4ð 4ð 4ð 4ð 4ð 4ð 4øøøð 4ð 4ð 4ð 4ð> �ˆ=Ðs   ÃHKËKËKr>  c                ó&  — t          |¦  «        }t          |j        |         ¦  «        }t          |j        ¦  «        }t          |j        ¦  «        }|j        }|j        r"||k     s|j        |k    s|dk    r|j	        dk    rdi fS d}	i }
|j	        dk    rdnt          |j	        ¦  «        }t          j        t          ¦  «        5  |dk    r4|                     ¦   «         ddœ}|                      d|d	¬
¦  «        }ddi}
n�|dk    rQ|j        }|s|j        }||                     ¦   «         d|d|dk    rdnddœ}|                      d|d	d	¬¦  «        }ddi}
n6|                     ¦   «         d|dddœ}|                      d|d	¬
¦  «        }ddi}
g }|d         D ]�}|d         |d         z   |d         z   }|d         |d         dz  z   |z  }|dk    rd|z
  }||j        k    r8|                     |j        dk    r|n||j        dk    r|n||d         f¦  «         Œ‚|                     d	¬ ¦  «         |d         d!         }	t*                               d"|	› d#|j        › d$|d         d         › d%|j        › �¦  «         ddd¦  «         n# 1 swxY w Y   |	|
fS )&z+Get a move from lichess's opening explorer.Úmasterr_   Nrü  Úmastersr  )rU  rm  z$https://explorer.lichess.ovh/mastersT)rb  rN  z5lichess-bot-source:Lichess Opening Explorer (Masters)Úplayerr   r×  r~  r  )rv  rU  rm  r  ÚrecentGamesÚcolorz#https://explorer.lichess.ovh/player)Ústreamrb  z4lichess-bot-source:Lichess Opening Explorer (Player))rU  rm  r  ÚtopGamesrw  z$https://explorer.lichess.ovh/lichessz5lichess-bot-source:Lichess Opening Explorer (Lichess)rm  Údrawsç      à?rØ  rï   rJ  r-   )Úreverserš   r  z  from lichess opening explorer (rY  rQ  )rÛ  r   rƒ  r   r’   rR  Úsourcer  rS  r	  r[   r
  r  rv   rU  rV  Úplayer_nameÚusernameÚ	min_gamesr:   ÚsortrH   rî   r¯   )r‰   r†   r&   r>  rö  rZ  r’   rR  r~  rŸ   r4  r  rN  Úresponserv  rm  Úpossible_moveÚgames_playedrJ  s                      rU   r2  r2  ž  s�  € õ �%‰=Œ=€DÝ�T”Z Ô%Ñ&Ô&€IÝÐ+Ô4Ñ5Ô5€HÝÐ+Ô4Ñ5Ô5€HØ!Ô(€FØ Ô(ð ¨I¸Ò,@Ð,@ÀDÔDVÐYaÒDaÐDaÐekÐowÒewÐewØÔ! WÒ,Ð,Ø�Rˆxˆà€DØ%'€GØ!Ô-°Ò8Ð8ˆjˆj½cÀ%ÔBSÑ>TÔ>T€GÝ	Ô	�YÑ	'Ô	'ð  ,ð  ,à�YÒÐØ"ŸYšY™[œ[°3Ð7Ð7ˆFØ×)Ò)Ð*PÐRXÐhlÐ)ÑmÔmˆHØÐ!XÐYˆGˆGØ�xÒÐØ)Ô5ˆFØð 'Øœ�Ø &¨u¯yªy©{¬{ÀSÐU\Ø%&¸DÀGºO¸O°°ÐQXðZð ZˆFà×)Ò)Ð*OÐQWÐ`dÐtxÐ)ÑyÔyˆHØÐ!WÐXˆGˆGà"ŸYšY™[œ[°3À7ÐXYÐjkÐlÐlˆFØ×)Ò)Ð*PÐRXÐhlÐ)ÑmÔmˆHØÐ!XÐYˆGØˆØ% gÔ.ð 		zð 		zˆMØ(¨Ô1°MÀ'Ô4JÑJÈ]Ð[bÔMcÑcˆLØ$ WÔ-°¸gÔ0FÈÑ0KÑKÈ|Ñ[ˆGØ�wŠˆØ˜g™+�ØÐ3Ô=Ò=Ð=ð —’Ð)=Ô)BÀiÒ)OÐ)O˜g˜gÐUaØ.BÔ.GÈ9Ò.TÐ.T˜l˜lÐZaÐcpÐqvÔcwðyñ zô zð zøà�
Š
˜4ˆ
Ñ Ô Ð Ø�QŒx˜Œ{ˆÝ�Šð + ð +ð +ÐFZÔF_ð +ð +ÐchÐijÔckÐlmÔcnð +ð +Ø!%¤ð+ð +ñ 	,ô 	,ð 	,ð? ,ð  ,ð  ,ñ  ,ô  ,ð  ,ð  ,ð  ,ð  ,ð  ,ð  ,øøøð  ,ð  ,ð  ,ð  ,ðD �ˆ=Ðs   ÃF4JÊJÊJr3  ú9tuple[str | list[str] | None, int, chess.engine.InfoDict]c                óÒ  — |j         }t          j        |j        ¦  «        }|j        }t          |j        ¦  «        }t          |j        ¦  «        }|j        t          |¦  «                 }	|rPt          |	¦  «        |k     s=|j        |k    s2|j        dvr|dk    s#|j        dk    r|dk    s||j        k    s|j        rddi fS |j        }
|j        dk    rdnt!          |j        ¦  «        }t#          j        t&          ¦  «        5  |dk    rt)          | |||
|¦  «        cddd¦  «         S |dk    rt+          | |||
¦  «        cddd¦  «         S 	 ddd¦  «         n# 1 swxY w Y   ddi fS )z°
    Get a move from an online egtb (either by lichess or chessdb).

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    ©r_   Ú	antichessÚatomicr   r_   ÚchessdbNéýÿÿÿrü  )r  r_   rß   rà   r~  r   r’   rR  rƒ  rÛ  r   rS  r	  Ú
max_piecesÚcastling_rightsrT  r[   r
  r  rv   Úget_lichess_egtb_moveÚget_chessdb_egtb_move)r‰   r†   r&   r3  Úuse_online_egtbÚpiecesr~  Úminimum_timeÚmaximum_timerZ  r\  r  s               rU   r(  r(  Ó  s'  € ð &Ô-€OÝŒ^˜EœNÑ+Ô+€FØÔ#€FÝ˜?Ô3Ñ4Ô4€LÝ˜?Ô3Ñ4Ô4€LØ”
�6 %™=œ=Ô)€IØð 
Ý�I‰Œ Ò-Ð-ØÔ! LÒ0Ð0ØÔ Ð(HÐHÐHØ˜)Ò#Ð#ØÔ  GÒ+Ð+Ø˜)Ò#Ð#Ø˜Ô2Ò2Ð2ØÔ$ð 3ð �R˜ˆ|ÐàÔ*€GØ!Ô-°Ò8Ð8ˆjˆj½cÀ%ÔBSÑ>TÔ>T€Gå	Ô	�YÑ	'Ô	'ð Cð CØ�YÒÐÝ(¨¨T°5¸'À7ÑKÔKðCð Cð Cð Cñ Cô Cð Cð Cð �YÒÐÝ(¨¨T°5¸'ÑBÔBð	Cð Cð Cð Cñ Cô Cð Cð Cð ðCð Cð Cñ Cô Cð Cð Cð Cð Cð Cð Cøøøð Cð Cð Cð Cð ��Rˆ<Ðs   ÄEÄ(EÅEÅ Er�   c                óp  — t          | ||j        ¦  «        \  }}d}|€t          | ||j        ¦  «        \  }}d}|rÝ|j        }|j        }t          |o|o|dk    ¦  «        }	|j        }
|j        }t          |
o|o|dk    ¦  «        }ddddd	d
œ}t          j
                             t          j
                             ||         ¦  «        | j        ¦  «        |dœ}t          |t          j        ¦  «        r$t          j
                             |d||	|¬¦  «        S |S t          j
                             dd¦  «        S )z�
    Get a move from a local egtb.

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    zlichess-bot-source:Syzygy EGTBNzlichess-bot-source:Gaviota EGTBr   r  r  r  r  r   r!  )rÌ   rN  r"  )Ú
get_syzygyÚsyzygyÚget_gaviotaÚgaviotarÛ   r)  r\   râ   r*  r_   r1   rò   r+  rô   r–   r$  r  )r†   r&   r�   r»   r¼   r  r~  rä   r5  r6  r7  r8  r®   r9  r4  s                  rU   r    r    ø  sL  € õ    t¨_Ô-CÑDÔD�N€IˆsØ-€FØÐÝ$ U¨D°/Ô2IÑJÔJ‰ˆ	�3Ø2ˆØð Ø+Ô>ˆØ0ÔIÐÝ˜.ÐMÐ-@ÐMÀSÈAÂXÑNÔNˆ
à'Ô6ˆ
Ø0ÔJÐÝ�jÐFÐ%8ÐF¸SÀBºYÑGÔGˆØ C¨A°4¸UÐCÐCˆÝ38´<×3HÒ3HÍÌÏÊÐYeÐfiÔYjÑIkÔIkÐmrÔmwÑ3xÔ3xØ4:ð*<ð *<ˆå�i¥¤Ñ,Ô,ð 	oÝ”<×*Ò*¨9°d¸GÐR\ÐgmÐ*ÑnÔnÐnØÐÝŒ<×"Ò" 4¨Ñ.Ô.Ð.rW   c                óš  — t          |                      ¦   «         ¦  «        dk    s| j        rdS t          j        | j        t          j                 ¦  «        }t          j        | j        t          j                 ¦  «        }|dk    s|dk    rdS |                      t          j	        t          j        ¦  «        }|                      t          j	        t          j        ¦  «        }|r|sdS |D ]_}|D ]Z}t          j
        |¦  «        t          j
        |¦  «        k    r.t          j        |¦  «        t          j        |¦  «        k     r  dS Œ[Œ`dS )zWDetermine if a given python-chess board represents an 'op1' 8-piece tablebase position.é   Frš   T)r¶   Ú	piece_maprŽ  r_   rß   Úoccupied_cor„  r…  r’  ÚPAWNÚsquare_fileÚsquare_rank)r†   Úwhite_piece_countÚblack_piece_countÚwhite_pawnsÚblack_pawnsÚwpÚbps          rU   Úis_op1_positionr§    s5  € å
ˆ5�?Š?ÑÔÑÔ Ò"Ð" eÔ&;Ð"Øˆuåœ uÔ'8½¼Ô'EÑFÔFÐÝœ uÔ'8½¼Ô'EÑFÔFÐà˜AÒÐÐ!2°aÒ!7Ð!7Øˆuà—,’,�uœz­5¬;Ñ7Ô7€KØ—,’,�uœz­5¬;Ñ7Ô7€Kàð ˜kð Øˆuàð ð ˆØð 	ð 	ˆBÝÔ  Ñ$Ô$­Ô(9¸"Ñ(=Ô(=Ò=Ð=Å%ÔBSÐTVÑBWÔBWÕZ_ÔZkÐlnÑZoÔZoÒBoÐBoØ�t�t�tøð	ð ˆ5rW   r\  r  c                ój  ‡‡— ddddddddœŠt          j        |j        ¦  «        }|j        dk    rdnd	}|dk     rd
nd}t	          |¦  «        }||k    �rÛ|dk     s|�rÒ|                      d|› �d|                     ¦   «         id¬¦  «        }	|dk    r–|	d         d         d         }
‰|	d         d         d                  dz  }|	d         d         |         dz  }|	d         d         d         }|r|dz  }t                               d|
› d|› d|› d|› d|› d|j	        › �¦  «         �n ‰|	d         d         d                  dz  Šd&ˆˆfd„}t          t          ||	d         ¦  «        ¦  «        }t          |¦  «        dk    r:d „ |D ¦   «         }‰}t                               d!|› d|j	        › �¦  «         ||d"d#ifS |d         }|d         }
‰|d                  dz  }||         dz  }|d         }|r|dz  }t                               d|
› d|› d|› d|› d|› d|j	        › �¦  «         |
|d"d#ifS d$d%i fS )'z‘
    Get a move from lichess's egtb.

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    r  rm   r   rï   rš   )Úlossz
maybe-losszblessed-lossrø  z
cursed-winz	maybe-winÚwinr_   r›  rh   ÚdtzÚdtczhttps://tablebase.lichess.ovh/rU  Tra  rG  rm  r-   ÚcategoryÚdtmr  z" from tablebase.lichess.ovh (wdl: r]  rY  ú, dtm: rQ  r„  r   r(   r\   c                ó.   •— ‰| d                  dz  ‰k    S )Nr­  rm   rd   )r„  Úbest_wdlÚname_to_wlds    €€rU   Úgood_enoughz*get_lichess_egtb_move.<locals>.good_enoughO  s   ø€ Ø" =°Ô#<Ô=ÀÑBÀhÒNÐNrW   c                ó   — g | ]
}|d          ‘ŒS ©r-   rd   r&  s     rU   r\  z)get_lichess_egtb_move.<locals>.<listcomp>T  ó   € ÐDÐDÐD¨T˜T %œ[ÐDÐDÐDrW   z2Suggesting moves from tablebase.lichess.ovh (wdl: rN  zlichess-bot-source:Lichess EGTBNrŒ  )r„  r   r(   r\   )r_   rß   rà   r	  r§  rV  rU  rH   rî   r¯   r¡   rá   r¶   )r‰   r&   r†   r\  r  r’  r�  ÚmetricÚis_op1r]  rŸ   r  r«  r®  r³  Úpossible_movesÚ	move_listr¼   r±  r²  s                     @@rU   r�  r�  .  sL  øø€ ð Ø!#Ø#%ØØ!"Ø !Øðð €Kõ Œ^˜EœNÑ+Ô+€FØÔ'¨7Ò2Ð2��¸€JØ-3°aªZ¨Z E E¸U€FÝ˜UÑ#Ô#€FØ�ÒÑ ¨!¢ ¨v¡Ø×!Ò!Ð"LÀ7Ð"LÐ"LØ*/°·²±´Ð)=ÈTð "ñ Sô Sˆà�fÒÐØ˜”= Ô# EÔ*ˆDØ˜d 7œm¨AÔ.¨zÔ:Ô;¸bÑ@ˆCØ�w”- Ô" 6Ô*¨RÑ/ˆCØ�w”- Ô" 5Ô)ˆCØð Ø�r‘	�Ý�KŠKð / Dð /ð /ÈCð /ð /ÐSYð /ð /Ð]`ð /ð /Ðilð /ð /Ø%)¤Wð/ð /ñ 0ô 0ð 0ñ 0ð # 4¨¤=°Ô#3°JÔ#?Ô@À2ÑEˆHðOð Oð Oð Oð Oð Oð Oõ "¥&¨°d¸7´mÑ"DÔ"DÑEÔEˆNÝ�>Ñ"Ô" QÒ&Ð&ØDÐD°^ÐDÑDÔD�	Ø�Ý—’ÐjÐQTÐjÐjÐaeÔahÐjÐjÑkÔkÐkØ  #¨Ð2SÐ'TÐTÐTà*¨1Ô-�	Ø  Ô'�Ø! )¨JÔ"7Ô8¸2Ñ=�Ø Ô'¨"Ñ,�Ø Ô&�Øð Ø˜2‘I�CÝ—’ð 3¨ð 3ð 3ÐPSð 3ð 3ÐW]ð 3ð 3Ðadð 3ð 3Ðmpð 3ð 3Ø)-¬ð3ð 3ñ 4ô 4ð 4ð �S˜8Ð%FÐGÐGÐGØ��Rˆ<ÐrW   c           
     ó´  ‡‡— d!d„Šd!d„}|dk    rdnd}|                       d	||                     ¦   «         d
dœ¬¦  «        }|d         dk    �r†|dk    rY|d         }|d         d         } ‰|¦  «        }	 ||¦  «        }
t                               d|› d|	› d|
› d|j        › �¦  «         �n  ‰|d         d         d         ¦  «        Šd"ˆˆfd„}t          t          |t          t
          t                   |d         ¦  «        ¦  «        ¦  «        }t          |¦  «        d
k    rO ‰|d         d         ¦  «        }	d„ |D ¦   «         }t                               d|	› d|j        › �¦  «         ||	ddifS |d         }|d         }|d         } ‰|¦  «        }	 ||¦  «        }
t                               d|› d|	› d|
› d|j        › �¦  «         ||	ddifS dd i fS )#z‘
    Get a move from chessdb's egtb.

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    rÌ   rÎ   r(   c                ó(   — t          g d¢d| ¦  «        S )N))éà±ÿÿr—   r  )r   r—   rm   ©r   Úir   )é N  r¿  rï   rš   ©Úpiecewise_functionrÒ   s    rU   Úscore_to_wdlz+get_chessdb_egtb_move.<locals>.score_to_wdln  s*   € Ý!ð #4ð #4ð #4ð 67¸ñ?ô ?ð 	?rW   c           	     óV   — t          ddd| z
  fddd| z
  fdddd| z
  fgd| z
  | ¦  «        S )	Nr½  r—   iÐŠÿÿr   r¾  rÀ  r¿  i0u  rÁ  rÒ   s    rU   Úscore_to_dtzz+get_chessdb_egtb_move.<locals>.score_to_dtzt  sW   € Ý! F¨C°¸%±Ð#@Ø$% s¨F°U©NÐ#;Ø#.Ø$)¨3°¸±Ð#>ð#@ð BGÈÁÐPUñWô Wð 	WrW   rG  rD  ÚqueryallrC  rï   rJ  rM  r|  rO  r   r   r  z from chessdb.cn (wdl: ú, dtz: rQ  rm  rŸ   r   r\   c                ó.   •—  ‰| d         ¦  «        ‰k    S )NrÌ   rd   )rŸ   r±  rÃ  s    €€rU   r³  z*get_chessdb_egtb_move.<locals>.good_enough‡  s   ø€ Ø#�| D¨¤MÑ2Ô2°hÒ>Ð>rW   c                ó   — g | ]
}|d          ‘ŒS rµ  rd   r&  s     rU   r\  z)get_chessdb_egtb_move.<locals>.<listcomp>�  r¶  rW   z,Suggesting moves from from chessdb.cn (wdl: rN  zlichess-bot-source:ChessDB EGTBr-   NrŒ  )rÌ   rÎ   r(   rÎ   )rŸ   r   r(   r\   )
rV  rU  rH   rî   r¯   r¡   rá   r"   r   r¶   )r‰   r&   r†   r\  rÅ  rK  r]  rÌ   rŸ   r  r«  r³  r¹  rº  r¼   r±  rÃ  s                  @@rU   r�  r�  g  s}  øø€ ð?ð ?ð ?ð ?ðWð Wð Wð Wð " VÒ+Ð+ˆYˆY°€FØ×ÒÐ>Ø06ÀÇÂÁÄÐVWÐ%XÐ%Xð ñ Zô Z€DàˆH„~˜ÒÑØ�fÒÐØ˜”MˆEØ˜”:˜a”=ˆDØ�,˜uÑ%Ô%ˆCØ�,˜uÑ%Ô%ˆCÝ�KŠKÐf DÐfÐfÀÐfÐfÈSÐfÐfÐ]aÔ]dÐfÐfÑgÔgÐgÑgà#�| D¨¤M°!Ô$4°WÔ$=Ñ>Ô>ˆHð?ð ?ð ?ð ?ð ?ð ?ð ?õ "¥&¨µd½4ÅÔ;PÐRVÐW^ÔR_Ñ6`Ô6`Ñ"aÔ"aÑbÔbˆNÝ�>Ñ"Ô" QÒ&Ð&Ø"�l >°!Ô#4°WÔ#=Ñ>Ô>�ØDÐD°^ÐDÑDÔD�	Ý—’ÐdÈ3ÐdÐdÐ[_Ô[bÐdÐdÑeÔeÐeØ  #¨Ð2SÐ'TÐTÐTà*¨1Ô-�	Ø! 'Ô*�Ø  Ô'�Ø"�l 5Ñ)Ô)�Ø"�l 5Ñ)Ô)�Ý—’Ðj¨ÐjÐjÀSÐjÐjÐQTÐjÐjÐaeÔahÐjÐjÑkÔkÐkà�S˜8Ð%FÐGÐGÐGØ��Rˆ<ÐrW   Ú
syzygy_cfgú0tuple[chess.Move | list[chess.Move] | None, int]c                óf  ‡‡— |j         r+t          j        | j        ¦  «        |j        k    s	| j        dvrdS |j        }t          j                             |j	        d         ¦  «        5 }|j	        dd…         D ]}| 
                    |¦  «         Œ	 t          | t          |¦  «        }t          t          t          |                     ¦   «         ¦  «        ¦  «        Šˆfd„|                     ¦   «         D ¦   «         }|dk    rTt%          |¦  «        dk    rAd„ |D ¦   «         }t&                               d	‰› d
|j        › �¦  «         |‰fcddd¦  «         S t-          |t/          d¦  «        ¬¦  «        d         Šˆfd„|D ¦   «         }	t1          j        |	¦  «        }t&                               d|                     ¦   «         › d‰› d‰› d
|j        › �¦  «         |‰fcddd¦  «         S # t6          $ �r0 	 t          | d„ |¦  «        }t9          t          |                     ¦   «         ¦  «        ¦  «        Šˆfd„|                     ¦   «         D ¦   «         }
t&                               |dk    rdnd¦  «         t%          |
¦  «        dk    r(|
}t&                               d	‰› d
|j        › �¦  «         nB|
d         }t&                               d|                     ¦   «         › d‰› d
|j        › �¦  «         |‰fcY cddd¦  «         S # t6          $ r Y Y ddd¦  «         dS w xY ww xY w# 1 swxY w Y   dS )z•
    Get a move from local syzygy egtbs.

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    rˆ  ©NrŒ  r   rï   Nc                óD   •— g | ]\  }}t          |¦  «        ‰k    ¯||f‘ŒS rd   )Ú
dtz_to_wdl)re   rŸ   r«  r±  s      €rU   r\  zget_syzygy.<locals>.<listcomp>³  s3   ø€ ÐdÐdÐd©)¨$°Í
ÐSVÉÌÐ[cÒHcÐHc˜4 ˜+ÐHcÐHcÐHcrW   Úsuggestc                ó   — g | ]\  }}|‘ŒS rd   rd   )re   Ú
chess_mover«  s      rU   r\  zget_syzygy.<locals>.<listcomp>µ  s   € ÐEÐEÐE¡ z°3˜
ÐEÐEÐErW   z#Suggesting moves from syzygy (wdl: rQ  rb   c                ó&   •— g | ]\  }}|‰k    ¯|‘ŒS rd   rd   )re   rÒ  r«  Úbest_dtzs      €rU   r\  zget_syzygy.<locals>.<listcomp>º  s#   ø€ ÐZÐZÐZ©¨°SÈ#ÐQYÊ/È/˜*È/È/È/rW   r  z from syzygy (wdl: rÇ  c                ó.   — |                       |¦  «         S r•   )Ú	probe_wdl)Ú	tablebaseÚbs     rU   r4  zget_syzygy.<locals>.<lambda>Á  s   € È	×H[ÒH[Ð\]ÑH^ÔH^ÐG^€ rW   c                ó&   •— g | ]\  }}|‰k    ¯|‘ŒS rd   rd   )re   rÒ  r  r±  s      €rU   r\  zget_syzygy.<locals>.<listcomp>Ã  s)   ø€ Ð#gÐ#gÐ#g±?°:¸sÐWZÐ^fÒWfÐWf JÐWfÐWfÐWfrW   rG  z\Found moves using 'move_quality'='suggest'. We didn't find an '.rtbz' file for this endgame.r^   )r  r_   rß   rà   r�  r	  rT  r—  Úopen_tablebaseÚpathsÚadd_directoryÚscore_syzygy_movesÚ
dtz_scorerrè  rX  rÏ  Úvaluesr>   r¶   rH   rî   r¯   ré  r   rp  r  r-   ÚKeyErrorrÎ   rI   )r†   r&   rÊ  rT  r×  r3   rm  Ú
good_movesrŸ   Ú
best_movesÚgood_chess_movesrÔ  r±  s              @@rU   r–  r–  œ  s  øø€ ð Ôð ÝŒ~˜eœnÑ-Ô-°
Ô0EÒEÐEØÔ Ð(HÐHÐHØˆxð Ô*€Lå	Œ×	$Ò	$ ZÔ%5°aÔ%8Ñ	9Ô	9ð # ¸YØÔ$ Q R RÔ(ð 	*ð 	*ˆDØ×#Ò# DÑ)Ô)Ð)Ð)ð	 Ý& u­j¸)ÑDÔDˆEå�3�z¨5¯<ª<©>¬>Ñ:Ô:Ñ;Ô;ˆHØdÐdÐdÐd°u·{²{±}´}ÐdÑdÔdˆJØ˜yÒ(Ð(­S°©_¬_¸qÒ-@Ð-@ØEÐE¸*ÐEÑEÔE�Ý—’Ð`À(Ð`Ð`ÐW[ÔW^Ð`Ð`ÑaÔaÐaØ˜X�~ð# ð # ð # ð # ñ # ô # ð # ð # õ ˜:­:°a©=¬=Ð9Ñ9Ô9¸!Ô<ˆHØZÐZÐZÐZ¸JÐZÑZÔZˆJÝ”= Ñ,Ô,ˆDÝ�KŠKÐr D§H¢H¡J¤JÐrÐrÀ8ÐrÐrÐT\ÐrÐrÐimÔipÐrÐrÑsÔsÐsØ˜�>ð%# ð # ð # ð # ñ # ô # ð # ð # øõ& ð 	 ñ 	 ð 	 ð Ý*¨5Ð2^Ð2^Ð`iÑjÔj�Ý�s 5§<¢<¡>¤>Ñ2Ô2Ñ3Ô3�Ø#gÐ#gÐ#gÐ#gÀeÇkÂkÁmÄmÐ#gÑ#gÔ#gÐ Ý—’Ø ,°Ò 6Ð 6ð |Ð{Ø<>ñ@ô @ð @åÐ'Ñ(Ô(¨1Ò,Ð,Ø+�DÝ—K’KÐ dÀhÐ dÐ dÐ[_Ô[bÐ dÐ dÑeÔeÐeÐeà+¨AÔ.�DÝ—K’KÐ i¨D¯HªH©J¬JÐ iÐ iÈ8Ð iÐ iÐ`dÔ`gÐ iÐ iÑjÔjÐjØ˜X�~Ð%Ð%ðC# ð # ð # ð # ñ # ô # ð # ð # øõD ð  ð  ð  Ø�xðG# ð # ð # ñ # ô # ð # ð # ð # ðD øøøð	 øøøð'# ð # ð # ð # øøøð # ð # ð # ð # ð # ð # s]   Á((L&ÂB7G(ÅBG(Ç(L#Ç4DLË6L#Ë7L&Ì
LÌL#ÌL&ÌLÌL#Ì#L&Ì&L*Ì-L*r×  úchess.syzygy.Tablebaseúint | floatc                ó°   — |                       |¦  «         }|j        s|s|nt          j        d|¦  «        }||rt          j        |j        |¦  «        ndz   S )zƒ
    Score a position based on a syzygy DTZ egtb.

    For a zeroing move (capture or pawn move), a DTZ of +/-0.5 is returned.
    r|  r   )Ú	probe_dtzÚhalfmove_clockÚmathÚcopysign)r×  r†   r«  s      rU   rÞ  rÞ  Ñ  s`   € ð "×+Ò+¨EÑ2Ô2Ð2€CØÔ%Ð
L¨SÐ
Lˆ#ˆ#µd´mÀBÈÑ6LÔ6L€CØ¸cÐH•$”- Ô 4°cÑ:Ô:Ð:ÀqÑIÐIrW   r«  ÚfloatrÎ   c                ó(   — t          g d¢d| ¦  «        S )zÑ
    Convert DTZ scores to syzygy WDL scores.

    A DTZ of +/-100 returns a draw score of +/-1 instead of a win/loss score of +/-2 because
    a 50-move draw can be forced before checkmate can be forced.
    )©éœÿÿÿr¿  rm   )r   r—   r  r¾  )r  r—   rš   rï   rÁ  )r«  s    rU   rÏ  rÏ  Ü  s   € õ ÐYÐYÐYÐ[\Ð^aÑbÔbÐbrW   Úgaviota_cfgc                óð  ‡‡— |j         r-t          j        | j        ¦  «        |j        k    s| j        dk    rdS |j        }|j        }t          j         	                    |j
        d         ¦  «        5 }|j
        dd…         D ]}|                     |¦  «         Œ	 t          | t          |¦  «        }t          t          t           |                     ¦   «         ¦  «        ¦  «        Šˆfd„|                     ¦   «         D ¦   «         }t'          |t)          d¦  «        ¬¦  «        d         Št+          ‰|¦  «        }	|dk    rŸt-          |‰|¦  «        }
t/          |
¦  «        dk    r2d	„ |
D ¦   «         }t0                               d
|	› d|j        › �¦  «         n«|
d         \  }}t0                               d|                     ¦   «         › d|	› d|› d|j        › �¦  «         nbˆfd„|D ¦   «         }
t9          j        |
¦  «        \  }}t0                               d|                     ¦   «         › d|	› d|› d|j        › �¦  «         ||	fcddd¦  «         S # t<          $ r Y ddd¦  «         dS w xY w# 1 swxY w Y   dS )z–
    Get a move from local gaviota egtbs.

    If `move_quality` is `suggest`, then it will return a list of moves for the engine to choose from.
    r_   rÍ  r   rï   Nc                óD   •— g | ]\  }}t          |¦  «        ‰k    ¯||f‘ŒS rd   )Údtm_to_gaviota_wdl)re   rŸ   r®  r±  s      €rU   r\  zget_gaviota.<locals>.<listcomp>  s6   ø€ ÐlÐlÐl©)¨$°ÕHZÐ[^ÑH_ÔH_ÐckÒHkÐHk˜4 ˜+ÐHkÐHkÐHkrW   rb   rÐ  c                ó   — g | ]\  }}|‘ŒS rd   rd   )re   rÒ  r®  s      rU   r\  zget_gaviota.<locals>.<listcomp>  s   € ÐIÐIÐI©?¨:°s˜JÐIÐIÐIrW   z+Suggesting moves from gaviota (pseudo wdl: rQ  r  z from gaviota (pseudo wdl: r¯  c                ó*   •— g | ]\  }}|‰k    ¯||f‘ŒS rd   rd   )re   rŸ   r®  Úbest_dtms      €rU   r\  zget_gaviota.<locals>.<listcomp>  s'   ø€ ÐYÐYÐY©i¨d°CÈÐPXÊÈ˜t S˜kÈÈÈrW   )r  r_   rß   rà   r�  r	  rT  Úmin_dtm_to_consider_as_wdl_1r™  rÚ  rÛ  rÜ  Úscore_gaviota_movesÚ
dtm_scorerrè  rX  rò  rß  r>   ré  r   Ú
dtm_to_wdlÚgood_enough_gaviota_movesr¶   rH   rî   r¯   r-   rp  r  rà  )r†   r&   rï  rT  rö  r×  r3   rm  rá  Ú
pseudo_wdlrâ  rŸ   r®  rõ  r±  s                @@rU   r˜  r˜  æ  s  øø€ ð Ôð ÝŒ~˜eœnÑ-Ô-°Ô0FÒFÐFØÔ  GÒ+Ð+Øˆxð Ô+€Lð $/Ô#KÐ å	Œ×	%Ò	% kÔ&7¸Ô&:Ñ	;Ô	;ð ¸yØÔ% a b bÔ)ð 	*ð 	*ˆDØ×#Ò# DÑ)Ô)Ð)Ð)ð	Ý'¨­z¸9ÑEÔEˆEå�3Õ1°5·<²<±>´>ÑBÔBÑCÔCˆHØlÐlÐlÐl°u·{²{±}´}ÐlÑlÔlˆJÝ˜:­:°a©=¬=Ð9Ñ9Ô9¸!Ô<ˆHå# HÐ.JÑKÔKˆJØ˜yÒ(Ð(Ý6°zÀ8ÐMiÑjÔj�
Ý�z‘?”? QÒ&Ð&ØIÐI¸jÐIÑIÔI�DÝ—K’KÐ nÈjÐ nÐ nÐeiÔelÐ nÐ nÑoÔoÐoÐoà *¨1¤‘I�D˜#Ý—K’Kð !7¨D¯HªH©J¬Jð !7ð !7ÐS]ð !7ð !7Ðfið !7ð !7Ø-1¬Wð!7ð !7ñ 8ô 8ð 8ð 8ð ZÐYÐYÐY¸:ÐYÑYÔY�
Ý"œM¨*Ñ5Ô5‘	��cÝ—’Ð{¨¯ª©
¬
Ð{Ð{ÈzÐ{Ð{ÐbeÐ{Ð{ÐrvÔryÐ{Ð{Ñ|Ô|Ð|Ø˜Ð#ð5ð ð ð ñ ô ð ð øõ6 ð 	ð 	ð 	Øð9ð ð ñ ô ð ð ð ð6	øøøð7ð ð ð øøøð ð ð ð ð ð s1   Á1(I+ÂF(IÉ
I(ÉI+É'I(É(I+É+I/É2I/ú=chess.gaviota.NativeTablebase | chess.gaviota.PythonTablebasec                óŠ   — |                       |¦  «         }|t          |rt          j        |j        |¦  «        nd¦  «        z   S )z-Score a position based on a gaviota DTM egtb.r   )Ú	probe_dtmrÎ   ré  rê  rè  )r×  r†   r®  s      rU   rø  rø    sD   € à×Ò˜uÑ%Ô%Ð
%€CØ•ÀÐK•T”] 5Ô#7¸Ñ=Ô=Ð=È!ÑLÔLÑLÐLrW   r®  c                ó(   — t          ddgd| ¦  «        S )z)Convert DTM scores to gaviota WDL scores.)rm   r¿  rm   r¾  rï   rÁ  )r®  s    rU   rò  rò  "  s   € å˜}¨kÐ:¸A¸sÑCÔCÐCrW   rö  c                ó2   — t          ddd|ddfgd| ¦  «        S )z(Convert DTM scores to syzygy WDL scores.rí  )rm   r¿  r  r¾  r—   rš   rï   rÁ  )r®  rö  s     rU   rù  rù  '  s+   € õ ˜°¸{ÐMiÐknÐpqÐLrÐsÐuvÐx{Ñ|Ô|Ð|rW   rá  úlist[tuple[chess.Move, int]]rõ  c                ó¢   ‡— |dk     rd„ | D ¦   «         S |‰k     rˆfd„| D ¦   «         S |‰ k    rˆfd„| D ¦   «         S |dk    rd„ | D ¦   «         S | S )a:  
    Get the moves that are good enough to consider.

    :param good_moves: All the moves to choose from.
    :param best_dtm: The best DTM score of a move.
    :param min_dtm_to_consider_as_wdl_1: The minimum DTM score to consider as WDL=1.
    :return: A list of the moves that are good enough to consider.
    r  c                ó(   — g | ]\  }}|d k     ¯||f‘ŒS )r  rd   ©re   rŸ   r®  s      rU   r\  z-good_enough_gaviota_moves.<locals>.<listcomp><  s%   € ÐEÐEÐE¡	  c¸3Àº9¸9��s�¸9¸9¸9rW   c                ó*   •— g | ]\  }}|‰k     ¯||f‘ŒS rd   rd   ©re   rŸ   r®  rö  s      €rU   r\  z-good_enough_gaviota_moves.<locals>.<listcomp>A  s,   ø€ Ð^Ð^Ð^¡	  c¸3ÐA]Ò;]Ð;]��s�Ð;]Ð;]Ð;]rW   c                ó,   •— g | ]\  }}|‰ k    ¯||f‘ŒS rd   rd   r  s      €rU   r\  z-good_enough_gaviota_moves.<locals>.<listcomp>E  s/   ø€ Ð`Ð`Ð`¡	  c¸3ÐC_ÐB_Ò;_Ð;_��s�Ð;_Ð;_Ð;_rW   rî  c                ó(   — g | ]\  }}|d k    ¯||f‘ŒS )rî  rd   r  s      rU   r\  z-good_enough_gaviota_moves.<locals>.<listcomp>I  s%   € ÐGÐGÐG¡	  c¸3À$º;¸;��s�¸;¸;¸;rW   rd   )rá  rõ  rö  s     `rU   rú  rú  .  s¢   ø€ ð �#‚~€~ð FÐE¨ZÐEÑEÔEÐEØÐ.Ò.Ð.ð _Ð^Ð^Ð^¨ZÐ^Ñ^Ô^Ð^ØÐ0Ð0Ò0Ð0ð aÐ`Ð`Ð`¨ZÐ`Ñ`Ô`Ð`Ø�4ÒÐð HÐG¨ZÐGÑGÔGÐGØÐrW   Úrange_definitionsú*list[tuple[float, Literal['e', 'i'], int]]Ú
last_valueÚpositionc                óD   — | D ]\  }}}||k     s|dk    r
||k    r|c S Œ|S )a$  
    Return a value according to a position argument.

    This function is meant to replace if-elif-else blocks that turn ranges into discrete values.
    Each tuple in the list has three parts: an upper limit, and inclusive/exclusive indicator, and
    a value. For example,
    `piecewise_function([(-20000, "e", 2), (0, "e" -1), (0, "i", 0), (20000, "i", 1)], 2, score)` is equivalent to:

    if score < -20000:
        return -2
    elif score < 0:
        return -1
    elif score <= 0:
        return 0
    elif score <= 20000:
        return 1
    else:
        return 2

    Arguments:
    range_definitions:
        A list of tuples with the first element being the inclusive right border of region and the second
        element being the associated value. An element of this list (a, "i", b) corresponds to an
        inclusive limit and is equivalent to
            if x <= a:
                return b
        where x is the value of the position argument. An element of the form (a, "e", b) corresponds to
        an exclusive limit and is equivalent to
            if x < a:
                return b
        For correct operation, this argument should be sorted by the first element. If two ranges have the
        same border, one with "e" and the other with "i", the "e" element should be first.
    last_value:
        If the position argument does not fall in any of the ranges in the range_definition argument,
        return this value.
    position:
        The value that will be compared to the first element of the range_definitions tuples.

    r¿  rd   )r	  r  r  ÚborderÚinc_excrf   s         rU   rÂ  rÂ  M  sH   € ðR #4ð ð Ñˆ�˜Ø�fÒÐ ¨C¢ °HÀÒ4FÐ4FØˆLˆLˆLøØÐrW   ÚscorerúsCallable[[chess.syzygy.Tablebase, chess.Board], int] | Callable[[chess.syzygy.Tablebase, chess.Board], int | float]údict[chess.Move, int | float]c                óŽ   — i }| j         D ]:}|                      |¦  «          ||| ¦  «        ||<   |                      ¦   «          Œ;|S )z'Score all the moves using syzygy egtbs.©Úlegal_movesÚpushro   ©r†   r  r×  rm  rŸ   s        rU   rÝ  rÝ  |  óV   € ð
 €EØÔ!ð ð ˆØ�
Š
�4ÑÔÐØ�f˜Y¨Ñ.Ô.ˆˆd‰Ø�	Š	‰ŒˆˆØ€LrW   ú[Callable[[chess.gaviota.NativeTablebase | chess.gaviota.PythonTablebase, chess.Board], int]údict[chess.Move, int]c                óŽ   — i }| j         D ]:}|                      |¦  «          ||| ¦  «        ||<   |                      ¦   «          Œ;|S )z(Score all the moves using gaviota egtbs.r  r  s        rU   r÷  r÷  ‰  r  rW   r•   )r%   r   r&   r'   r(   r)   )rX   r   r(   r   )r7   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ˆ   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&   rˆ   r<  r   r(   rA  )
r‰   rŠ   r†   r‡   r&   rˆ   r=  r   r(   rA  )
r‰   rŠ   r†   r‡   r&   rˆ   r>  r   r(   rA  )
r‰   rŠ   r†   r‡   r&   rˆ   r3  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‡   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á  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  )er˜  Ú
__future__r   r2   Úchess.enginer_   Úchess.polyglotÚchess.syzygyÚchess.gaviotar@   ÚloggingÚdatetimer±   rp  ré  r
  Úcollectionsr   Úcollections.abcr   Úlibr   r   Ú
lib.configr   r	   Ú	lib.timerr
   r   r   r   r   r   Úlib.lichess_typesr   r   r   r   r   r   r   r   r   r   r   r   r   r   Úextra_game_handlersr   Úoperatorr   Útypingr    r!   r"   Útypesr#   Ú	getLoggerr•  rH   r$   Ú__annotations__rV   rF   ra  r)   rC   rB   r·  rº  rÌ  rD   r¤   rÛ  rà  rÓ  rÒ  rÔ  r£   rž   r¢   r0  r1  r2  r(  r    r§  r�  r�  r–  rÞ  rÏ  r˜  rø  rò  rù  rú  rÂ  rÝ  r÷  rd   rW   rU   ú<module>r/     s  ðØ -Ð -Ð -Ø "Ð "Ð "Ð "Ð "Ð "Ø 	€	€	€	Ø Ð Ð Ð Ø Ð Ð Ð Ø Ð Ð Ð Ø Ð Ð Ð Ø €€€Ø Ð Ð Ð Ø €€€Ø €€€Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø $Ð $Ð $Ð $Ð $Ð $Ø Ð Ð Ð Ð Ð Ð Ð Ø :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ø IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IÐ IðIð Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið Ið 6Ð 5Ð 5Ð 5Ð 5Ð 5Ø Ð Ð Ð Ð Ð Ø %Ð %Ð %Ð %Ð %Ð %Ð %Ð %Ð %Ð %Ø Ð Ð Ð Ð Ð ð 
ˆÔ	˜8Ñ	$Ô	$€à18°±´Ð  Ð :Ð :Ð :Ñ :ð%'ð %'ð %'ð %'ð %'ðPUð Uð Uð Uð Ð ðFð Fð Fð Fð Fñ Fô Fð FðR&ð &ð &ð &ð &�ñ &ô &ð &ð.&ð &ð &ð &ð &�=ñ &ô &ð &ðB6ð 6ð 6ð 6ð 6�Mñ 6ô 6ð 6ðrð ð ð ð ñ ô ð ð6 .€ðð ð ð ð"Pð Pð Pð Pð4=ð =ð =ð =ð
;ð ;ð ;ð ;ð
Wð Wð Wð Wð(
Sð 
Sð 
Sð 
Sð4ð 4ð 4ð 4ð4Að Að Að Að
*ð *ð *ð *ðZ1/ð 1/ð 1/ð 1/ðh#ð #ð #ð #ðL1ð 1ð 1ð 1ðh2ð 2ð 2ð 2ðj"ð "ð "ð "ðJ/ð /ð /ð /ð:ð ð ð ð26ð 6ð 6ð 6ðr2ð 2ð 2ð 2ðj2 ð 2 ð 2 ð 2 ðjJð Jð Jð Jðcð cð cð cð3ð 3ð 3ð 3ðlMð Mð Mð MðDð Dð Dð Dð
}ð }ð }ð }ðð ð ð ð>,ð ,ð ,ð ,ð^
ð 
ð 
ð 
ð
ð 
ð 
ð 
ð 
ð 
rW   