§
    E«jF  ã            
       ó:  — U d 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m	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZmZmZmZm Z  eej!                 Z"ee#d<    ej$        e%¦  «        Z& G d„ d¦  «        Z'de(de)de)de)de(f
d„Z*dS )úChallenge other bots.é    N)Úmodel)ÚTimerÚdaysÚsecondsÚminutesÚyears)Údefaultdict)ÚSequence)ÚLichessÚRateLimitedError)ÚConfiguration)ÚcastÚ	TypeAlias)ÚOnlineBlocklist)ÚUserProfileTypeÚPerfTypeÚ	EventTypeÚ
FilterTypeÚChallengeTypeÚMULTIPROCESSING_LIST_TYPEc                   óæ  — e Zd ZdZdedededdfd„Zdefd„Z	d	e
d
ededede
de
de
fd„Zded	e
ddfd„Zdee
ef         fd„Zde
fd„Zd0d„Zdee         de
dedede
dee         fd„Zdee
dz  eeee
e
f         fd„Zdede
dee
         de
fd„Zdee
         d ed!eddfd"„Zd#e
ddfd$„Zd0d%„Zd0d&„Zd	e
ddfd'„Zd	e
defd(„Z d1d	e
d)e
d*e!j"        dz  ddfd+„Z#d	e
d)e
defd,„Z$d-e%ddfd.„Z&d-e%ddfd/„Z'dS )2ÚMatchmakingr   ÚliÚconfigÚuser_profileÚreturnNc                 ó   — || _         t          t          d„ |j        j        ¦  «        ¦  «        | _        |j        | _        || _        t          t          d¦  «        ¦  «        | _
        t          t          | j        j        ¦  «        ¦  «        | _        t          t          d¦  «        ¦  «        | _        t          d¦  «        | _        t          ¦   «         | _        | j        j        rt          d¦  «        nt%          d¦  «        | _        d| _        t+          t          ¦  «        | _        | j        j        | _        | j        j        D ]}|                      |¦  «         Œt5          | j        j        ¦  «        | _        dS )z)Initialize values needed for matchmaking.c                 ó   — | dk    S )NÚfromPosition© )Úvariants    ú*/app/lichess-bot-master/lib/matchmaking.pyú<lambda>z&Matchmaking.__init__.<locals>.<lambda>   s   € °G¸~Ò4M€ ó    é   é   é<   é
   Ú N)r   ÚlistÚfilterÚ	challengeÚvariantsÚmatchmakingÚmatchmaking_cfgr   r   r   Úlast_challenge_created_delayr   Úchallenge_timeoutÚlast_game_ended_delayÚlast_user_profile_update_timeÚmin_wait_timeÚrate_limit_timerÚallow_during_gamesr	   Úmax_wait_timeÚchallenge_idr
   Úchallenge_type_acceptableÚchallenge_filterÚ
block_listÚadd_to_block_listr   Úonline_block_list)Úselfr   r   r   Únames        r#   Ú__init__zMatchmaking.__init__   s?  € àˆŒÝ�VÐ$MÐ$MÈvÔO_ÔOhÑiÔiÑjÔjˆŒØ%Ô1ˆÔØ(ˆÔÝ,1µ'¸"±+´+Ñ,>Ô,>ˆÔ)Ý%*­7°4Ô3GÔ3YÑ+ZÔ+ZÑ%[Ô%[ˆÔ"Ý-2µ7¸1±:´:Ñ->Ô->ˆÔ*Ý$ R™[œ[ˆÔÝ %¡¤ˆÔð -1Ô,@Ô,SÐb�W R™[œ[˜[ÕY^Ð_aÑYbÔYbˆÔØˆÔõ OZÕZ_ÑN`ÔN`ˆÔ&Ø $Ô 4Ô EˆÔàÔ(Ô3ð 	)ð 	)ˆDØ×"Ò" 4Ñ(Ô(Ð(Ð(å!0°Ô1EÔ1WÑ!XÔ!XˆÔÐÐr%   c                 ó  — | j         j        }| j                             ¦   «         o| j                             ¦   «         }| j                             ¦   «         o| j        }| j                             ¦   «         | j        k    }|rp| j	         
                    | j        ¦  «         t                               d| j        › d�¦  «         |                      | j        ¦  «         |                      ¦   «          t          |o|s|o|¦  «        S )z%Whether we should create a challenge.zChallenge id z cancelled.)r0   Úallow_matchmakingr3   Ú
is_expiredr6   r1   r9   Útime_since_resetr5   r   ÚcancelÚloggerÚinfoÚdiscard_challengeÚshow_earliest_challenge_timeÚbool)r?   Úmatchmaking_enabledÚtime_has_passedÚchallenge_expiredÚmin_wait_time_passeds        r#   Úshould_create_challengez#Matchmaking.should_create_challenge5   sú   € à"Ô2ÔDÐØÔ4×?Ò?ÑAÔAÐhÀdÔF[×FfÒFfÑFhÔFhˆØ Ô=×HÒHÑJÔJÐ`ÈtÔO`ÐØ#Ô@×QÒQÑSÔSÐVZÔVhÒhÐØð 	0ØŒG�NŠN˜4Ô,Ñ-Ô-Ð-Ý�KŠKÐF¨Ô(9ÐFÐFÐFÑGÔGÐGØ×"Ò" 4Ô#4Ñ5Ô5Ð5Ø×-Ò-Ñ/Ô/Ð/ÝÐ'Ðk¨_Ð-QÐ@QÐkÐWkÑlÔlÐlr%   ÚusernameÚ	base_timeÚ	incrementr   r"   Úmodec                 ó”  — |dk    |dœ}|r||d<   n+|s|r||d<   ||d<   nt                                d¦  «         dS 	 | j                             ¦   «          | j                             ||¦  «        }|                     dd¦  «        }	|	s|                      ||¦  «         |	S # t          $ r=}
t            	                    |
¦  «         t          |
j        ¦  «        | _        Y d	}
~
n6d	}
~
wt          $ r&}
t                                |
|
¬
¦  «         Y d	}
~
nd	}
~
ww xY wt            	                    d¦  «         |                      ¦   «          dS )zCreate a challenge.Úrated)rV   r"   r   zclock.limitzclock.incrementz˜At least one of challenge_days, challenge_initial_time, or challenge_increment must be greater than zero in the matchmaking section of your config file.r*   ÚidN)Úexc_infozCould not create challenge)rG   Úerrorr1   Úresetr   r-   ÚgetÚhandle_challenge_error_responser   Úwarningr   Útimeoutr6   Ú	ExceptionÚdebugrJ   )r?   rQ   rR   rS   r   r"   rT   ÚparamsÚresponser9   Úes              r#   Úcreate_challengezMatchmaking.create_challengeB   s–  € ð 9=ÀºÐT[Ð.\Ð.\ˆàð 	Ø!ˆF�6‰NˆNØð 	˜)ð 	Ø$-ˆF�=Ñ!Ø(1ˆFÐ$Ñ%Ð%å�LŠLð eñ fô fð fà�2ð	(ØÔ-×3Ò3Ñ5Ô5Ð5Ø”w×(Ò(¨°6Ñ:Ô:ˆHØ#Ÿ<š<¨¨bÑ1Ô1ˆLØð IØ×4Ò4°X¸xÑHÔHÐHØÐøÝð 	5ð 	5ð 	5Ý�NŠN˜1ÑÔÐÝ$)¨!¬)Ñ$4Ô$4ˆDÔ!Ð!Ð!Ð!Ð!Ð!øøøøÝð 	(ð 	(ð 	(Ý�LŠL˜ QˆLÑ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'øøøøð	(øøøõ 	�ŠÐ3Ñ4Ô4Ð4Ø×)Ò)Ñ+Ô+Ð+Øˆrs$   ¾A#B" Â"
DÂ,3C$Ã$DÃ1DÄDrb   c                 ó¼  — t                                |¦  «         |                     d¦  «        rBt          t          j        |                     d¦  «        ¦  «        }t          |¦  «        | _        nV|                     d¦  «        r+|                      |d|                     d¦  «        ¦  «         n|                      |d¦  «         |  	                    ¦   «          dS )zXIf a challenge fails, print the error and adjust the challenge requirements in response.Úbot_is_rate_limitedÚrate_limit_timeoutÚopponent_is_rate_limitedr*   N)
rG   rY   r[   r   ÚdatetimeÚ	timedeltar   r6   Úadd_challenge_filterrJ   )r?   rb   rQ   r^   s       r#   r\   z+Matchmaking.handle_challenge_error_responseb   sÄ   € å�Š�XÑÔÐØ�<Š<Ð-Ñ.Ô.ð 	4Ý�8Ô-¨x¯|ª|Ð<PÑ/QÔ/QÑRÔRˆGÝ$)¨'¡N¤NˆDÔ!Ð!Ø�\Š\Ð4Ñ5Ô5ð 	4Ø×%Ò% h°°H·L²LÐAUÑ4VÔ4VÑWÔWÐWÐWà×%Ò% h°Ñ3Ô3Ð3Ø×)Ò)Ñ+Ô+Ð+Ð+Ð+r%   c                 ó    — | j         d         }|S )zcGet the bot's rating in every variant. Bullet, blitz, rapid etc. are considered different variants.Úperfs©r   )r?   Ú	user_perfs     r#   ÚperfzMatchmaking.perfn   s   € à)-Ô):¸7Ô)Cˆ	ØÐr%   c                 ó    — | j         d         }|S )zOur username.rQ   rn   ©r?   rQ   s     r#   rQ   zMatchmaking.usernames   s   € àÔ)¨*Ô5ˆØˆr%   c                 ó  — | j                              ¦   «         rk| j                              ¦   «          t          j        t
          ¦  «        5  | j                             ¦   «         | _        ddd¦  «         dS # 1 swxY w Y   dS dS )z7Update our user profile data, to get our latest rating.N)	r4   rD   rZ   Ú
contextlibÚsuppressr_   r   Úget_profiler   ©r?   s    r#   Úupdate_user_profilezMatchmaking.update_user_profilex   sÃ   € àÔ-×8Ò8Ñ:Ô:ð 	:ØÔ.×4Ò4Ñ6Ô6Ð6ÝÔ$¥YÑ/Ô/ð :ð :Ø$(¤G×$7Ò$7Ñ$9Ô$9�Ô!ð:ð :ð :ñ :ô :ð :ð :ð :ð :ð :ð :ð :øøøð :ð :ð :ð :ð :ð :ð	:ð 	:s   ÁA8Á8A<Á?A<Úonline_botsÚrating_preferenceÚ
min_ratingÚ
max_ratingÚ	game_typec                 ó  ‡‡‡— dt           dt          fˆfd„Š|dk    r)t          |||z
  z
  |dz
  ¦  «        Šˆˆfd„|D ¦   «         }nB|dk    r)t          |||z
  z
  |dz   ¦  «        Šˆˆfd„|D ¦   «         }ndgt	          |¦  «        z  }|S )	z]Get the weight for each bot. A higher weights means the bot is more likely to get challenged.Úbotr   c                 óˆ   •— |                       di ¦  «        }|                      ‰i ¦  «        }|                      dd¦  «        S )Nrm   Úratingr   )r[   )r   rm   rp   r}   s      €r#   r�   z'Matchmaking.get_weights.<locals>.rating‚   s=   ø€ Ø),¯ª°¸"Ñ)=Ô)=ˆEØ"ŸYšY y°"Ñ5Ô5ˆDØ—8’8˜H aÑ(Ô(Ð(r%   Úhighé   c                 ó,   •— g | ]} ‰|¦  «        ‰z
  ‘ŒS r!   r!   ©Ú.0r   r�   Úreduce_ratings_bys     €€r#   ú
<listcomp>z+Matchmaking.get_weights.<locals>.<listcomp>Š   s'   ø€ ÐNÐNÐN¸3�v�v˜c‘{”{Ð%6Ñ6ÐNÐNÐNr%   Úlowc                 ó,   •— g | ]}‰ ‰|¦  «        z
  ‘ŒS r!   r!   r…   s     €€r#   rˆ   z+Matchmaking.get_weights.<locals>.<listcomp>Ž   s'   ø€ ÐNÐNÐN¸3Ð(¨6¨6°#©;¬;Ñ6ÐNÐNÐNr%   )r   ÚintÚminÚmaxÚlen)	r?   ry   rz   r{   r|   r}   Úweightsr�   r‡   s	        ` @@r#   Úget_weightszMatchmaking.get_weights   sÜ   øøø€ ð	)�ð 	)­Cð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð
  Ò&Ð&å # J°*¸zÑ2IÑ$JÈJÐYZÉNÑ [Ô [ÐØNÐNÐNÐNÐNÀ+ÐNÑNÔNˆGˆGØ %Ò'Ð'å # J°*¸zÑ2IÑ$JÈJÐYZÉNÑ [Ô [ÐØNÐNÐNÐNÐNÀ+ÐNÑNÔNˆGˆGà�c�C Ñ,Ô,Ñ,ˆGØˆr%   c           	      óÆ  ‡ ‡‡‡‡‡— t          j        ‰ j        j                             ¦   «         dgz   ¦  «        }t
                               d|pd› d�¦  «         |€i n‰ j        j                             |¦  «        }‰ j        |z  }‰                      |d‰ j	        ¦  «        Š‰                      |dddg¦  «        Š|j
        }t          j        |j        ¦  «        }t          j        |j        ¦  «        }t          j        |j        ¦  «        }t          |¦  «        t          |p|¦  «         g}t          j        |¦  «        rd	}d	}nd	}t          ‰|||¦  «        Š|j        Š|j        Š|j        }	‰                      ¦   «                              ‰i ¦  «                             d
d	¦  «        }
|	�|
d	k    r
|
|	z
  Š|
|	z   Št
                               d‰› d‰› d‰› d�¦  «         dt*          dt          fˆˆˆˆ fd„}‰ j                             ¦   «          ‰ j                             ¦   «         }t5          t7          ||¦  «        ¦  «        }dt*          dt          fˆˆˆ ˆfd„}t5          t7          ||¦  «        ¦  «        }|p|}d}‰                      ||‰‰‰¦  «        }	 t          j        ||¬¦  «        d	         }‰ j                             |d         ¦  «        }|                     d¦  «        r‰                      |d         ¦  «         n|d         }nG# t@          $ r: |rt
           !                    d¦  «         nt
           "                    d¦  «         Y nw xY w||||‰‰fS )zChoose an opponent.Nz
Using the Údefaultz matchmaking configuration.Úchallenge_variantÚchallenge_modeÚcasualrV   r   r�   zSeeking z game with opponent rating in [z, z] ...r   r   c                 óH  •— |                       di ¦  «                              ‰i ¦  «        }| d         ‰                     ¦   «         k    oY‰                     | d         ¦  «         o=|                      dd¦  «        dk    o#‰|                      dd¦  «        cxk    o‰k    nc S )Nrm   rQ   Úgamesr   r�   )r[   rQ   Úin_block_list)r   rp   r}   r|   r{   r?   s     €€€€r#   Úis_suitable_opponentz9Matchmaking.choose_opponent.<locals>.is_suitable_opponent´   s¯   ø€ Ø—7’7˜7 BÑ'Ô'×+Ò+¨I°rÑ:Ô:ˆDØ˜
”O t§}¢}¡¤Ò6ð JØ ×.Ò.¨s°:¬Ñ?Ô?Ð?ðJàŸš ¨!Ñ,Ô,¨qÒ0ðJð # d§h¢h¨x¸Ñ&;Ô&;ÐIÐIÒIÐI¸zÒIÐIÐIÐIðKr%   c                 óv   •‡ — ‰j         t          j        k    r‰‰‰gng }t          ˆ ˆfd„|D ¦   «         ¦  «        S )Nc              3   óP   •K  — | ] }‰                      ‰d          |¦  «        V — Œ!dS )rQ   N)Úshould_accept_challenge)r†   Úaspectr   r?   s     €€r#   ú	<genexpr>zKMatchmaking.choose_opponent.<locals>.ready_for_challenge.<locals>.<genexpr>Á   s8   øè è € ÐcÐcÐQW�t×3Ò3°C¸
´OÀVÑLÔLÐcÐcÐcÐcÐcÐcr%   )r;   r   ÚFINEÚall)r   Úaspectsr}   rT   r?   r"   s   ` €€€€r#   Úready_for_challengez8Matchmaking.choose_opponent.<locals>.ready_for_challenge¿   sL   øø€ Ø48Ô4IÍZÌ_Ò4\Ð4\�w 	¨4Ð0Ð0ÐbdˆGÝÐcÐcÐcÐcÐcÐ[bÐcÑcÔcÑcÔcÐcr%   )r�   rQ   ÚblockingzError:z$No suitable bots found to challenge.)#ÚrandomÚchoicer0   Ú	overridesÚkeysrG   rH   ÚlookupÚget_random_config_valuer.   rz   Úchallenge_initial_timeÚchallenge_incrementÚchallenge_daysrK   Úgame_categoryÚopponent_min_ratingÚopponent_max_ratingÚopponent_rating_differencerp   r[   r   r>   Úrefreshr   Úget_online_botsr+   r,   r�   ÚchoicesÚget_public_datar=   r_   Ú	exceptionrY   )r?   Úoverride_choiceÚoverrideÚmatch_configrz   rR   rS   Únum_daysÚplay_correspondenceÚrating_diffÚ
bot_ratingr™   ry   r¢   Ú
ready_botsÚbot_usernamer�   r   Úbot_profiler}   r|   r{   rT   r"   s   `                  @@@@@r#   Úchoose_opponentzMatchmaking.choose_opponent“   sØ  øøøøøø€ å œ-¨Ô(<Ô(F×(KÒ(KÑ(MÔ(MÐQUÐPVÑ(VÑWÔWˆÝ�ŠÐZ Ð!=°IÐZÐZÐZÑ[Ô[Ð[Ø(Ð0�2�2°dÔ6JÔ6T×6[Ò6[Ð\kÑ6lÔ6lˆØÔ+¨hÑ6ˆà×.Ò.¨|Ð=PÐRVÔR_Ñ`Ô`ˆØ×+Ò+¨LÐ:JÈXÐW^ÐL_Ñ`Ô`ˆØ(Ô:Ðå”M ,Ô"EÑFÔFˆ	Ý”M ,Ô"BÑCÔCˆ	Ý”= Ô!<Ñ=Ô=ˆå# H™~œ~µ4¸	Ð8NÀYÑ3OÔ3OÐ/OÐPÐÝŒ=Ð,Ñ-Ô-ð 	ØˆIØˆIˆIàˆHå! '¨9°iÀÑJÔJˆ	à!Ô5ˆ
Ø!Ô5ˆ
Ø"Ô=ˆØ—Y’Y‘[”[—_’_ Y°Ñ3Ô3×7Ò7¸À!ÑDÔDˆ
ØÐ" z°A¢~ ~Ø# kÑ1ˆJØ# kÑ1ˆJÝ�ŠÐh˜yÐhÐhÈÐhÐhÐWaÐhÐhÐhÑiÔiÐið	K¥oð 	K½$ð 	Kð 	Kð 	Kð 	Kð 	Kð 	Kð 	Kð 	Kð 	Kð 	Ô×&Ò&Ñ(Ô(Ð(Ø”g×-Ò-Ñ/Ô/ˆÝ�6Ð"6¸ÑDÔDÑEÔEˆð	d¥_ð 	d½ð 	dð 	dð 	dð 	dð 	dð 	dð 	dð 	dð 	dõ �&Ð!4°kÑBÔBÑCÔCˆ
Ø Ð/ KˆØˆØ×"Ò" ;Ð0AÀ:ÈzÐ[dÑeÔeˆð	EÝ”. °gÐ>Ñ>Ô>¸qÔAˆCØœ'×1Ò1°#°j´/ÑBÔBˆKØ�Š˜zÑ*Ô*ð /Ø×&Ò& s¨:¤Ñ7Ô7Ð7Ð7à" :œ�øøÝð 	Eð 	Eð 	EØð EÝ× Ò  Ñ*Ô*Ð*Ð*å—’ÐCÑDÔDÐDøøð		Eøøøð ˜Y¨	°8¸WÀdÐJÐJs   ÊA5L ÌAMÍMÚ	parameterr³   c                 ód   — |                      |¦  «        }|dk    r|nt          j        |¦  «        S )zVChoose a random value from `choices` if the parameter value in the config is `random`.r¤   )r¨   r¤   r¥   )r?   r   rÁ   r³   Úvalues        r#   r©   z#Matchmaking.get_random_config_value×   s1   € à—]’] 9Ñ-Ô-ˆØ Ò)Ð)ˆuˆu­v¬}¸WÑ/EÔ/EÐEr%   Úactive_gamesÚchallenge_queueÚ	max_gamesc                 óf  — | j         j        r|nt          d|¦  «        }t          |¦  «        t          |¦  «        z   }||k    s<|dk    r"| j                             ¦   «         | j        k     s|                      ¦   «         sdS t           	                    d¦  «         |  
                    ¦   «          |                      ¦   «         \  }}}}	}
}t           	                    d|› d|
› d�¦  «         |r|                      ||||	|
|¦  «        nd}t           	                    d	|pd
› d�¦  «         || _        dS )zú
        Challenge an opponent.

        :param active_games: The games that the bot is playing.
        :param challenge_queue: The queue containing the challenges.
        :param max_games: The maximum allowed number of simultaneous games.
        rƒ   r   NzChallenging a random botzWill challenge z for a z game.r*   zChallenge id is ÚNoneú.)r0   r7   rŒ   rŽ   r1   rE   r8   rP   rG   rH   rx   rÀ   rd   r9   )r?   rÄ   rÅ   rÆ   Úmax_games_for_matchmakingÚ
game_countr¾   rR   rS   r   r"   rT   r9   s                r#   r-   zMatchmaking.challengeÜ   sQ  € ð 26Ô1EÔ1XÐ$o I IÕ^aÐbcÐenÑ^oÔ^oÐ!Ý˜Ñ&Ô&­¨_Ñ)=Ô)=Ñ=ˆ
ØÐ3Ò3Ð3Ø ’N�N tÔ'H×'YÒ'YÑ'[Ô'[Ð^bÔ^pÒ'pÐ'pØ×3Ò3Ñ5Ô5ð (qàˆFå�ŠÐ.Ñ/Ô/Ð/Ø× Ò Ñ"Ô"Ð"ØBF×BVÒBVÑBXÔBXÑ?ˆ�i ¨D°'¸4Ý�ŠÐJ lÐJÐJ¸7ÐJÐJÐJÑKÔKÐKØiuÐ}�t×,Ò,¨\¸9ÀiÐQUÐW^Ð`dÑeÔeÐeÐ{}ˆÝ�ŠÐ@ |Ð'=°vÐ@Ð@Ð@ÑAÔAÐAØ(ˆÔÐÐr%   r9   c                 ó.   — | j         |k    r	d| _         dS dS )z´
        Clear the ID of the most recent challenge if it is no longer needed.

        :param challenge_id: The ID of the challenge that is expired, accepted, or declined.
        r*   N)r9   )r?   r9   s     r#   rI   zMatchmaking.discard_challengeó   s(   € ð Ô Ò,Ð,Ø "ˆDÔÐÐð -Ð,r%   c                 ó`   — | j                              ¦   «          |                      ¦   «          dS )znReset the timer for when the last game ended, and prints the earliest that the next challenge will be created.N)r3   rZ   rJ   rw   s    r#   Ú	game_donezMatchmaking.game_doneü   s/   € àÔ"×(Ò(Ñ*Ô*Ð*Ø×)Ò)Ñ+Ô+Ð+Ð+Ð+r%   c                 óŒ  — | j         j        r·| j                             ¦   «         }| j        | j                             ¦   «         z
  }| j                             ¦   «         }t          |||¦  «        }t          j	         
                    ¦   «         |z   }t                               d|                     d¦  «        › �¦  «         dS dS )z:Show the earliest that the next challenge will be created.z%Next challenge will be created after z%cN)r0   rC   r3   Útime_until_expirationr5   r1   rE   r6   r�   ri   ÚnowrG   rH   Ústrftime)r?   Úpostgame_timeoutÚtime_to_next_challengeÚrate_limit_delayÚ	time_leftÚearliest_challenge_times         r#   rJ   z(Matchmaking.show_earliest_challenge_time  sÃ   € àÔÔ1ð 	jØ#Ô9×OÒOÑQÔQÐØ%)Ô%7¸$Ô:[×:lÒ:lÑ:nÔ:nÑ%nÐ"Ø#Ô4×JÒJÑLÔLÐÝÐ,Ð.DÐFVÑWÔWˆIÝ&.Ô&7×&;Ò&;Ñ&=Ô&=À	Ñ&IÐ#Ý�KŠKÐhÐ@W×@`Ò@`ÐaeÑ@fÔ@fÐhÐhÑiÔiÐiÐiÐið	jð 	jr%   c                 óN   — |                       |dt          d¦  «        ¦  «         dS )zAdd a bot to the blocklist.r*   r)   N)rk   r	   rr   s     r#   r=   zMatchmaking.add_to_block_list  s&   € à×!Ò! (¨Bµ°b±	´	Ñ:Ô:Ð:Ð:Ð:r%   c                 óB   — |                       |d¦  «         p|| j        v S )zGCheck if an opponent is in the block list to prevent future challenges.r*   )rœ   r>   rr   s     r#   r˜   zMatchmaking.in_block_list  s(   € à×0Ò0°¸2Ñ>Ô>Ð>ÐeÀ8ÈtÔOeÐCeÐer%   Úgame_aspectr^   c                 óV   — t          |pt          d¦  «        ¦  «        | j        ||f<   dS )aï  
        Prevent creating another challenge for a timeout when an opponent has declined a challenge.

        :param username: The name of the opponent.
        :param game_aspect: The aspect of a game (time control, chess variant, etc.) that caused the opponent to decline a
        challenge. If the parameter is empty, that is equivalent to adding the opponent to the block list.
        :param timeout: The amount of time to not challenge an opponent. If None, the default is a day.
        rƒ   N)r   r   r:   )r?   rQ   rÚ   r^   s       r#   rk   z Matchmaking.add_challenge_filter  s5   € õ CHÈÐHZÕSWÐXYÑSZÔSZÑB[ÔB[ˆÔ&¨°+Ð'>Ñ?Ð?Ð?r%   c                 óD   — | j         ||f                              ¦   «         S )a]  
        Whether a bot is likely to accept a challenge to a game.

        :param username: The name of the opponent.
        :param game_aspect: A category of the challenge type (time control, chess variant, etc.) to test for acceptance.
        If game_aspect is empty, this is equivalent to checking if the opponent is in the block list.
        )r:   rD   )r?   rQ   rÚ   s      r#   rœ   z#Matchmaking.should_accept_challenge  s#   € ð Ô-¨x¸Ð.EÔF×QÒQÑSÔSÐSr%   Úeventc                 óH   — |                       |d         d         ¦  «         dS )z�
        Set the challenge id to an empty string, if the challenge was accepted.

        Otherwise, we would attempt to cancel the challenge later.
        ÚgamerW   N)rI   )r?   rÝ   s     r#   Úaccepted_challengezMatchmaking.accepted_challenge(  s'   € ð 	×Ò˜u Vœ}¨TÔ2Ñ3Ô3Ð3Ð3Ð3r%   c                 ó*  — t          j        |d         | j        ¦  «        }|j        }|d         d         }t                               |› d|› d|› �¦  «         |                      |j        ¦  «         |j        r| j	        t          j        k    rdS |j        rdnd}ddd|j        |j        |j        |||j        |j        d	œ
}|d         d
                              ¦   «         }||vrt                               d|› �¦  «         | j	        t          j        k    r|                     |d¦  «        nd}|                      |j        |¦  «         t                               d|› d|› �                     ¦   «         dz   ¦  «         |                      ¦   «          dS )z�
        Handle a challenge that was declined by the opponent.

        Depends on whether `FilterType` is `NONE`, `COARSE`, or `FINE`.
        r-   ÚdeclineReasonz
 declined z: NrV   r•   r*   )
ÚgenericÚlaterÚnobotÚtoofastÚtooslowÚtimecontrolrV   r•   Ústandardr"   ÚdeclineReasonKeyz!Unknown decline reason received: zWill not challenge z to another z game today.)r   Ú	Challenger   Úchallenge_targetrG   rH   rI   rW   Ú	from_selfr;   r   ÚNONErV   Úspeedr"   Úlowerr]   rŸ   r[   rk   r@   ÚstriprJ   )	r?   rÝ   r-   ÚopponentÚreasonrT   Údecline_detailsÚ
reason_keyÚgame_problems	            r#   Údeclined_challengezMatchmaking.declined_challenge0  s®  € õ ”O E¨+Ô$6¸Ô8IÑJÔJˆ	ØÔ-ˆØ�{Ô# OÔ4ˆÝ�Š�xÐ@Ð@¨9Ð@Ð@¸Ð@Ð@ÑAÔAÐAØ×Ò˜yœ|Ñ,Ô,Ð,ØÔ"ð 	 dÔ&;½z¼Ò&NÐ&NØˆFà#œ/Ð7ˆwˆw¨xˆØ68Ø46Ø46Ø6?´oØ6?´oØ:C¼/Ø48Ø59Ø7@Ô7HØ6?Ô6Gð	+Ið 	+Iˆð ˜;Ô'Ð(:Ô;×AÒAÑCÔCˆ
Ø˜_Ð,Ð,Ý�NŠNÐK¸zÐKÐKÑLÔLÐLØ>BÔ>SÕWaÔWfÒ>fÐ>f�×*Ò*¨:°rÑ:Ô:Ð:ÐlnˆØ×!Ò! (¤-°Ñ>Ô>Ð>Ý�ŠÐN¨(ÐNÐNÀÐNÐN×TÒTÑVÔVÐYgÑgÑhÔhÐhà×)Ò)Ñ+Ô+Ð+Ð+Ð+r%   )r   N)N)(Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   rA   rK   rP   Ústrr‹   rd   r   r\   Údictr   rp   rQ   rx   r+   r�   ÚtuplerÀ   r©   Úsetr   r-   rI   rÎ   rJ   r=   r˜   ri   rj   rk   rœ   r   rà   r÷   r!   r%   r#   r   r      sŽ  € € € € € ØÐðY˜7ð Y¨Mð YÈð YÐ]að Yð Yð Yð Yð<m¨ð mð mð mð mð¨ð ¸ð Èð ÐTWð Ðbeð Ø"ðØ'*ðð ð ð ð@
,¸ð 
,ÐQTð 
,ÐY]ð 
,ð 
,ð 
,ð 
,ð�d˜3 ˜=Ô)ð ð ð ð ð
˜#ð ð ð ð ð
:ð :ð :ð :ð t¨OÔ'<ð ÐQTð Ðbeð Ðsvð Ø"ðØ'+¨C¤yðð ð ð ð(BK  s¨T¡z°3¸¸SÀ#ÀsÐ'JÔ!Kð BKð BKð BKð BKðHF¨mð FÈð FÐVZÐ[^ÔV_ð FÐdgð Fð Fð Fð Fð
) c¨#¤hð )ÐAZð )Ðgjð )Ðosð )ð )ð )ð )ð.#¨cð #°dð #ð #ð #ð #ð,ð ,ð ,ð ,ð
jð jð jð jð;¨#ð ;°$ð ;ð ;ð ;ð ;ðf cð f¨dð fð fð fð fð	\ð 	\¨Sð 	\¸sð 	\ÈXÔM_ÐbfÑMfð 	\Ðrvð 	\ð 	\ð 	\ð 	\ðT°ð TÀ#ð TÈ$ð Tð Tð Tð Tð4¨	ð 4°dð 4ð 4ð 4ð 4ð!,¨	ð !,°dð !,ð !,ð !,ð !,ð !,ð !,r%   r   r"   rR   rS   r¹   r   c                 ó^   — ||dz  z   }| dk    r| S |rdS |dk     rdS |dk     rdS |dk     rd	S d
S )aƒ  
    Get the game type (e.g. bullet, atomic, classical). Lichess has one rating for every variant regardless of time control.

    :param variant: The game's variant.
    :param base_time: The base time in seconds.
    :param increment: The increment in seconds.
    :param num_days: If the game is correspondence, we have some days to play the move.
    :return: The game category.
    é(   ré   Úcorrespondenceé³   Úbulletiß  ÚblitziÛ  ÚrapidÚ	classicalr!   )r"   rR   rS   r¹   Úgame_durations        r#   r­   r­   T  se   € ð  	¨B¡Ñ.€MØ�*ÒÐØˆØð  ØÐØ�sÒÐØˆxØ�sÒÐØˆwØ�tÒÐØˆwØˆ;r%   )+rû   r¤   Úloggingri   rt   Úlibr   Ú	lib.timerr   r   r   r   r	   Úcollectionsr
   Úcollections.abcr   Úlib.lichessr   r   Ú
lib.configr   Útypingr   r   Úlib.blocklistr   Úlib.lichess_typesr   r   r   r   r   rë   r   Ú__annotations__Ú	getLoggerrø   rG   r   rü   r‹   r­   r!   r%   r#   ú<module>r     s°  ðØ Ð Ð Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ø #Ð #Ð #Ð #Ð #Ð #Ø $Ð $Ð $Ð $Ð $Ð $Ø 1Ð 1Ð 1Ð 1Ð 1Ð 1Ð 1Ð 1Ø $Ð $Ð $Ð $Ð $Ð $Ø "Ð "Ð "Ð "Ð "Ð "Ð "Ð "Ø )Ð )Ð )Ð )Ð )Ð )Ø ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ð ]Ø'/°´Ô'@Ð ˜9Ð @Ð @Ñ @à	ˆÔ	˜8Ñ	$Ô	$€ð},ð },ð },ð },ð },ñ },ô },ð },ð@
˜3ð ¨3ð ¸3ð È#ð ÐRUð ð ð ð ð ð r%   