
    6j                       d Z ddlm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 ddlmZ dd	lmZmZmZmZ dd
lmZmZ ddlmZ ddlmZ  ed          ZdZej        dej         dej!        dej"        dej#        dej$        dej%        dej&        dej'        dej(        di
Z) G d de          Z* G d d          Z+ G d d          Z,dS )u  WerewolfEngine:「阶段 + 能力词表」状态机。

夜间按 night_order 排序、按 role.night_action 分发(kill/check/save_poison/…)、按 counts_as 判屠边
—— 全程**不写 "if 角色==预言家"**。决策来自可插拔的 DecisionProvider:
- M0 = RandomProvider(随机合法决策,跑通流程,无 LLM);
- M1 = AI 脑(实现同一接口);M2 = 真人到点 await(在 provider 之上加等待层)。
    )annotationsN)Counter)Path)OptionalProtocol)
get_logger)
perception)Boarddeal
load_boardresolve_night_order)Role
load_roles)state)	GameStatezwerewolf.engine   u   等待开局   警长竞选u   上警发言u   警徽投票u   天黑请闭眼u	   天亮了u   轮流发言   放逐投票u   投票结算u   对局结束c                  z    e Zd ZdZd d
Zd!dZd!dZd"dZd#dZd$dZ	d#dZ
d!dZd#dZd%dZd!dZd!dZd&dZdS )'DecisionProviderub   引擎在每个决策点回调它;引擎已算好合法候选,provider 只需在其中做选择。r   r   seatint
candidates	list[int]returndictc                    d S N selfr   r   r   s       2/root/genesis-world/src/genesis/werewolf/engine.pywolf_discusszDecisionProvider.wolf_discuss'             Optional[int]c                    d S r   r   r    s       r"   decide_killzDecisionProvider.decide_kill(   r$   r%   c                    d S r   r   r    s       r"   decide_checkzDecisionProvider.decide_check)   r$   r%   knifecan_savebool
can_poisonpoison_candidatesc                    d S r   r   )r!   r   r   r+   r,   r.   r/   s          r"   decide_witchzDecisionProvider.decide_witch*   s    ^a^ar%   c                    d S r   r   r!   r   r   s      r"   decide_run_sheriffz#DecisionProvider.decide_run_sheriff,   r$   r%   c                    d S r   r   r3   s      r"   decide_speech_dirz"DecisionProvider.decide_speech_dir-   r$   r%   c                    d S r   r   r3   s      r"   decide_withdrawz DecisionProvider.decide_withdraw.   r$   r%   c                    d S r   r   r    s       r"   decide_badge_passz"DecisionProvider.decide_badge_pass/   r$   r%   c                    d S r   r   r3   s      r"   decide_explodezDecisionProvider.decide_explode0   r$   r%   strc                    d S r   r   r3   s      r"   speakzDecisionProvider.speak1   r$   r%   c                    d S r   r   r    s       r"   decide_votezDecisionProvider.decide_vote2   r$   r%   c                    d S r   r   r    s       r"   decide_hunter_shootz$DecisionProvider.decide_hunter_shoot3   r$   r%   Nonec                    d S r   r   r3   s      r"   
digest_dayzDecisionProvider.digest_day4   r$   r%   N)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   rD   )__name__
__module____qualname____doc__r#   r(   r*   r1   r4   r6   r8   r:   r<   r?   rA   rC   rF   r   r%   r"   r   r   %   s        ll[[[[ccccddddb b b bJJJJIIIIGGGGiiiiFFFF<<<<cccckkkkBBBBBBr%   r   c                  $   e Zd Z	 dLdMdZdNdOdZdPdQdZdRdZdQdZdSdZdTdUdZ	dVd"Z
dWd$ZdXd'ZdYd(ZdZd)Zd[d\d/Zd]d0Zd^d2Zd_d3Zd_d4Zd_d5Zd_d6Zd`d8ZdLdad:ZdRd;ZdRd<ZdYd=Zdbd@ZdcdBZd_dCZdRdDZd]dEZdRdFZ dRdGZ!dddJZ"dedKZ#dS )fWerewolfEngineN	world_dir
str | Pathboard_idr=   providerr   rngOptional[random.Random]r   rD   c                   t          |          }t          |dz            | _        t          |dz  | dz            | _        || _        |pt          j                    | _        t          | j        | j                  | _
        | j                            dd          }t          | j        | j                  }t          | j        j        | j        j        ||          | _        | j        j        D ]B}| j        | j                            |                   j        dk    rddd	| j        j        |<   Cd
| _        d
| _        d | _        d | _        d | _        d | _        i | _        d| _        d S )Nrolesboardsz.jsonr   i)rO   seatsrT   seedsave_poisonTantidotepoison        F)r   r   rT   r   boardrP   randomRandomrQ   r   _night_orderrandintr   r   idrV   r   role_ofnight_actionwitch_potionspacethink_pausebanner
wait_audioprewarm_ttsis_human_spipeaborted)r!   rM   rO   rP   rQ   rW   rV   ss           r"   __init__zWerewolfEngine.__init__8   sP   OO	&0W1D&E&E
&y8';>P>P>P'PQQ
 )&-///
DJGGx9--TZ**
TZ=MUZaefff
! 	Q 	QAz$*,,Q//0=NN;?4.P.P
(+	&*r%         ?multfloatc                X    | j         dk    rt          j        | j         |z             dS dS )up   在关键转折处停一拍(天亮宣布、放逐结算),给前端宣布动画时间;pace=0 时不停(测试)。r   N)rf   timesleep)r!   rq   s     r"   _beatzWerewolfEngine._beatO   s1    9q==Jty4'((((( =r%   r\   kindtextr   r&   secsc                V    ||||dk    rt          j                     |z   nd d| _        d S )Nr   )rw   rx   r   until)rt   rh   r!   rw   rx   r   ry   s        r"   _set_bannerzWerewolfEngine._set_bannerU   s8    #T48<qt!3!3dL Lr%   c                    d | _         d S r   )rh   r!   s    r"   _clear_bannerzWerewolfEngine._clear_bannerY   s    r%   c                    | j         dk    s|dk    s| j        rdS |                     ||||           t          j        |           dS )u   点亮带倒计时的横幅并真正停住引擎线程 secs 秒(pace>0 才停);前端据此显示倒计时、并行播放语音。r   N)rf   rm   r}   rt   ru   r|   s        r"   _holdzWerewolfEngine._hold\   sP    9>>TQYY$,YFtT4000
4r%   r   c                B   t          | j        o|                     |                    }| j        D|sB|                     d| d|           	 |                     ||           n# t          $ r Y nw xY w| j        dk    r|                     dd|| j                   dS dS )u  一位发言彻底结束的节拍:先等其语音真正播完(前端 audio 结束回报,而非估时),再进入思考停顿。
        语音没播完不进思考;关语音则不空等。这保证『说完→听完→才思考→才下一位』。
        ★真人本人的发言不等播音:他是自己说出来的(前端不回放自己的发言、也不报 spoken),
          再去等 audio 信号只会傻等到超时——点发送应当立刻进入思考倒计时。其它真人客户端会在思考间隙听到他的 TTS。Nspeaking   号 发言中…r   thinkingu(   思考时间 · 消化上一位发言…)r-   rk   ri   r}   	Exceptionrg   r   )r!   r   rx   speaker_is_humans       r"   _after_speechzWerewolfEngine._after_speechc   s    
   E$--2E2EFF?&/?&ZD)B)B)BDIIId++++   aJJz#MtUYUefffff  s   A% %
A21A2judgeetypec                .   | j                             ||           |                     dd|z              | j        (	 |                     d|           n# t          $ r Y nw xY w| j        *	 |                     d|           dS # t          $ r Y dS w xY wdS )u   法官播报:记一条法官台词(进 feed)+ 点亮法官横幅 + 等其语音播完再继续(用语音引领节奏)。
        seat=0 代表法官;关语音/无前端则不空等(wait_audio 立即返回/超时兜底)。r   u   🎙 法官 · Nr   )r   recordr}   rj   r   ri   )r!   rx   r   s      r"   _narratezWerewolfEngine._narrater   s     	
%&&&"3d":;;;'  D))))   ?&4(((((    '&s#   A 
A! A!,B 
BBitemslistr   c                    i fdfd|D             }|D ]}|                                  |D ]}|                                 S )u   对每个 item 并发跑 fn(item) → {item: result}。AI 多线程提速;真人那一支在自己线程里等 UI。
        并发上限不在这里限,而在 LLM 调用层(brain._LLM_SEM)——这样真人等 UI 不占 LLM 名额。c                    	  |           | <   d S # t           $ rA}t                              d| t          |          d d                    d | <   Y d }~d S d }~ww xY w)Nu   [parallel] %s 失败:%sP   )r   loggerwarningr=   )itefnouts     r"   workerz(WerewolfEngine._parallel.<locals>.worker   s|    ["R&&B [ [ [8"c!ffSbSkJJJVZCPRGGGGGGG[s    
A6AAc                @    g | ]}t          j        |fd           S )Ttargetargsdaemon)	threadingThread).0r   r   s     r"   
<listcomp>z,WerewolfEngine._parallel.<locals>.<listcomp>   s-    XXXByvRE$GGGXXXr%   )startjoin)r!   r   r   thstr   r   s     `  @@r"   	_parallelzWerewolfEngine._parallel   s     	[ 	[ 	[ 	[ 	[ 	[
 YXXXRWXXX 	 	AGGIIII 	 	AFFHHHH
r%   votersc                                          dd                                | fd          }|D ]R}|                    |          }| |          v r. j        j                             j        j        |||d           S|S )u   并发收票:期间**不写 votes_log**(谁都看不到本轮票 → 杜绝跟票),全收齐后统一公布。返回 {voter: target}。waitingu,   全场同时投票中…(互相看不到票)c                X    j                             j        |  |                     S r   )rP   rA   r   )vcands_fnr!   s    r"   <lambda>z/WerewolfEngine._collect_votes.<locals>.<lambda>   s+    4=3L3LTZYZ\d\def\g\g3h3h r%   )dayrw   voterr   )r}   r   getr   	votes_logappendr   )r!   r   r   rw   resultsr   r   s   ` `    r"   _collect_voteszWerewolfEngine._collect_votes   s    $RSSS..)h)h)h)h)hii 	l 	lAAAHHQKK
$++DJND[\hi,j,jkkkr%   r   labelc                    d                     d t          |                                          D                       }|                     |r| d| dn| dd           dS )uQ   票型公布(bug5):全场可见谁投了谁——进 feed + 法官语音播报。u   ，c              3  0   K   | ]\  }}|| d| dV  d S )Nu   号→   号r   )r   r   r   s      r"   	<genexpr>z1WerewolfEngine._announce_votes.<locals>.<genexpr>   s=      dd41aVWVcq.....VcVcVcVcddr%   u   票型:u   。u   无人投票。announceN)r   sortedr   r   )r!   r   r   arrowss       r"   _announce_voteszWerewolfEngine._announce_votes   sq    dd6'--//;R;Rdddddf[22v2222UB[B[B[]ghhhhhr%   c                      j         r                                s	 j        v rd S i  fd}t          j        |d          }|                                 |d j        <   d S )Nc                 Z   	 j                             j                  d<   j        r3                    d          r                     d                    d S d S d S # t
          $ r<} t                              dt          |           d d                    Y d } ~ d S d } ~ ww xY w)Nrx   u   预生成 %d 号发言失败:%sd   )	rP   r?   r   rj   r   r   r   r   r=   )r   holderr   r!   s    r"   workz-WerewolfEngine._prefetch_speech.<locals>.work   s    V!%!4!4TZ!F!Fv# ;

6(:(: ;$$T6&>:::::; ; ; ; V V V@$AtPStUUUUUUUUUVs   AA$ $
B*.1B%%B*T)r   r   )threadr   )rk   rl   r   r   r   )r!   r   r   thr   s   ``  @r"   _prefetch_speechzWerewolfEngine._prefetch_speech   s    M 	dmmD11 	ddk6I6IF	V 	V 	V 	V 	V 	V 	V T$777')V<<Dr%   c                X   | j                             |d           }t          | j        o|                     |                    }|rE|sC|d                                          |d                             d          |d         d         S | j                            | j        |          S )Nr   r   rx   )	rl   popr-   rk   r   r   rP   r?   r   )r!   r   p	human_nows       r"   _take_speechzWerewolfEngine._take_speech   s    KOOD$''>4==+>+>??	 	+Y 	+hK{v&&2{6**}""4:t444r%   Forderr   allow_exploder-   c                R   |r|                      |d                    t          |          D ]x\  }}| j        s| j        j        r dS |r|                     |          j        dk    r|                     |          r| j        	                    |d           | j        
                    |t          j                   | j                            d| d|           |                     | dd           |                                   d	S |                     d
| d|           |                     |          }| j                            |||           |dz   t%          |          k     r|                      ||dz                       |                     ||           zdS )u_  逐位发言:下一位在上一位 record 后即并行预生成,轮到时直接揭晓(文字+语音都在自己轮次)。
        allow_explode=True(白天发言)时,轮到狼可选择自爆→中止当天发言。返回是否发生了自爆。
        aborted(房间关闭/分胜负)立即收尾,不再空跑发言(治 bug10:结束后还出发言)。r   FwolfNexileu?   号狼人自爆,掀桌亮明身份!白天中止,直接入夜。r   u;   号自爆出局,白天发言与投票中止,即刻天黑。Tr   r      )r   	enumeraterm   r   winner_roleteam_ask_exploderl   r   killSCAUSE_EXPLODEr   r   _transfer_badge_if_deadr}   r   lenr   )r!   r   r   r   ir   rx   s          r"   _run_speecheszWerewolfEngine._run_speeches   s     	,!!%(+++ '' 	+ 	+GAt| tz0 uu D!1!1!6&!@!@TEVEVW[E\E\!@d+++
ao666
!!'d+s+s+sz~!bbbdklll,,...ttZD)B)B)BNNN$$T**DJeT5551us5zz!!%%eAEl333tT****ur%   c                    t          | j        dd           }	 |rt           || j        |                    ndS # t          $ r Y dS w xY w)Nr<   FgetattrrP   r-   r   r   r!   r   r   s      r"   r   zWerewolfEngine._ask_explode   sc    T]$4d;;	13>44:t,,---> 	 	 	55	   !: 
AAr   c                L    | j         | j                            |                   S r   )rT   r   rc   )r!   r   s     r"   r   zWerewolfEngine._role   s    z$*,,T2233r%   c                N    fd| j                                         D             S )Nc                *    g | ]} |          |S r   r   )r   rn   preds     r"   r   z)WerewolfEngine._alive.<locals>.<listcomp>   s&    ???attAww????r%   )r   alive_seats)r!   r   s    `r"   _alivezWerewolfEngine._alive   s+    ????4:1133????r%   c                4                            fd          S )Nc                @                         |           j        dk    S Nr   r   r   rn   r!   s    r"   r   z.WerewolfEngine._wolves_alive.<locals>.<lambda>   s    TZZ]]%76%A r%   r   r   s   `r"   _wolves_alivezWerewolfEngine._wolves_alive   s    {{AAAABBBr%   c                4                            fd          S )Nc                @                         |           j        dk    S )Ngodr   	counts_asr   s    r"   r   z,WerewolfEngine._gods_alive.<locals>.<lambda>   s    TZZ]]%<%E r%   r   r   s   `r"   _gods_alivezWerewolfEngine._gods_alive   s    {{EEEEFFFr%   c                4                            fd          S )Nc                @                         |           j        dk    S )Nvillagerr   r   s    r"   r   z1WerewolfEngine._villagers_alive.<locals>.<lambda>   s    TZZ]]%<
%J r%   r   r   s   `r"   _villagers_alivezWerewolfEngine._villagers_alive   s    {{JJJJKKKr%   Optional[str]c                4   d| j         _        t          t                    D ]}| j        r n|                                  | j        s|                                 r nk|                     | j         j        dk               | j        s|                                 r n*|                                  | j         xj        dz  c_        | 	                                 t                              d| j         j        pd| j         j                   | j         j        S )Nr   )firstu'   [狼人杀] 对局结束:%s 胜(%d 天)u   无)r   r   range
MAX_ROUNDSrm   _night
_check_win_day_digest_dayr   r   infor   )r!   _s     r"   run_gamezWerewolfEngine.run_game   s   
z"" 
	  
	 A| KKMMM| t00 IITZ^q0I222| t00 JNNaNNN=tz?P?YTY[_[e[ijjjz  r%   viewerc                   du p3| j                                        pt          | j         j                  }|rdnt	          j        | j         | j                  }|r|j        rt          |j                  nt                      }g }t          | j         j                  D ]}| j        | j         
                    |                   }|pduo	|k    p||v }|                    || j                             |          || j         j        k    |r|j        nd|r|j        ndd           |r;t          | j         j        dd                   t          | j         j                  }
}	n0t          |j        dd                   t          |j                  }
}	d}|r7|j        |j        fd|j        pg D             pd|j        |j        |j        d}d}| j        r| j        }|                    d          rDt3          dt5          t7          |d         t9          j                    z
                                nd}|d         |d	         |                    d
          |d}| j        j        | j         j        | j         j        t@                              | j         j        d          | j         j        tB          j"        k    | j         j        | j         j        |||	|
||dS )uK  一帧渲染态。
        - viewer=None 或已出局 → **上帝视角**(揭示全部真名 + 全量 transcript 含狼私聊);
        - 活着的 viewer → **玩家视角**:只亮自己身份(狼额外亮队友),按 perception 给 transcript,
          并附 private 块(自己的查验史/刀型/药/队友)供侧栏显示。N)r   alive
is_sheriffroler   ic                     g | ]
}|k    |S r   r   )r   rn   r  s     r"   r   z(WerewolfEngine.frame.<locals>.<listcomp>  s    $T$T$T1VQr%   )r  r   	teammateschecksr+   potionsr{   r   rw   rx   r   )rw   rx   r   	secs_left )r]   r   phasephase_labelis_nightsheriffr   r   r  rV   
transcriptdeathsprivaterh   )#r   is_aliver-   r   r	   viewrT   r  setr   rc   r   r  namer   r   r  r  dead	role_namecheck_resultsknife_targetr  rh   r   maxr   roundrt   r]   r   r  PHASE_LABELr   NIGHT)r!   r  r   pvr  rV   rn   rrevealtxr  r  rh   blefts    `             r"   framezWerewolfEngine.frame   s   
 nZDJ$7$7$?$? ?Z4
HYCZCZMTTjodj&$*MM*,IIC%%%CEE	
()) 	 	A
4:--a001ATV4/SQ&[5RANFLLDJ$7$7$:$:!tzOaJa"(2df<VAFFRV       	Bdj3CDD9::DAR<S<SBBbmCDD122DMMB 	d!|RW$T$T$T$T1C$T$T$T$\X\!#!1BOXZXbd dG ; 	fACD55>>[3q#eAgJ$<==>>???W[Di6AEE&MM`deeFZ_TZ^djFV&??4:+;R@@djN^bcbiNiz)TZ5Fs^d"7^d	
 
 	
r%   c                	    t           j         j        _        d  j        _        d }t                      }d }                     d j        j         d           dddd}ddd	d} j        D ]m j	                 j
        }                      fd
          }|s1                     d|                    |d                     ||v r                     ||                    |dk    r                      fd          }|rg }	|D ]}
 j                             j        |
|          pi }|                    d          } j                            dd| d|                    dd                                           |
d           ||v r|	                    |           |	r:t'          |	                              d          d         d         }| j        _        z|dk    r|D ]fd j                                        D             } j                             j        |          }||v rX                     |          j        dk    rdnd} j        j                            g                               ||d           )|dk    r=|D ]9 j        j                            ddd          } j        j                            d d          }|d!         o|d uo|k    p|}|d"         }fd# j                                        D             } j                             j        ||||          }|r/|                    d$          r|                    |           d|d!<    j        j                            d%d&          }|r;|                    d"          |v r$|s|                    d$          s|d"         }d|d"<   ;o                     dd'           g }|%||vr!|                    |t           j         f           |!|                    |t           j!        f           |D ] \  }} j        "                    ||           !|D ]\  }} #                    ||           d S )(Nu   第 u    天,天黑请闭眼。u%   天黑了 · 狼人睁眼行动中…u"   天黑了 · 预言家查验中…u   天黑了 · 女巫抉择中…)r   checkrX   u)   狼人请睁眼,今晚你们要猎杀谁?u#   预言家请睁眼,你要查验谁?u#   女巫请睁眼,今晚是否用药?c                @    j                             |           k    S r   )r   rc   )rn   role_idr!   s    r"   r   z'WerewolfEngine._night.<locals>.<lambda>0  s    4:+=+=a+@+@G+K r%   nightu   天黑了 · 夜晚行动中…r   c                @                         |           j        dk    S r   r   r   s    r"   r   z'WerewolfEngine._night.<locals>.<lambda>7  s    djjmm.@F.J r%   r   	wolf_chatu
   提议刀 u    号 —— messager  r   )r   channelr   r   r.  c                     g | ]
}|k    |S r   r   )r   rn   seers     r"   r   z)WerewolfEngine._night.<locals>.<listcomp>F  s    NNN1AIIQIIIr%   good)r   resultrX   FrY   witch_self_saverZ   r[   c                     g | ]
}|k    |S r   r   )r   rn   witchs     r"   r   z)WerewolfEngine._night.<locals>.<listcomp>Q  s    PPPAQ%ZZaZZZr%   save witch_save_and_poison_same_nightTu   天亮结算中…)$r   r%  r   r  
last_knifer  r   r   r`   rT   rd   r   r}   r   rP   r#   r   stripr   r   most_commonr   r*   r   r   seer_checks
setdefaultre   r]   optionsr1   addCAUSE_KNIFECAUSE_POISONr   _maybe_hunter_shoot)r!   r+   savedpoison_targetNIGHT_BANNERNIGHT_NARRATEactionactorscands	proposalswdr   respotself_save_okr,   r.   pcandsboth_okr  r   causer0  r7  r<  s   `                      @@@r"   r  zWerewolfEngine._night"  s+   7
 $
#%%'+DTZ^DDDEEE GRv'HJ J!LW|(MO O( )	K )	KGZ(5F[[!K!K!K!K!KLLF Wl&6&6v?`&a&abbb&&mF3444$J$J$J$JKK 6 "I# 0 0 M66tz1eLLRPREE(OO
))+7iA7i7iSTSXSXYbdfSgSg7i7i7o7o7q7q/0& * B B B::%,,Q///  6 '	 2 2 > >q A A! DQ G05
-7""" i iDNNNN
(>(>(@(@NNNE224:tUKKAEzz(,

1(:f(D(Dff&
.99$CCJJVWcfKgKghhhi =((# K KE*266u5\a>b>bccC#':#5#9#9:KU#S#SL":i53Di%SX.Jh\hH!$XJPPPP)?)?)A)APPPF224:ueXWacijjA BAEE&MM B		%(((E#j/"j0445WY]^^G! KaeeHoo&?&?W&?TUTYTYZ`TaTa&?()(US]"6777(*e!3!3MM5!-0111$MM=!.9:::! 	) 	)KD%JOOD%((((! 	2 	2KD%$$T51111	2 	2r%   c                    t          | j                                                  D ]1}t          j        | j        |fd                                           2dS )ui  脑层钩子:每天收尾触发各存活 agent 的记忆压缩。
        ★后台 fire-and-forget(不 barrier 等待):压缩是 LLM 调用,若卡在这里等齐会让"下一阶段发言前傻等很久"(bug8);
          改为后台线程跑,自然在随后的黑夜阶段(本就要花时间)完成,不阻塞推进。RandomProvider 为 no-op,开销可忽略。Tr   N)r   r   r   r   r   _safe_digestr   )r!   rn   s     r"   r  zWerewolfEngine._digest_daye  sc     dj,,..// 	W 	WAD$5QDNNNTTVVVV	W 	Wr%   c                    	 | j                             | j        |           d S # t          $ r<}t                              d|t          |          d d                    Y d }~d S d }~ww xY w)Nu$   [digest] %d号 后台压缩失败:%sr   )rP   rF   r   r   r   r   r=   )r!   r   r   s      r"   rZ  zWerewolfEngine._safe_digestl  s    	VM$$TZ66666 	V 	V 	VNNA4QPSQSPSUUUUUUUUU	Vs    $ 
A*1A%%A*	dead_seatrX  c                   | j         | j                                               }|j        dk    s|t          j        k    rd S fd| j                                        D             }|sd S | j                            | j        |          }||v rj| j        	                    |t          j
                   | j                            d d| d           |                     |t          j
                   d S d S )Nhunter_shootc                     g | ]
}|k    |S r   r   )r   rn   r\  s     r"   r   z6WerewolfEngine._maybe_hunter_shoot.<locals>.<listcomp>v  s    GGGqYr%   shotu   号开枪带走了r   r   )rT   r   rc   on_deathr   rG  r   rP   rC   r   
CAUSE_SHOTr   rH  )r!   r\  rX  r  rO  r   s    `    r"   rH  z"WerewolfEngine._maybe_hunter_shootr  s   z$*,,Y778=N**eq~.E.EFGGGGDJ2244GGG 	FM--dj)UKK::JOOAq|,,,Jf&L&La&L&L&LS\]]]$$Q55555 :r%   r   c           	     f    |r  j         j        r                                  t          j         j        _         fd j        j        D             }                     |sdn1dd	                    d t          |          D                       z   dz   d                                             t          j         j        _                             d                                                                 d	d
          }                                  |s                                  d S d S )Nc                    g | ]K}|d          j         j        k    r3|d         t          j        t          j        t          j        fv C|d         LS )r   rX  r   )r   r   r   rF  rG  rb  )r   rR  r!   s     r"   r   z'WerewolfEngine._day.<locals>.<listcomp>  sW     V V V1QuX=W=W7q~q|'TTT vYTTTr%   u.   天亮了。昨晚是平安夜,无人死亡。u   天亮了。昨晚，   、c              3      K   | ]	}| d V  
dS r   Nr   r   rn   s     r"   r   z&WerewolfEngine._day.<locals>.<genexpr>  s(      ?e?ea1			?e?e?e?e?e?er%   u    倒在了血泊中。r   u@   现在进入发言环节,请各位依次陈述、各抒己见。speechT)r   )r]   r  _sheriff_electionr   DAY_ANNOUNCEr   r  r  r   r   r   r   
DAY_SPEECHr   _speech_orderr   	_day_vote)r!   r   	overnightexplodeds   `   r"   r  zWerewolfEngine._day  sb    	%TZ' 	%""$$$>
V V V V
(9 V V V	i AFF2UZZ?e?eSYZcSdSd?e?e?e5e5ee  iA  A  CM	N 	N 	N$$&&&<
XYYY%%d&8&8&:&:HTX%YY 	NN	 	r%   c                >   | j                                         }| j         j        }||vr|S |                    |          }||dz   d         |d|         z   }|                     d| d|           t          | j        dd          }|r || j         |          ndpi }|                    d          dv r|                    d          nd	}|d	k    r|nt          t          |                    }|d	k    rd
nd}	| 
                    | d|	 dd           ||gz   S )u`   发言序:有警长则由警长定序(选左/右手边起,自己压轴);无警长按座位序。r   Nr   u+   号警长定序中 · 选择发言方向…r   r6   	direction)cwccwrs  u   左手边(座位顺位)u   右手边(座位逆位)u   号警长决定:从自己u   起依次发言,自己压轴。r  )r   r   r  indexr}   r   rP   r   r   reversedr   )
r!   r
  shr   othersr   choicerr  seqsides
             r"   rm  zWerewolfEngine._speech_order  sM   
&&((ZU??LKKOOq1uvvrr*r$V$V$V]_```T]$7>>(*4""TZ$$$;/5zz+/F/F-/W/WFJJ{+++]a	!T))fftHV4D4D/E/E,5,=,=((C\[[d[[[]fgggbTzr%   c                    t           j         j        _                             d                                dd                                 j                                         fd          fd j                                        D             s,                     dd                                             d S t           j	         j        _                             dd	
                    d
 D                       z   dz   d                                d                                dd                                 fd          fdD             }fdD             |r6                     d	
                    d |D                       dz   d           s,                     dd                                             d S t           j         j        _                             d           fd j                                        D             }                     |fdd          }                     |d           t          fd|                                D                       }                     |          }| j        _                             |r| dndd                                             d S )Nu>   第一天,先选警长。想竞选警长的玩家,请表态。r   u!   全场同时决定是否上警…c                D    j                             j        |           S r   )rP   r4   r   r   s    r"   r   z2WerewolfEngine._sheriff_election.<locals>.<lambda>  s    (H(HUV(W(W r%   c                >    g | ]}                     |          |S r   r   )r   rn   runss     r"   r   z4WerewolfEngine._sheriff_election.<locals>.<listcomp>  s(    IIIATXXa[[IaIIIr%   u"   无人竞选警长,警徽流失。r  u   上警玩家:re  c              3      K   | ]	}| d V  
dS rg  r   rh  s     r"   r   z3WerewolfEngine._sheriff_election.<locals>.<genexpr>  s(      2Q2Qa9992Q2Q2Q2Q2Q2Qr%   u   ,请依次发表竞选宣言。sheriff_speechu!   上警玩家抉择是否退水…c                .                         |           S r   )_ask_withdrawr   s    r"   r   z2WerewolfEngine._sheriff_election.<locals>.<lambda>  s    $2D2DQ2G2G r%   c                >    g | ]}                     |          |S r   r  r   rn   wds     r"   r   z4WerewolfEngine._sheriff_election.<locals>.<listcomp>  s(    8881bffQii8Q888r%   c                >    g | ]}                     |          |S r   r  r  s     r"   r   z4WerewolfEngine._sheriff_election.<locals>.<listcomp>  s(    ===A266!99=a===r%   c              3      K   | ]	}| d V  
dS rg  r   rh  s     r"   r   z3WerewolfEngine._sheriff_election.<locals>.<genexpr>  s(      $B$B1YYY$B$B$B$B$B$Br%   u    宣布退水,退出竞选。u(   上警玩家全部退水,警徽流失。uJ   请未上警/已退水的玩家同时投票,选出你心目中的警长。c                    g | ]}|v|	S r   r   )r   rn   r   s     r"   r   z4WerewolfEngine._sheriff_election.<locals>.<listcomp>  s#    QQQAQj=P=Pa=P=P=Pr%   c                "    t                    S r   )r   )r   r   s    r"   r   z2WerewolfEngine._sheriff_election.<locals>.<lambda>  s    D<L<L r%   r   c              3  $   K   | ]
}|v |V  d S r   r   )r   r   r   s     r"   r   z3WerewolfEngine._sheriff_election.<locals>.<genexpr>  s'       P PqZ P Pr%   u3   号当选警长,获得 1.5 票与发言定序权。u"   警长竞选平票,警徽流失。)r   SHERIFF_RUNr   r  r   r}   r   r   r   SHERIFF_SPEECHr   r   SHERIFF_VOTEr   r   r   values_top_or_noner  )	r!   	withdrawn
electorater   tallyr  r   r  r  s	   `     @@@r"   rj  z WerewolfEngine._sheriff_election  s)   =
VWWW$GHHH~~dj4466WWWWY YIIII!7!7!9!9III
 	MM>	JJJ   F+
o

2Q2Qj2Q2Q2Q(Q(QQTuu  xA  	B  	B  	B:'7888$GHHH^^J(G(G(G(GHH8888
888	=======
 	qMM%**$B$B	$B$B$BBBEddfoppp 	MMDiPPP   F>
bcccQQQQ!7!7!9!9QQQ
%%j2L2L2L2LiXXWn555  P P P PGNN,<,< P P PPP##E**$
Y`  KUUUU  gK  MV  	W  	W  	Wr%   c                    t          | j        dd           }	 |rt           || j        |                    ndS # t          $ r Y dS w xY w)Nr8   Fr   r   s      r"   r  zWerewolfEngine._ask_withdraw  sc    T]$5t<<	13>44:t,,---> 	 	 	55	r   c                ~   | j         j        }|| j                             |          rdS | j                                         }t	          | j        dd          }d}|r(|r&	  || j         ||          }n# t          $ r d}Y nw xY w||v r|nd}|| j         _        |                     |r| d| dn| dd           dS )u   警长已不在场(被刀/毒/枪/放逐)→ 由倒下的警长移交警徽给一名存活者,或撕毁(bug9)。幂等:警长健在则不动。Nr:   u+   号(警长)倒下,临终将警徽移交给 u   号。u:   号(警长)倒下,警徽被撕毁,本局不再设警长。r  )r   r  r  r   r   rP   r   r   )r!   rw  rO  r   r   s        r"   r   z&WerewolfEngine._transfer_badge_if_dead  s   Z:,,R00:F
&&((T]$7>> 	% 	DJE22   !U??#
Z` ]VVVVVV \\\^g	i 	i 	i 	i 	is   !A4 4BBc                n   t           j        | j        _        |                     d           | j                                        fd}|                     |d          }|                     |d           t                      }|	                                D ]O\  }}| ||          v r=||xx         | 
                    |          j        || j        j        k    rdndz  z  cc<   P|                     |          }t           j        | j        _        |                                  ||                     dd           d S | j                            |t           j                   |                     | dd           |                     |t           j                   |                                  d S )	NuG   发言结束,请大家同时投票,放逐一名你最怀疑的玩家。c                "      fdD             S )Nc                     g | ]
}|k    |S r   r   )r   rn   r   s     r"   r   z>WerewolfEngine._day_vote.<locals>.<lambda>.<locals>.<listcomp>  s    999A!q&&a&&&r%   r   )r   r
  s   `r"   r   z*WerewolfEngine._day_vote.<locals>.<lambda>  s    9999999 r%   r   r   g      ?rp   u"   投票平票,本轮无人出局。u   号被投票放逐,请离场。)r   DAY_VOTEr   r  r   r   r   r   r   r   r   vote_weightr  r  	DAY_EXILEr   r   CAUSE_EXILErH  r   )r!   r   r   r  r   r   exiledr
  s          @r"   rn  zWerewolfEngine._day_vote  s   :
_```
&&((9999%%eXw??Wn555  	j 	jHE1HHUOO##aDJJu--9ETZM_D_D_SSehii""5));
>MM>HHHF
...@@@'JJJ  777$$&&&&&r%   r  r   c                    |sdS t          |                                          fd|                                D             }| j                            |          S )uW   最高票者;平票按 rng 在并列者中裁决(保证推进,PK 流程留待 M1/M2)。Nc                &    g | ]\  }}|k    |S r   r   )r   rn   r   tops      r"   r   z/WerewolfEngine._top_or_none.<locals>.<listcomp>  s"    ;;;A!s((1(((r%   )r"  r  r   rQ   ry  )r!   r  leadersr  s      @r"   r  zWerewolfEngine._top_or_none  sZ     	4%,,..!!;;;;;;;xw'''r%   c                   | j         j        rdS |                                 sd| j         _        n| j        j        dk    r5|                                 r|                                 sd| j         _        nD| j        j        dk    r4|                                 s |                                 sd| j         _        | j         j        rCt          j        | j         _	        | 
                    d| j         j        dk    rdndz   d	           dS d
S )NTr8  	kill_sider   kill_allu   游戏结束。u   狼人阵营获胜!u&   狼人全部出局,好人阵营获胜!endF)r   r   r   r]   winr   r   r   ENDr  r   r   s    r"   r  zWerewolfEngine._check_win  s   : 	4!!## 	' &DJZ^{**D4D4D4F4F*dNcNcNeNe* &DJZ^z))43C3C3E3E)I^I^I`I`) &DJ: 	 uDJMM+
HY]cHcHc/D/DGIJOQ Q Q4ur%   r   )
rM   rN   rO   r=   rP   r   rQ   rR   r   rD   )rp   )rq   rr   r   rD   )Nr\   )
rw   r=   rx   r=   r   r&   ry   rr   r   rD   )r   rD   )r   r   rx   r=   r   rD   )r   )rx   r=   r   r=   r   rD   )r   r   r   r   )r   r   rw   r=   r   r   )r   r   r   r=   r   rD   )r   r   r   rD   )r   r   r   r=   )F)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   rX  r=   r   rD   )r   r-   r   rD   )r  r   r   r&   )r   r-   )$rG   rH   rI   ro   rv   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r,  r  r  rZ  rH  r  rm  rj  r  r   rn  r  r  r   r%   r"   rL   rL   7   s       04    .) ) ) ) )L L L L L      g g g g    "       i i i i= = = =5 5 5 5    0   4 4 4 4@ @ @ @C C C CG G G GL L L L! ! ! !$#
 #
 #
 #
 #
LA2 A2 A2 A2FW W W WV V V V6 6 6 6   "   "" " " "H   i i i i$' ' ' ',( ( ( (     r%   rL   c                  j    e Zd ZdZdddZd Zd	 Zd
 Zd Zd Z	d Z
d Zd Zd Zd Zd Zd Zd ZdS )RandomProviderul   随机但合法的决策(M0 跑通流程 / 后续真人超时托管的兜底 bot)。给种子即可复现。NrQ   rR   r   rD   c                :    |pt          j                    | _        d S r   )r^   r_   rQ   )r!   rQ   s     r"   ro   zRandomProvider.__init__  s    )&-//r%   c                D    |r| j                             |          nd ddS )Nu   随便挑一个边路的。)r   r4  rQ   ry  r    s       r"   r#   zRandomProvider.wolf_discuss  s)    9CM$(//*555Zwxxxr%   c                >    |r| j                             |          nd S r   r  r    s       r"   r(   zRandomProvider.decide_kill       .8Btxz***dBr%   c                >    |r| j                             |          nd S r   r  r    s       r"   r*   zRandomProvider.decide_check  r  r%   c                    |o| j                                         dk     }|r;|s9|r7| j                                         dk     r| j                             |          nd }||dS )Ng333333?g333333?)r=  r[   )rQ   r^   ry  )	r!   r   r   r+   r,   r.   r/   r=  r[   s	            r"   r1   zRandomProvider.decide_witch  s}    3DHOO--3 k)-k2CkHLHYHY\_H_H_ (//"3444fj 	///r%   c                <    | j                                         dk     S )Ng      ?rQ   r^   r3   s      r"   r4   z!RandomProvider.decide_run_sheriff$  s    x  3&&r%   c                >    d| j                             ddg          iS )Nrr  rs  rt  r  r3   s      r"   r6   z RandomProvider.decide_speech_dir'  s    TX__dE];;<<r%   c                <    | j                                         dk     S )NgQ?r  r3   s      r"   r8   zRandomProvider.decide_withdraw*  s    x  4''r%   c                >    |r| j                             |          nd S r   r  r    s       r"   r:   z RandomProvider.decide_badge_pass-  r  r%   c                    dS )NFr   r3   s      r"   r<   zRandomProvider.decide_explode0  s    ur%   c                    | dS )Nu   号发言。r   r3   s      r"   r?   zRandomProvider.speak3  s    $$$$r%   c                >    |r| j                             |          nd S r   r  r    s       r"   rA   zRandomProvider.decide_vote6  r  r%   c                >    |r| j                             |          nd S r   r  r    s       r"   rC   z"RandomProvider.decide_hunter_shoot9  r  r%   c                    d S r   r   r3   s      r"   rF   zRandomProvider.digest_day<  s    tr%   r   )rQ   rR   r   rD   )rG   rH   rI   rJ   ro   r#   r(   r*   r1   r4   r6   r8   r:   r<   r?   rA   rC   rF   r   r%   r"   r  r    s       vv* * * * *y y yC C CC C C0 0 0' ' '= = =( ( (C C C  % % %C C CC C C    r%   r  )-rJ   
__future__r   r^   r   rt   collectionsr   pathlibr   typingr   r   genesis.obs.logging_setupr   genesis.werewolfr	   genesis.werewolf.boardr
   r   r   r   genesis.werewolf.rolesr   r   r   r   genesis.werewolf.stater   r   r   LOBBYr  r  r  r%  rk  rl  r  r  r  r$  r   rL   r  r   r%   r"   <module>r     s    # " " " " "                   % % % % % % % % 0 0 0 0 0 0 ' ' ' ' ' ' O O O O O O O O O O O O 3 3 3 3 3 3 3 3 ' ' ' ' ' ' , , , , , ,	%	&	&
 G^Q]NA<LnNNAG->P[L.!*nak>[\[`bpC C C C Cx C C C$U U U U U U U Up. . . . . . . . . .r%   