
    ˖6j\B                    J   d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	 ddl
mZ ddl
mZ ddlmZ dd	lmZ  e	d
          ZddddddgZd#dZd$dZ G d de          Z G d d          Z G d d          Z G d d          Z G d d           Z G d! d"          ZdS )%u  M2:人在环中。把"真人座位"接进引擎 —— **不改引擎**,只加一个路由 provider:

真人座位走 HumanController(命令行 / 测试脚本 / 将来的 web),其余座位走 AI(MindProvider);
真人输入超时或无效 → 回落到 AI/随机托管,世界绝不卡住。
真人若是狼,wolf_discuss 时会看到狼私聊频道里 AI 队友先发的提议(信息差已由 perception 保证)。
    )annotationsN)OptionalProtocol)
get_logger)
perception)state)BoardMemory)RandomProviderzwerewolf.humancwu$   从我左手边起 →(座位顺位))valuelabelccwu$   从我右手边起 ←(座位逆位)sOptional[str]returnOptional[int]c                    | pd                                 } |                     d                                          rt          |           nd S )N -)striplstripisdigitintr   s    1/root/genesis-world/src/genesis/werewolf/human.py
_parse_intr      s@    	
bAXXc]]**,,63q666$6    boolc                V    | pd                                                                 dv S )Nr   )yyesu   是u   救u   好1true)r   lowerr   s    r   _yesr%   #   s(    G??""$$(VVVr   c                  $    e Zd ZdZddZdddZdS )HumanControlleruw   真人交互通道。kind:'seat'(从 candidates 选座位/可跳)| 'yesno' | 'text'。None=超时/跳过→AI 托管。textstrr   Nonec                    d S N selfr(   s     r   showzHumanController.show)         r   Npromptkind
candidatesOptional[list]r   c                    d S r,   r-   r/   r2   r3   r4   s       r   askzHumanController.ask*   r1   r   r(   r)   r   r*   r(   Nr2   r)   r3   r)   r4   r5   r   r   __name__
__module____qualname____doc__r0   r8   r-   r   r   r'   r'   '   s7         B  B****kkkkkkkr   r'   c                  $    e Zd ZdZddZdddZdS )CLIHumanu(   命令行通道:终端里文字试玩。r(   r)   r   r*   c                *    t          d|z              d S )N
)printr.   s     r   r0   zCLIHuman.show/   s    dTkr   Nr2   r3   r4   r5   r   c                J    	 t          |dz             S # t          $ r Y d S w xY w)N )inputEOFErrorr7   s       r   r8   zCLIHuman.ask2   s;    	#&&& 	 	 	44	s    
""r9   r:   r;   r<   r-   r   r   rB   rB   -   sG        22         r   rB   c                  .    e Zd ZdZdddZdd
ZdddZdS )ScriptedHumanud   测试用:按队列回答;队列空了返回 None(→ AI 托管)。记录展示过的文本备查。Nanswersr5   r   r*   c                @    t          |pg           | _        g | _        d S r,   )listrL   shown)r/   rL   s     r   __init__zScriptedHuman.__init__;   s     GMr** "


r   r(   r)   c                :    | j                             |           d S r,   )rO   appendr.   s     r   r0   zScriptedHuman.show?   s    
$r   r2   r3   r4   r   c                b    | j         r't          | j                             d                    nd S )Nr   )rL   r)   popr7   s       r   r8   zScriptedHuman.askB   s,    +/<As4<##A&&'''TAr   r,   )rL   r5   r   r*   r9   r:   r;   )r=   r>   r?   r@   rP   r0   r8   r-   r   r   rK   rK   9   sg        nn# # # # #       B B B B B B Br   rK   c                  F    e Zd ZdZdddZdd
ZdddZddZddZddZ	dS ) WebHumanControlleru   网页通道:ask 阻塞对局线程,等 /api/action 提交答案(或超时→None→AI 托管)。
    线程安全:对局线程调 ask 阻塞在 Event 上;HTTP 线程调 submit 唤醒、调 pending 取当前待输入。     V@timeoutfloatr   r*   c                    || _         t          j                    | _        t          j                    | _        d | _        d | _        d| _        d| _	        d S )Ng        r   )
rX   	threadingLock_lockEvent_event_answer_pending	_deadline_seq)r/   rX   s     r   rP   zWebHumanController.__init__I   sG    ^%%
o''&*(,			r   r(   r)   c                    d S r,   r-   r.   s     r   r0   zWebHumanController.showR   s    r   Nr2   r3   r4   r5   r   c                   | j         5  | xj        dz  c_        | j        |||d| _        t          j                    | j        z   | _        d | _        | j        	                                 d d d            n# 1 swxY w Y   | j        
                    | j                  }| j         5  |r| j        nd }d | _        d d d            n# 1 swxY w Y   |s-t                              dt          | j                             |S )N   )idr2   r3   r4   u1   [web] 真人 %ss 未响应 → AI 托管该决策)r]   rc   ra   time	monotonicrX   rb   r`   r_   clearwaitloggerinfor   )r/   r2   r3   r4   gotanss         r   r8   zWebHumanController.askU   ss   Z 	  	 IINII#'9\fggDM!^--<DNDLK	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  kt|,,Z 	! 	!"%/$,,4C DM	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!  	`KKKSQUQ]M^M^___
s$   A"A66A:=A:'CC
C
answerr   c                    | j         5  | j        	 ddd           dS |dnt          |          | _        | j                                         	 ddd           dS # 1 swxY w Y   dS )uR   HTTP 线程:提交真人答案,唤醒对局线程。返回是否确有待输入。NFr   T)r]   ra   r)   r`   r_   set)r/   rp   s     r   submitzWebHumanController.submitd   s    Z 	 	}$	 	 	 	 	 	 	 	 "(22S[[DLKOO	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   	A2AA!$A!Optional[dict]c           	        | j         5  | j        s	 d d d            d S t          | j                  }t          dt	          | j        t          j                    z
                      |d<   |cd d d            S # 1 swxY w Y   d S )Nr   seconds_left)r]   ra   dictmaxr   rb   rh   ri   )r/   ps     r   pendingzWebHumanController.pendingm   s    Z 	 	= 	 	 	 	 	 	 	 	 T]##A #As4>DN<L<L+L'M'M N NAn	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   	A9AA99A= A=c                    | j         5  d| _        d| _        | j                                         ddd           dS # 1 swxY w Y   dS )uq   玩家退出/座位被夺回时强制结束当前等待:ask 立刻返回 None → AI 托管,绝不卡住对局。N)r]   r`   ra   r_   rr   r/   s    r   releasezWebHumanController.releaseu   s    Z 	 	DL DMKOO	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   (=AA)rW   )rX   rY   r   r*   r9   r:   r;   )rp   r)   r   r   )r   rt   r   r*   )
r=   r>   r?   r@   rP   r0   r8   rs   rz   r}   r-   r   r   rV   rV   F   s        } }                      r   rV   c                  x    e Zd ZdZddZddZ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 )HumanSeatProvideruV   实现 DecisionProvider:human_seat 走 controller,其余委托给内层 AI provider。
human_seatr   
controllerr'   r   r*   c                >    || _         || _        || _        || _        d S r,   )r   air   roles)r/   r   r   r   r   s        r   rP   zHumanSeatProvider.__init__   s"    $$


r   seatr   c                    || j         k    S r,   )r   r/   r   s     r   	_is_humanzHumanSeatProvider._is_human   s    t&&r   c                    t          j        || j        | j                  }| j                            t          | j                                      |d                     d S N   )transcript_tail)r   viewr   r   r   r0   r	   render)r/   r   vs      r   _show_boardzHumanSeatProvider._show_board   sS    OE4?DJ??[99@@TV@WWXXXXXr   c                D   |                      |          s| j                            |||          S |                     |           t	          | j                            dd|                    }| j                            dd          pd}||vr|r|d         nd }||dS Nu"   【狼队私聊】你提议刀谁?r   u%   【狼队私聊】给队友说一句:r(   r   r   )targetmessage)r   r   wolf_discussr   r   r   r8   )r/   r   r   r4   tmsgs         r   r   zHumanSeatProvider.wolf_discuss   s    ~~d## 	A7''tZ@@@t**+PRXZdeeffo!!"I6RRXVXJ!+5
1A,,,r   c                    |                      |          s| j                            |||          S t          | j                            dd|                    }||v r|n|r|d         nd S Nu   【你·刀人】今晚刀谁?r   r   )r   r   decide_killr   r   r8   r/   r   r   r4   r   s        r   r   zHumanSeatProvider.decide_kill   ss    ~~d## 	@7&&udJ???t**+KVU_``aaOOqq:*O*Q--4Pr   c                   |                      |          s| j                            |||          S |                     |           t	          | j                            dd|                    }||v r|n|r|d         nd S Nu   【你·查验】今晚验谁?r   r   )r   r   decide_checkr   r   r   r8   r   s        r   r   zHumanSeatProvider.decide_check   s    ~~d## 	A7''tZ@@@t**+KVU_``aaOOqq:*O*Q--4Pr   c                h   |                      |          s| j                            ||||||          S |                     |           |r,t	          | j                            d| dd                    nd}d }|r1t          | j                            dd|                    }	|	|v r|	nd }||dS Nu   【你·女巫】今夜 u!    号倒在刀下,用解药救吗?yesnoFu/   【你·女巫】要用毒药毒谁?(可不毒)r   )savepoison)r   r   decide_witchr   r%   r   r8   r   )
r/   r   r   knifecan_save
can_poisonpoison_candidatesr   r   ry   s
             r   r   zHumanSeatProvider.decide_witch   s    ~~d## 	e7''tUHjRcddd {C  NtDO''(k5(k(k(kmtuuvvv  IN 	;4?../`bhj{||}}A000QQdF///r   c                    |                      |          s| j                            ||          S |                     |           t	          | j                            dd                    S Nu'   【你·竞选】上警竞选警长吗?r   )r   r   decide_run_sheriffr   r%   r   r8   r/   r   r   s      r   r   z$HumanSeatProvider.decide_run_sheriff   sd    ~~d## 	;7--eT:::DO''(QSZ[[\\\r   c                    |                      |          s| j                            ||          S |                     |           | j                            ddt                    }d|dv r|ndiS NuG   【你·警长定序】从哪边开始发言?(你将压轴最后发言)choice	direction)r   r   r   )r   r   decide_speech_dirr   r   r8   SPEECH_DIR_OPTIONS)r/   r   r   ro   s       r   r   z#HumanSeatProvider.decide_speech_dir   s    ~~d## 	:7,,UD999o!!"kmu  xJ  K  KC=$8$8SSdCCr   c                    |                      |          s| j                            ||          S |                     |           t	          | j                            dd                    S Nu@   【你·退水】竞选发言后,是否退水退出警长竞选?r   )r   r   decide_withdrawr   r%   r   r8   r   s      r   r   z!HumanSeatProvider.decide_withdraw   sd    ~~d## 	87**5$777DO''(jlsttuuur   c                    |                      |          s| j                            |||          S |                     |           t	          | j                            dd|                    }||v r|nd S NuK   【你·移交警徽】你(警长)出局,把警徽交给谁?(跳过=撕毁)r   )r   r   decide_badge_passr   r   r   r8   r   s        r   r   z#HumanSeatProvider.decide_badge_pass   s    ~~d## 	F7,,UD*EEEt**+x  {A  CM  N  N  O  OOOqq-r   c                    |                      |          s| j                            ||          S |                     |           t	          | j                            dd                    S Nu[   【你·自爆】轮到你发言,是否自爆?(掀桌亮狼身份,中止今天直接入夜)r   )r   r   decide_exploder   r%   r   r8   r   s      r   r   z HumanSeatProvider.decide_explode   sz    ~~d## 	77))%666DO''  )F  HO  P  P  Q  Q  	Qr   c                    |                      |          s| j                            ||          S |                     |           | j                            dd          pdS Nu+   【你·发言】轮到你了,说点什么:r(   u   (我先听听大家的))r   r   speakr   r   r8   r   s      r   r   zHumanSeatProvider.speak   s`    ~~d## 	.7==---""#PRXYYv]vvr   c                "   |                      |          s| j                            |||          S |                     |           |j        t
          j        k    rdnd}t          | j        	                    |d|                    }||v r|nd S Nu'   【你·警徽投票】投谁当警长?u)   【你·投票】投谁出局?(可弃票)r   )
r   r   decide_voter   phaseSSHERIFF_VOTEr   r   r8   )r/   r   r   r4   r2   r   s         r   r   zHumanSeatProvider.decide_vote   s    ~~d## 	@7&&udJ????D{an?\?\;;B 	t**66:FFGGOOqq-r   c                    |                      |          s| j                            |||          S |                     |           t	          | j                            dd|                    }||v r|nd S Nu,   【你·开枪】开枪带走谁?(可放弃)r   )r   r   decide_hunter_shootr   r   r   r8   r   s        r   r   z%HumanSeatProvider.decide_hunter_shoot   s{    ~~d## 	H7..udJGGGt**+Y[acmnnooOOqq-r   c                f    |                      |          s| j                            ||          S d S r,   )r   r   
digest_dayr   s      r   r   zHumanSeatProvider.digest_day   s3    ~~d## 	37%%eT222tr   N)r   r   r   r'   r   r*   r   r   r   r   r~   )r=   r>   r?   r@   rP   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r-   r   r   r   r   }   s2       ``   ' ' ' 'Y Y Y Y
- - -Q Q QQ Q Q	0 	0 	0] ] ]D D Dv v v. . .Q Q Qw w w. . .. . .    r   r   c                      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 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 )&MultiHumanProvideru  多真人版路由 provider:每个真人座位挂一个 WebHumanController;attach/detach 动态切换 真人↔AI
    —— 这正是『退出→AI补位、回来→夺回原座位』的落点。无 controller 的座位一律走 AI。线程安全(并发投票)。r   r*   c                `    || _         || _        i | _        t          j                    | _        d S r,   )r   r   _controllersr[   r\   r]   )r/   r   r   s      r   rP   zMultiHumanProvider.__init__   s+    
;=^%%


r   r   r   r   rV   c                Z    | j         5  || j        |<   d d d            d S # 1 swxY w Y   d S r,   r]   r   )r/   r   r   s      r   attachzMultiHumanProvider.attach   s{    Z 	1 	1&0Dd#	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1s    $$c                    | j         5  | j                            |d           }d d d            n# 1 swxY w Y   |r|                                 d S d S r,   )r]   r   rT   r}   )r/   r   cs      r   detachzMultiHumanProvider.detach   s    Z 	2 	2!%%dD11A	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	IIKKKKK	 	s   044r   c                V    | j         5  || j        v cd d d            S # 1 swxY w Y   d S r,   r   r   s     r   	has_humanzMultiHumanProvider.has_human   sy    Z 	- 	-4,,	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	-s   	""rr   c                l    | j         5  t          | j                  cd d d            S # 1 swxY w Y   d S r,   )r]   rr   r   r|   s    r   human_seatszMultiHumanProvider.human_seats  s|    Z 	* 	*t())	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	*s   )--Optional[WebHumanController]c                x    | j         5  | j                            |          cd d d            S # 1 swxY w Y   d S r,   )r]   r   getr   s     r   _ctrlzMultiHumanProvider._ctrl  s    Z 	/ 	/$((..	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/s   /33c           	         |                     t          |                              t          j        ||| j                  d                     d S r   )r0   r	   r   r   r   r   )r/   r   r   r   s       r   _showzMultiHumanProvider._show  sF    	{4  ''
tTZ(P(Pbd'eefffffr   c                8   |                      |          }|| j                            |||          S |                     |||           t	          |                    dd|                    }|                    dd          pd}||vr|r|d         nd }||dS r   )r   r   r   r   r   r8   )r/   r   r   r4   r   r   r   s          r   r   zMultiHumanProvider.wolf_discuss  s    JJt97''tZ@@@

1eT"""quuA6:VVWWee;VDDJJ!+5
1A,,,r   c                    |                      |          }|| j                            |||          S t          |                    dd|                    }||v r|n|r|d         nd S r   )r   r   r   r   r8   r/   r   r   r4   r   r   s         r   r   zMultiHumanProvider.decide_kill  so    JJt97&&udJ???quu=vzRRSSOOqq:*O*Q--4Pr   c                   |                      |          }|| j                            |||          S |                     |||           t	          |                    dd|                    }||v r|n|r|d         nd S r   )r   r   r   r   r   r8   r   s         r   r   zMultiHumanProvider.decide_check"  s    JJt97''tZ@@@

1eT"""quu=vzRRSSOOqq:*O*Q--4Pr   c                \   |                      |          }|| j                            ||||||          S |                     |||           |r't	          |                    d| dd                    nd}d }	|r,t          |                    dd|                    }
|
|v r|
nd }	||	dS r   )r   r   r   r   r%   r8   r   )r/   r   r   r   r   r   r   r   r   r   ry   s              r   r   zMultiHumanProvider.decide_witch*  s    JJt97''tUHjRcddd

1eT"""lttAEE]U]]]_fgghhhz 	;155!RTZ\mnnooA000QQdF///r   c                    |                      |          }|| j                            ||          S |                     |||           t	          |                    dd                    S r   )r   r   r   r   r%   r8   r/   r   r   r   s       r   r   z%MultiHumanProvider.decide_run_sheriff6  sc    JJt97--eT:::

1eT"""AEECWMMNNNr   c                    |                      |          }|| j                            ||          S |                     |||           |                    ddt
                    }d|dv r|ndiS r   )r   r   r   r   r8   r   )r/   r   r   r   ro   s        r   r   z$MultiHumanProvider.decide_speech_dir=  sw    JJt97,,UD999

1eT"""ee]_gi{||C=$8$8SSdCCr   c                    |                      |          }|| j                            ||          S |                     |||           t	          |                    dd                    S r   )r   r   r   r   r%   r8   r   s       r   r   z"MultiHumanProvider.decide_withdrawE  sd    JJt97**5$777

1eT"""AEE\^effgggr   c                    |                      |          }|| j                            |||          S |                     |||           t	          |                    dd|                    }||v r|nd S r   )r   r   r   r   r   r8   r   s         r   r   z$MultiHumanProvider.decide_badge_passL  s    JJt97,,UD*EEE

1eT"""quujlrt~  A  AOOqq-r   c                    |                      |          }|| j                            ||          S |                     |||           t	          |                    dd                    S r   )r   r   r   r   r%   r8   r   s       r   r   z!MultiHumanProvider.decide_explodeT  sw    JJt97))%666

1eT"""AEEw  zA  B  B  C  C  	Cr   c                    |                      |          }|| j                            ||          S |                     |||           |                    dd          pdS r   )r   r   r   r   r8   r   s       r   r   zMultiHumanProvider.speak[  s_    JJt97==---

1eT"""uuBFKKhOhhr   c                    |                      |          }|| j                            |||          S |                     |||           |j        t
          j        k    rdnd}t          |                    |d|                    }||v r|nd S r   )	r   r   r   r   r   r   r   r   r8   )r/   r   r   r4   r   r2   r   s          r   r   zMultiHumanProvider.decide_voteb  s    JJt97&&udJ???

1eT"""?D{an?\?\;;B 	quuVVZ8899OOqq-r   c                    |                      |          }|| j                            |||          S |                     |||           t	          |                    dd|                    }||v r|nd S r   )r   r   r   r   r   r8   r   s         r   r   z&MultiHumanProvider.decide_hunter_shootl  sy    JJt97..udJGGG

1eT"""quuKVU_``aaOOqq-r   c                f    |                      |          | j                            ||          S d S r,   )r   r   r   r   s      r   r   zMultiHumanProvider.digest_dayt  s1    ::d#7%%eT222tr   Nr~   )r   r   r   rV   r   r*   )r   r   r   r*   r   )r   rr   )r   r   r   r   )r=   r>   r?   r@   rP   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r-   r   r   r   r      s       Z Z& & & &1 1 1 1   - - - -* * * */ / / /g g g g	- 	- 	-Q Q QQ Q Q
0 
0 
0O O OD D Dh h h. . .C C Ci i i. . .. . .    r   r   )r   r   r   r   )r   r   r   r   )r@   
__future__r   r[   rh   typingr   r   genesis.obs.logging_setupr   genesis.werewolfr   r   r   genesis.werewolf.boardmemoryr	   genesis.werewolf.enginer
   rl   r   r   r%   r'   rB   rK   rV   r   r   r-   r   r   <module>r      s(    # " " " " "      % % % % % % % % 0 0 0 0 0 0 ' ' ' ' ' ' ' ' ' ' ' ' 4 4 4 4 4 4 2 2 2 2 2 2	$	%	%
 CDDDEE 7 7 7 7
W W W Wl l l l lh l l l	 	 	 	 	 	 	 	
B 
B 
B 
B 
B 
B 
B 
B4 4 4 4 4 4 4 4nl l l l l l l l^K K K K K K K K K Kr   