
    IjM                    p   d Z ddlmZ ddl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  e
e      j                         j                  d   Zedz  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&dZd'dZd(d)dZd(d)dZ efd*dZ!d+dZ"e#dk(  r e"        yy),zHSummarize currently playable map progression from confirmed transitions.    )annotationsN)defaultdictdeque)Path	urlencode   outc                "    |  dt        |       S )Nz/game.html?r   )
web_prefixparamss     8/home/exedev/hwanse/tools/summarize_playable_progress.pyweb_hrefr      s    \Yv%6$788    c                0    t         | z  j                         S N)OUTexists)relative_hrefs    r   out_artifact_existsr      s    -''))r   c                4    t        |      r	d|  d| dS |  dS )N[]()z not generated)r   labelr   s     r   markdown_optional_linkr      s,    =)5'M?!,,WN##r   c                    t        |      r/dt        j                  |       dt        j                  |        dS dt        j                  |        dS )Nz	<a href="">z</a>z<span class="missing">z not generated</span>)r   htmlescaper   s     r   html_optional_linkr"      sM    =)4;;}56bU9K8LDQQ#DKK$6#77LMMr   c                &   g }t               }t        ||v r|gng       }|rp|j                         }||v r|j                  |       |j	                  |       t        | j                  |g             D ]  }||vs|j	                  |        |rp|S r   )setr   popleftaddappendsortedget)graphmaps	start_map	reachableseenqueuesourcetargets           r   reachable_fromr2   %   s    I5Dd!29+;E
T> UYYvr23 	%FT!V$	%  r   c           	     <   g }t        |       D ]x  }t        |      D cg c]  \  }}||k(  r|||f   D ]  }|  }}}}|j                  d        |j                  |t        | ||      |r|d   d   |d   d   dnd d       z t        |d       S c c}}}w )	Nc                    | d   | d   | d   fS )Nyxr1    )points    r   <lambda>z(entry_routes_for_graph.<locals>.<lambda>>   s    U3ZsU8_,U r   keyr   r6   r5   )r6   r5   )startMapr-   	startTilec                *    t        | d          | d   fS )Nr-   r<   )lenrows    r   r9   z(entry_routes_for_graph.<locals>.<lambda>D   s    CK0@,A+A3z?*S r   )r(   sortr'   r2   )	r*   r+   edge_pointsroutesr0   edge_source_targetr8   start_pointss	            r   entry_routes_for_graphrH   5   s    F-  )/{(;
 
$Wf$$k7%;<	
  

 
 	UV'tV<S_|As3,q/#:NOei
 	 &STT
s   B
c                z    t               }g }| D ])  }||v r|j                  |       |j                  |       + |S r   )r$   r&   r'   )valuesr.   resultvalues       r   uniquerM   G   sE    5DF D=e	
 Mr   c                   g }t        | xs i j                               D ]  \  }}||vr|j                  d      xs g D ]  }||vs||k(  r|j                  d      xs g D cg c].  }||j                  d      xs |j                  d      xs g v r|0 }}|j                  ||t        |D ch c]%  }|j                  d      s|j                  d      ' c}      t        |D ch c]%  }|j                  d      s|j                  d      ' c}      t	        |      d         |S c c}w c c}w c c}w )N	fieldMapsrecordstargetsselectorleafPointerHex)r0   r1   	selectorsleafPointersrecordCount)r(   itemsr)   r'   r?   )save_selector_scene_linksr+   edgesr0   entryr1   recordrP   s           r   selector_candidate_edgesr\   R   sG   E!:!@b G G IJ ii,2 	FT!Vv%5 $ii	28bfjj3Tvzz+7NTRTU G 
 LL  #'$lU[U_U_`jUkVZZ
%;$lm &SZ'{^d^h^hiy^z

3C(D'{ |"7| 	$ L %m'{s   %3D10D6D6)D; D;c           	        t        t              }t        t              }| j                  d      xs g D ]  }|j                  d      }|j                  d      }t	        |t
              rt	        |t
              sF||   j                  |       |j                  d      xs g D ]<  }|||f   j                  |j                  dd      |j                  dd      |d       >  ||fS )	NconfirmedEdgesr0   r1   pointsr6   r   r5   r6   r5   r1   )r   r$   listr)   
isinstancestrr&   r'   )summaryr*   rC   edger0   r1   r8   s          r   confirmed_graphrf   i   s    !,S!1E5@5FK,-3 (#(#&#&j.Ef&!XXh'-2 	E()00YYsA&YYsA& 2 	 +r   c                   g }| xs g D ]N  }|j                  d      }||vr|j                  d      xs g D ]  }|j                  d      dk7  r|j                  d      xs i }|j                  d      }|j                  d      }t        |t              rt        |t              sqt        g |j                  d      xs g |j                  d	      xs g       }	|	D ]r  }
|
|k(  s|
|vr|j	                  ||
|j                  d
      |||j                  d      |j                  d      |j                  d      |j                  d      d	       t  Q |j                  d        |S )NmapexitCandidatespromotionStatuszmanual-review-onlysampler6   r5   blockedTargetCandidatesselectorTargetCandidatesside	standable	reviewUrltrialUrl)	r0   r1   rn   r6   r5   ro   statusrp   rq   c                N    | d   | d   | j                  d      xs d| d   | d   fS )Nr0   r1   rn    r5   r6   r)   items    r   r9   z*map_exit_candidate_edges.<locals>.<lambda>   s6    hh&AQAWUWY]^aYbdhildm n r   r:   )r)   rb   intrM   r'   rB   )map_exit_candidatesr+   rY   rA   r0   	candidaterk   r6   r5   rQ   r1   s              r   map_exit_candidate_edgesr{   {   sz   E"(b !128b 	I}}./3GG]]8,2F

3A

3Aa%Z3-? -- 9:@b-- :;Ar G " V#vT'9$$%MM&1!'K!8'mm,=>!*{!; )j 9
 
		< 
JJnJoLr   c                   t        |       \  }}t        ||      }|D ]E  }||d      j                  |d          ||d   |d   f   j                  |d   |d   |d   d       G t	        ||| j                  dd            }t        | j                  d      xs g       }|D cg c]  }|d   |v r	|d   |vr| }	}t        |      }
|D cg c]  }|d   |
v r	|d   |
v r| }}| j                  t        |      t        |D ch c]  }|d   |d   f c}      |t        |      t        |||      |	|d	       | S c c}w c c}w c c}w )
Nr0   r1   r6   r5   r`   r<   rt   reachableFromStart)mapExitTrialTransitionCountmapExitTrialEdgeCountmapExitTrialReachableFromStartmapExitTrialReachableCountmapExitTrialEntryRoutesmapExitTrialFrontiermapExitTrialReachableEdges)
rf   r{   r&   r'   r2   r)   r$   updater?   rH   )rd   ry   r+   r*   rC   
exit_edgesre   r-   confirmed_reachablefrontierreachable_setreachable_edgess               r   annotate_map_exit_trial_routesr      s   (1E;)*=tDJ d8n!!$x.1T(^T(^45<<cc8n>
 	 udGKK
B,GHIgkk*>?E2F#>00T(^K^5^ 	H  	NM#>]*tH~/N 	O  NN'*:!$S]%^4tH~tH~&F%^!_*3&))n#9%{#S (&5  N%
 &_s   $D<EEc                0   |j                         D cg c]  }|j                  d      dk(  s| }}|j                         D cg c]  }|j                  d      dk(  s| }}t        t              }	t        t              }
|D ]6  }|d   }|d   }|	|   j                  |       |
||f   j                  |       8 t        |	| |      }t        |	| |
      }t        t              }|xs g D ]n  }|j                  d      }|j                  d      xs t        |j                  d      xs d      }t        |t              sV|sY|||f   j                  |       p t        t              }t        t              }|
j                         D ]2  \  \  }}}||   j                  |       |||f   j                  |       4 t        t              }|xs g D ]  }|j                  d      d	k(  s|j                  d
      s*t        |j                  d      t              sJ|j                  d      | v s^|j                  d      | v sr|j                  d      xs t        |j                  d      xs d      }||d   ||d   f   j                  |        |j                         D ]  \  \  }}}}t        d |D              }|D ]j  }|d   |k7  r|d   }|d   }||   j                  |       |||f   j                  |d   |d   ||j                  d      |j                  d      dd       l  t        || |      }t        t              }t        t              }|
j                         D ]2  \  \  }}}||   j                  |       |||f   j                  |       4 t        ||       }|D ]C  }|d   }|d   }||   j                  |       |||f   j                  dd|d|d   |d   d       E t        || |      } t        |      }!|D cg c]  }|d   |!v r	|d   |!vr| }"}t        |       }#|D cg c]  }|d   |#v r	|d   |#v r| }$}t        || |      }%t        t              }&|D ]  }'|&|'d      j                  |'        t        t              }(|"D ]  }|(|d      j                  |        g })|D ]  }|	j                  |      r|&j                  |g       }*|(j                  |g       }+|)j                  |dt!        |*      t#        |*D 'ch c]  }'|'j                  d      xs g D ]  }|   c}}'      t#        |+D ch c]  }|d   	 c}      t!        |+      |*sdndd        g },g }-|D ]"  }'|'d   }|'j                  d      xs g }.|'j                  d      xs g }/|'j                  d      xs t        |'j                  d      xs d      }|j                  ||fg       }0|D ch c]2  }|d   |k(  r(|j                  d      |'j                  d      k(  r|d   4 }1}|.D cg c]	  }||1vs| }2}|2s|0D cg c]<  }|j                  d      |2v r'|j                  d      d	k(  r|j                  d
      r|> }3}t#        |3d       d d }4|,j                  ||'j                  d      |'j                  d      |'j                  d       t!        |/      |2t!        |3      d!       |-j                  ||'j                  d      |'j                  d      |'j                  d       t!        |/      t!        |2      |2t!        |3      |4r|4d   j                  d      nd |4r+|4d   d   |4d   d   |4d   d   |4d   j                  d      d"nd d#
       % |-j%                  d$        i d%|d&t!        |       d't!        |      d(t!        |      d)t!        |
      d*|d+t!        |      d,|d-t'        d. |j                         D              d/t!        |      d0t        || |      d1|d2t!        |      d3| d4t!        |       d5|%d6|"|$t#        |
j                               D 5cg c]Q  \  \  }}}||t#        |D 5cg c]-  }5|5d   |5d   |5j                  d7      |5j                  d8      d9/ c}5d:       d;S c}5}}}|)|,|-d<S c c}w c c}w c c}w c c}w c c}}'w c c}w c c}w c c}w c c}w c c}5w c c}5}}}w )=Nstate	confirmedrejectedr0   r1   recordVaHexrecordVart   
unreviewedsourceStandableactiveDistancec              3  &   K   | ]	  }|d      yw)r   Nr7   ).0gaps     r   	<genexpr>z build_summary.<locals>.<genexpr>   s     <c*+<s   r6   r5   activeNearest)r6   r5   r1   r   r   trialr   saveSelectorSceneLinkrT   rU   )r6   r5   r1   r   rT   rU   rh   rQ   z9no strict event transition records on the confirmed routez5event transition records exist but none are confirmed)rh   confirmedOutgoingEdgeseventTransitionRecordseventTargetssaveSelectorFrontierTargetssaveSelectorFrontierCountreasonr_   c                    | j                  dd      | j                  d      xs d| j                  dd      | j                  dd      fS )Nr   '  r1   rt   r5   r   r6   ru   )r   s    r   r9   zbuild_summary.<locals>.<lambda>Q  sC    GG,d3GGH%+GGCOGGCO	! r   r:   r	   
sceneIdHex	eventKind)r0   r   r   r   r_   rQ   standableUnreviewedPoints)r6   r5   r1   r   )
r0   r   r   r   r_   targetCountrQ   r   nearestActiveDistancefirstStandablePointc                    | j                  d      | j                  d      nd| d   | d    | d   | j                  d      xs dfS )Nr   r   r   r   r0   r   rt   ru   r@   s    r   r9   zbuild_summary.<locals>.<lambda>w  sT    038O0P0\CGG+,bf,--MGGM"(b
 r   r<   mapCountconfirmedTransitionCountrejectedTransitionCountconfirmedEdgeCountr}   reachableCountconfirmedEntryRoutes!trialActiveNearestTransitionCountc              3  X   K   | ]"  }|D ]  }|j                  d       dk(  sd  $ yw)r   r   r	   Nru   )r   rW   rw   s      r   r   z build_summary.<locals>.<genexpr>  sG       1Ruch  1R[_lpltltu|l}  BQ  mQ  1R  1Rs   *	*trialActiveNearestEdgeCount$trialActiveNearestReachableFromStarttrialActiveNearestEntryRoutessaveSelectorCandidateEdgeCount'saveSelectorCandidateReachableFromStart#saveSelectorCandidateReachableCount saveSelectorCandidateEntryRoutessaveSelectorCandidateFrontierspawnXspawnY)r6   r5   r   r   c                    | d   | d   fS )Nr5   r6   r7   rv   s    r   r9   zbuild_summary.<locals>.<lambda>  s    d3ic%; r   )r0   r1   r_   )#saveSelectorCandidateReachableEdgesr^   confirmedRouteBlockersunconfirmedTransitionRecordsnextReviewCandidates)rJ   r)   r   r$   ra   r&   r'   r2   rH   rc   rb   rW   extendrx   minr\   r?   r(   rB   sum)6r+   transitionsreviewsr,   transition_gap_rowsrX   reviewr   r   r*   confirmed_by_edger0   r1   r-   entry_routesgap_rows_by_recordr   r[   trial_graphtrial_by_edgerW   gap_rows_by_target_source_recordrF   gapsnearesttrial_entry_routesselector_graphselector_by_edgeselector_edgesre   selector_reachabler   selector_frontierselector_reachable_setselector_reachable_edgesselector_entry_routestransitions_by_sourcerA   selector_frontier_by_sourceconfirmed_route_blockers
event_rowsselector_rowscandidate_rowsnext_review_candidatesrQ   r_   record_gap_rowsconfirmed_targetsunconfirmed_targetsunconfirmed_standablefirst_standablerw   s6                                                         r   build_summaryr      s
    '.nn&6]F&**W:MQ\:\]I]%,^^%5[6G9LPZ9Z[H[!,S!1E;Ft;L ;!!f&!66*+226:	; udI6I)%7HIL<G<M"(b ="'I3swwz/B/Hb+Ifc"v/077<	= (33'7K7B47HM#4#:#:#< 6%F'vv&'..u56 BMTAR"(b 	SGGG,)*377#34c:!T)!T)WW]+Ms377:3F3L"/MFHvs8}EFMMcR	S .@-E-E-G )#'7T<t<< 	C#$/]F]F##F+66*+22XX "ww}5"%''*:";(4 	  0T=Q*5c*:N:Ed:K#4#:#:#< 9%v""6*&&)*11%89 ..GNN hhv""6*&&)*11,k* 03
 		 (iHi. #>00T(^K^5^ 	 
 !!34 # >33XJ`8` 	   
 3>4IYZ3>t3D 6c%j)00569DT9J! A#DN3::4@A! 99V*..vr:
377C ''&'&)*o"j#jsPSPWPWXaPbPhfh#jVF#jF#jk+1m2\d4>2\+]),]); " LL)
 	& N ;U'')$*"(b'I3swwz/B/Hb+I,00&&1A2F $
h6)

=)SWW]-CC 8
 
 5<_&vM^?^v__ +%778$(;;GGG$4GG-.	 %! % %% qO !! "ww}5!ggl3 WW[1f+.-01F-G#  #)) "ww}5!ggl3 WW[1f+"#67.-01F-GUd);)?)?@P)Qjn ' -Q/4,Q/4"1!"4X">*9!*<*@*@AQ*R	 %+ O;x 
   #I#CI# 	#C	N# 	"3x=	#
 	c"34# 	i# 	#i.# 	# 	,S  1R@T@T@V  1R  .R# 	&s='9# 	/{DR[0\# 	();# 	)#n*=# 	23E# 	.s3E/F#  	+,A!#" 	():##$ 0H ,22C2I2I2K+L
 
 ( % !   %  949@R^b^f^fgo^pq  <		
 #;(6 6E# #q ^[R , $k2\"
 `%`
s_   ccc"c"c'=c,#c1c7:7c<7	ddAd;d2dddc           	        |D ci c]%  }|j                  d      |j                  d      f|' }}| j                  d      xs g D ]  }|j                  |j                  d      |j                  d      f      }|s7|j                  d      |d<   |j                  d      |d<   t        |j                  d      xs g       |d<   |j                  d	      |d	<   |j                  d
      |d
<   |j                  d      xs g D cg c]$  }|j                  d      r|j                  d      & c}|d<    i }| j                  d      xs g D ]&  }|j                  |d   g       j                  |       ( | j                  d      xs g D ]n  }|j                  |j                  d            xs g }	|	D cg c]9  }|j                  d      |j                  d      |j                  d      xs g d; c}|d<   p | S c c}w c c}w c c}w )Nr0   r1   r   promotionRisknotepromotionNotebranchStepsbranchGateCountsourceTilesetMatchtargetTilesetMatch	conditionbranchConditionsr   rh   )r1   r   r   saveSelectorFrontierRisks)r)   r?   
setdefaultr'   )
rd   branch_rowsrA   risksre   risksteprisks_by_sourceblockersource_riskss
             r   %annotate_save_selector_frontier_risksr     s     
	CGGH-.3E  ;<B 
yy$((8,dhhx.@AB $ 9_ $ 0_"%dhh}&=&C"D%)XX.B%C!"%)XX.B%C!" /52$
xx$ HH[!$
 
 .0O;<B D""4>26==dCD;;78>B 	
&**7;;u+=>D" %0
 	 ((8,!%/!:$(HH-?$@$FB0
+,	
 N?$
0
s   *G>)H6>Hc                   ddddd| d    ddd| d    d	dd
| d    d	dd| d    d	dd| d    d	dddg}| d   r1| d   D ](  }t        |d|i      }|j                  d| d| d       * n|j                  d       |j                  g d       | d   D ]f  }|d   d   }t        ||d   |d    d|d    d      }d j                  d! |d   D              }|j                  d"|d    d#|d$    d#| d%| d&	       h | d   s|j                  d'       |j                  g d(       | j	                  d)g       D ]  }d j                  d* |j	                  d+      xs g D              xs( d j                  |j	                  d,      xs g       xs d-}	|j                  d"|d    d#|j	                  d.d       d#d j                  |j	                  d/      xs g       xs d- d#|	 d#|j	                  d0      xs d- d1        | j	                  d)      s|j                  d2       |j                  g d3       | d4   D ]l  }
d|
d   i}|
j	                  d5      r|
d5   d    d|
d5   d    |d5<   t        ||      }|j                  d"|
d    d#d j                  |
d6          d%| d&       n | d4   s|j                  d7       |j                  dd8dd9dd:| j	                  d;d       d	dd<| j	                  d=d       d	dd>t        | j	                  d?g              d	dd@dAg       | j	                  dBg       d dC D ]m  }
|
d   dDdE}|
j	                  d5      r|
d5   d    d|
d5   d    |d5<   t        ||      }|j                  d"|
d    d#d j                  |
d6          d%| d&       o | j	                  dB      s|j                  d7       |j                  ddFddGddH| j	                  dId       d	ddJ| j	                  dKd       d	ddL| j	                  dMd       d	ddNdOg       | j	                  dPg       d dC D ]  }|d   dQ|d    d|d    |d    d|d    dR}|d$   dSdT}|j                  d"|d    d#|d$    d#|j	                  dU      xs d- d#|d    d|d    d#|j	                  dV      xs d- dWt        ||       dXt        ||       d&        | j	                  dP      s|j                  dY       |j                  g dZ       | j	                  d[g       d dC D ]m  }
|
d   dQdE}|
j	                  d5      r|
d5   d    d|
d5   d    |d5<   t        ||      }|j                  d"|
d    d#d j                  |
d6          d%| d&       o | j	                  d[      s|j                  d7       |j                  dd\dd]dd^| j	                  d_d       d	dd`| j	                  dad       d	ddbdcg       | j	                  ddg       d dC D ]  }t        ||d   dSdSde      }t        ||d   dfdE      }t        ||d$   dSdSde      }d j                  |j	                  dg      xs g       xs d-}|j                  d"|d    d#|d$    d#|j	                  dh      xs d- d#| d#d j                  |j	                  di      xs g       xs d- d#d j                  |j	                  dj      xs g       xs d- dk| dl| dX| d&        | j	                  dd      s|j                  dm       |j                  g dn       | j	                  dog       d dC D ]H  }
|
d   dSdSdfdp}t        ||      }|j                  d"|
d    d#d j                  |
d6          d%| d&       J | j	                  do      s|j                  d7       |j                  g dq       | j	                  drg       d dC D ]i  }|j	                  ds      }|d   dSdSde}|d   dDdE}|r@|d    d|d    |d5<   |d    d|d    |dt<   |d$   |du<   |d    d|d    |d5<   |d$   |du<   |j	                  dv      r|dv   |dw<   |dv   |dw<   t        ||      }t        ||      }dx|d    dy}t        dz|      }|r|d    d|d    d{|d$    nd-}|r|j	                  d|      nd }|j                  d"|d    d#|d}    d#|d~    d#||nd- d#| d#|j	                  d      xs d- d#|j	                  d      |j	                  d      nd- d|j	                  dv      xs d- d| d| dl| d&       l | j	                  dr      s|j                  d       |j                  g d       | d   D ]  }t        ||d   dSdSde      }|j                  d"|d    d#|d    d#d j                  |d          d#|j	                  d~d       d#|j	                  d      xs d- d#|j	                  d      |j	                  d      nd- d|j	                  dv      xs d- d| d&        | d   s|j                  d       |j                  d       dj                  |      S )Nz# Playable Progressrt   zGenerated from confirmed transition reviews. Normal gameplay only uses confirmed transitions; unreviewed transitions require `events=1` debug mode.zStart map: `r<   z`.zMaps in build: r   .zConfirmed transition points: r   zConfirmed map edges: r   z0Reachable from start via confirmed transitions: r   z## Reachable Mapsr}   rh   z- [r   r   z- -)rt   z## Confirmed Edgesrt   z#| source | target | points | open |z| --- | --- | --- | --- |r^   r_   r   r0   r6   ,r5   rh   r=   , c           
   3  ~   K   | ]5  }|d     d|d    d|j                  d       d|j                  d        7 ywr6   r   r5    -> r   r   Nru   r   r8   s     r   r   zmarkdown.<locals>.<genexpr>  K      
 Szl!E#J<tEIIh,?+@%))HBUAVW
   ;=z| z | r1   z
 | [open](z) |z| - | - | - | - |)rt   z## Confirmed Route Blockersrt   zI| map | event records | event targets | save-selector frontier | reason |z | --- | ---: | --- | --- | --- |r   c              3  p   K   | ].  }|j                  d        d|j                  d      xs d d 0 ywr1   z (r   -r   Nru   r   rw   s     r   r   zmarkdown.<locals>.<genexpr>  >      #
 xx!""TXXo%>%E#$FaH#
   46r   r   r
  r   r   r   z |z| - | - | - | - | - |)rt   z## Confirmed Entry Routesrt   z%| start map | reachable maps | open || --- | --- | --- |r   r=   r-   z| - | - | - |z## Active-Nearest Trial Routesz`trialTransitions=activeNearest` keeps confirmed gameplay separate and lets the web runtime test one nearest standable unreviewed point per transition component.z(Trial active-nearest transition points: r   z Trial active-nearest map edges: r   z0Reachable from start with trial active-nearest: r   z+| start map | reachable maps | open trial |r  r      r   rh   trialTransitionsz## Map-Exit Trial Routesa  `trialTransitions=mapExitCandidates` keeps geometry-only edge exits separate from confirmed gameplay. These candidates are for manual route testing and must not be treated as confirmed transitions. `trialTransitions=routeAssist` combines selector-only links and geometry-only exits so the web runtime can keep playtesting past blockers without promoting them to confirmed route evidence.z"Map-exit trial transition points: r~   zMap-exit trial map edges: r   z+Reachable from start with map-exit trials: r   zQ| frontier source | target | side | point | status | trial source | open target |z+| --- | --- | --- | --- | --- | --- | --- |r   mapExitCandidatesrh   r  r=   	focusTile1rh   overviewrn   rr   z | [trial](z) | [target](z| - | - | - | - | - | - | - |)rt   z0| start map | reachable maps | open exit trial |r  r   z!## Save Selector Candidate RouteszThese routes add save-selector scene-link candidates on top of confirmed transitions. They are useful for review navigation, and `trialTransitions=routeAssist` can combine them with map-exit candidates, but they are not confirmed tile transitions.zSave-selector candidate edges: r   z4Reachable from start with save-selector candidates: r   zx| frontier source | target | risk | branch gates | selector | leaf pointers | open source | trial source | open target |z7| --- | --- | --- | --- | --- | --- | --- | --- | --- |r   rh   eventsr  routeAssistr   r   rT   rU   z | [source](z) | [trial](z%| - | - | - | - | - | - | - | - | - |)rt   z5| start map | reachable maps | open candidate route |r  r   rh   r  r  r  )rt   z## Next Review Candidatesrt   z| source | targets | standable unreviewed | active dist | first point | scene | kind | record | review | debug open | trial open |zG| --- | ---: | ---: | ---: | --- | --- | ---: | --- | --- | --- | --- |r   r   r  transitionTargetr   transitionRecordtransition_review_gaps/.htmlr   r  r   r   r   r   r   z | `z` | z | [debug](z-| - | - | - | - | - | - | - | - | - | - | - |)rt   z## Remaining Transition Recordsrt   zY| source | points | targets | standable unreviewed | scene | kind | record | debug open |z4| --- | ---: | --- | ---: | --- | ---: | --- | --- |r   rQ   z` | [debug](z!| - | - | - | - | - | - | - | - |
)r   r'   r   joinr)   r?   r   )rd   r   linesnamehrefre   firstr_   r   selector_risksrouter   trial_paramstarget_paramssource_href
trial_hreftarget_hrefbranch_gatesrA   
debug_hrefreview_hrefreview_cell
first_textactive_distances                           r   markdownr3    s:   
 	^

wz*+2.

'*-.a0

'0J(K'LAN

(< =>a@

:7CS;T:UUVW

!E$ #$01 	0DJ6DLL3tfBtfA./	0 	U	LL   () ]Xq!
DNERUJ<WXY^_bYcXdIe$fg 
h
 
 	r$x.)T(^,<CxzRVQWWZ[\] #$()	LL   ;;7< 	
 #
$?@FB#
 
 P YYw{{#@AGRHP MP 	 	 GKK0H!$L#MSyy^4:;BsC3c'++h"7">3!?rC	
	
 ;;/0,-	LL   /0 
z*+99[!%*;%7%<$=Qu[?QRU?V>W"XF;
F+z"#3tyy{1C'D&EZPTvUXY	

 )*_%	LL
(
 	l

27;;?bde3f2gghi

*7;;7TVW+X*YYZ[

:3w{{Kqsu?v;w:xxyz
5  <bA#2F 
z*P99[!%*;%7%<$=Qu[?QRU?V>W"XF;
F+z"#3tyy{1C'D&EZPTvUXY	

 ;;67_%	LL
"
 	N

,W[[9VXY-Z,[[\]

$W[[1H!%L$MQO

5gkkB^`a6b5ccde
[5  2B7< 
> 3 I;aS	{3 I;aS	{3	
 !%XC@h DN#33txx7G7N36OsCyk49+S();)Bs(C D
L9:-Q[]jHkGlloq	

 ;;-.45	LL  
 6;CR@ 
z*@ST99[!%*;%7%<$=Qu[?QRU?V>W"XF;
F+z"#3tyy{1C'D&EZPTvUXY	

 ;;01_%	LL
+
 	B

)'++6VXY*Z)[[\]

>w{{Kprs?t>uuvw
 	CA  ;R@"E 

z4>S^a+bcj$x.Vc*de
z4>S^a+bcyy*<!=!CDKh DN#33txx7P7WTW6XX[\h[iilyy+.4"5<=Syy.17R8?C@[M Z!l-}CA	


 ;;67<=	LL  
 ?DSbI 
z*cs`mn
F+z"#3tyy{1C'D&EZPTvUXY	

 ;;9:_%	LL   {{126s; 
-.X#3G"8}/R%*3ZL%*">F;%*3ZL%*">F;).xF%&+0:,ac
|(DL%/4XL+,77=!),]);F%&/2=/AL+,j&1
j,7
/HeD,X{CJOc
|1U3ZLU8_4EFUX
9>%))$45DXs3}#5"6c#>Y:Z9[[^"1"=3Gsl#cggl3:s;3'*ww{';'Gsww{#SQ R&-#.d;-{:,Vbcmbnnq	s	
'
4 ;;-.DE	LL   56 

CMSVY$Z[Xs3x=/TYYs9~5N4Osww2A67sww|$+,CP[H\Hh0Dnq/r s&-#.l4&E	

 1289	LL99Ur   c                   g }| d   D ]  }|d   d   }t        |d   |d    d|d    d      }d	j                  d
 |d   D              }|j                  dt        j                  |d          dt        j                  |d          dt        j                  |       dt        j                  |       d	        g }| j                  dg       d d D ]  }|j                  d      }|d   ddd}	|d   dd}
|r@|d    d|d    |	d<   |d    d|d    |	d<   |d   |	d<   |d    d|d    |
d<   |d   |
d<   |j                  d      r|d   |	d<   |d   |
d<   t        |	      }t        |
      }d|d    d}t        d|      }|r|d    d|d    d|d    nd }|r|j                  d!      nd }|j                  dt        j                  |d          d|d"    d|d#    d||nd  dt        j                  |       dt        j                  |j                  d$      xs d        d|j                  d%      |j                  d%      nd  d&t        j                  |j                  d      xs d        d'| dt        j                  |       d(t        j                  |       d)        g }| d*   D ]  }t        |d   ddd      }|j                  dt        j                  |d          d|d    dt        j                  d	j                  |d+                d|j                  d#d       dt        j                  |j                  d$      xs d        d|j                  d%      |j                  d%      nd  d&t        j                  |j                  d      xs d        d,t        j                  |       d-        d.j                  fd/| d0   D              xs d1}g }| d2   D ]  }d3|d4   i}	|j                  d      r|d   d    d|d   d    |	d<   t        |	      }|j                  dt        j                  |d4          dt        j                  d	j                  |d5                dt        j                  |       d        g }| j                  d6g       D ]  }d	j                  d7 |j                  d8      xs g D              xs( d	j                  |j                  d9      xs g       xs d }|j                  dt        j                  |d3          d|j                  d:d       dt        j                  d	j                  |j                  d;      xs g       xs d        dt        j                  |       dt        j                  |j                  d<      xs d        d=        g }| j                  d>g       d d D ]  }|d4   dd}	|j                  d      r|d   d    d|d   d    |	d<   t        |	      }|j                  dt        j                  |d4          dt        j                  d	j                  |d5                dt        j                  |       d?        g }| j                  d@g       d d D ]  }t        |d   dA|d    d|d    |d    d|d    dB      }t        |d   ddC      }|j                  dt        j                  |d          dt        j                  |d          dt        j                  |j                  dD      xs d        d|d    d|d    dt        j                  |j                  dE      xs d        dt        j                  |       dFt        j                  |       dG        g }| j                  dHg       d d D ]  }|d4   dAd}	|j                  d      r|d   d    d|d   d    |	d<   t        |	      }|j                  dt        j                  |d4          dt        j                  d	j                  |d5                dt        j                  |       d        g }| j                  dIg       d d D ]  }t        |d   ddd      }t        |d   dJd      }t        |d   ddd      }|j                  dt        j                  |d          dt        j                  |d          dt        j                  |j                  dK      xs d        dt        j                  d	j                  |j                  dL      xs g       xs d        dt        j                  d	j                  |j                  dM      xs g       xs d        dt        j                  d	j                  |j                  dN      xs g       xs d        dt        j                  |       dOt        j                  |       dFt        j                  |       dG        g }| j                  dPg       d d D ]  }t        |d4   dddJdQ      }|j                  dt        j                  |d4          dt        j                  d	j                  |d5                dt        j                  |       d        d.j                  g dRdSdTdUdVdWdXdY| dZ    d[dY| d\    d]dY| d^    d_dY| d`    dat        j                  | d4          dbdcdd| d`    dedfdg| dhdidjd.j                  |      xs dkdldmdnd.j                  |      xs dodldpdqd.j                  |      xs drdldsdtdXdY| j                  dud       dvdY| j                  dwd       dxdYt        | j                  dyg              dzt        j                  | d4          dbdcd{d.j                  |      xs d|dld}d~dXdY| j                  dd       ddY| j                  dd       ddY| j                  dd       dt        j                  | d4          dbdcdd.j                  |      xs ddldd.j                  |      xs ddldddXdY| j                  dd       ddY| j                  dd       dt        j                  | d4          dbdcdd.j                  |      xs ddldd.j                  |      xs ddlddd.j                  |      xs ddlddd.j                  |      xs ddl      S )Nr^   r_   r   r0   r6   r   r5   r   r  c           
   3  ~   K   | ]5  }|d     d|d    d|j                  d       d|j                  d        7 ywr  ru   r  s     r   r   zhtml_page.<locals>.<genexpr>  r  r  z<tr><td>z	</td><td>r1   z</td><td><a href="z">open</a></td></tr>r   r  r   r  r  r   r  r=   r  r  r   r  r  r  r   r  r
  r   r   r   r   r   z</td><td><code>z</code></td><td>z">debug</a></td><td><a href="z">trial</a></td></tr>r   rQ   z</code></td><td><a href="z">debug</a></td></tr>r   c           	   3     K   | ]?  }d t        j                  t        d|i             dt        j                  |       d A yw)z<li><a href="rh   r   z	</a></li>N)r    r!   r   )r   r#  r   s     r   r   zhtml_page.<locals>.<genexpr>  sI       HZ%$GHIDKKX\L]K^^ghs   AAr}   z
<li>-</li>r   rh   r<   r-   r   c              3  p   K   | ].  }|j                  d        d|j                  d      xs d d 0 ywr	  ru   r  s     r   r   zhtml_page.<locals>.<genexpr>  r  r  r   r   r   r   r   z
</td></tr>r   z">open trial</a></td></tr>r   r  r  r  rn   rr   z">trial</a></td><td><a href="z">target</a></td></tr>r   r   r  r   r   rT   rU   z">source</a></td><td><a href="r   r  z<!doctype html>z<meta charset="utf-8">z <title>Playable Progress</title>a  <style>body{font-family:system-ui,sans-serif;background:#111;color:#ddd;margin:24px}a{color:#8fd3ff}table{border-collapse:collapse;width:100%;margin:16px 0}td,th{border:1px solid #333;padding:6px 8px;text-align:left}th{background:#1f1f1f}.metrics{display:flex;gap:12px;flex-wrap:wrap}.metric{background:#1b1b1b;border:1px solid #333;padding:10px 12px}.metric strong{display:block;font-size:22px}.missing{color:#999}</style>z<h1>Playable Progress</h1>zx<p>Normal gameplay only uses confirmed transitions. Unreviewed transitions require <code>events=1</code> debug mode.</p>z<div class="metrics">z<div class="metric"><strong>r   z </strong><span>maps</span></div>r   z,</strong><span>confirmed points</span></div>r   z+</strong><span>confirmed edges</span></div>r   z</strong><span>reachable from z</span></div>z</div>z3<p>Reachable from start via confirmed transitions: z.</p>z<h2>Reachable Maps</h2>z<ul>z</ul>z<h2>Confirmed Edges</h2>z`<table><thead><tr><th>source</th><th>target</th><th>points</th><th>open</th></tr></thead><tbody>z1<tr><td colspan="4">No confirmed edges.</td></tr>z</tbody></table>z!<h2>Confirmed Route Blockers</h2>z<table><thead><tr><th>map</th><th>event records</th><th>event targets</th><th>save-selector frontier</th><th>reason</th></tr></thead><tbody>z:<tr><td colspan="5">No confirmed route blockers.</td></tr>z<h2>Confirmed Entry Routes</h2>z\<table><thead><tr><th>start map</th><th>reachable maps</th><th>open</th></tr></thead><tbody>z8<tr><td colspan="3">No confirmed entry routes.</td></tr>z$<h2>Active-Nearest Trial Routes</h2>z<p><code>trialTransitions=activeNearest</code> keeps confirmed gameplay separate and lets the web runtime test one nearest standable unreviewed point per transition component.</p>r   z(</strong><span>trial points</span></div>r   z'</strong><span>trial edges</span></div>r   z$</strong><span>trial reachable from zb<table><thead><tr><th>start map</th><th>reachable maps</th><th>open trial</th></tr></thead><tbody>z.<tr><td colspan="3">No trial routes.</td></tr>z<h2>Map-Exit Trial Routes</h2>a  <p><code>trialTransitions=mapExitCandidates</code> keeps geometry-only edge exits separate from confirmed gameplay. These candidates are for manual route testing and must not be treated as confirmed transitions. <code>trialTransitions=routeAssist</code> combines selector-only links and geometry-only exits so the web runtime can keep playtesting past blockers without promoting them to confirmed route evidence.</p>r~   z1</strong><span>map-exit trial points</span></div>r   z0</strong><span>map-exit trial edges</span></div>r   z'</strong><span>map-exit reachable from z<table><thead><tr><th>frontier source</th><th>target</th><th>side</th><th>point</th><th>status</th><th>trial source</th><th>open target</th></tr></thead><tbody>z3<tr><td colspan="7">No map-exit frontier.</td></tr>zg<table><thead><tr><th>start map</th><th>reachable maps</th><th>open exit trial</th></tr></thead><tbody>z1<tr><td colspan="3">No map-exit routes.</td></tr>z'<h2>Save Selector Candidate Routes</h2>a	  <p>These routes add save-selector scene-link candidates on top of confirmed transitions. They are useful for review navigation, and <code>trialTransitions=routeAssist</code> can combine them with map-exit candidates, but they are not confirmed tile transitions.</p>r   z9</strong><span>save-selector candidate edges</span></div>r   z(</strong><span>candidate reachable from z<table><thead><tr><th>frontier source</th><th>target</th><th>risk</th><th>branch gates</th><th>selector</th><th>leaf pointers</th><th>open source</th><th>trial source</th><th>open target</th></tr></thead><tbody>z8<tr><td colspan="9">No save-selector frontier.</td></tr>zl<table><thead><tr><th>start map</th><th>reachable maps</th><th>open candidate route</th></tr></thead><tbody>z6<tr><td colspan="3">No save-selector routes.</td></tr>z<h2>Next Review Candidates</h2>z<table><thead><tr><th>source</th><th>targets</th><th>standable unreviewed</th><th>active dist</th><th>first point</th><th>scene</th><th>kind</th><th>record</th><th>review</th><th>debug open</th><th>trial open</th></tr></thead><tbody>z9<tr><td colspan="11">No next review candidates.</td></tr>z%<h2>Remaining Transition Records</h2>z<table><thead><tr><th>source</th><th>points</th><th>targets</th><th>standable unreviewed</th><th>scene</th><th>kind</th><th>record</th><th>debug open</th></tr></thead><tbody>z3<tr><td colspan="8">No remaining records.</td></tr>)r   r!  r'   r    r!   r)   r"   r?   )rd   r   rowsre   r%  r$  r_   	next_rowsrA   r   r(  r.  r+  r/  r0  r1  r2  	remainingr-   
entry_rowsr'  blocker_rowsr   r&  
trial_rowsmap_exit_frontier_rowsr,  map_exit_route_rowsselector_frontier_rowsr*  selector_route_rowss    `                             r   	html_pagerB    s   D() 
Xq!
DNERUJ<WXY^_bYcXdIe$fg 
h
 
 	;;tH~./ 0;;tH~./ 0;;v&' ( KK-. /		

 I{{126s; !
-.X#3G"8}/R%*3ZL%*">F;%*3ZL%*">F;).xF%&+0:,ac
|(DL%/4XL+,77=!),]);F%&/2=/AL+,j&1
j,7
/HeD(;?JOc
|1U3ZLU8_4EFUX
9>%))$45D;;s8}-. /}%& '234 5&5&A?sK L;;z*+ ,;;sww|4;<= >+.77;+?+K377;'QTU VSWW]%;%BsCD E-   KK
34 5 KK
34 5	
'!
D I56 

CMSVY$Z[;;s8}-. /x=/ ";;tyyY89: ;776:; <;;sww|4;<= >+.77;+?+K377;'QTU VSWW]%;%BsCD E KK-. /		

 		 01   
  J/0 
z*+99[!%*;%7%<$=Qu[?QRU?V>W"XF;
F+;;uZ012 3;;tyy{);<=> ? KK-. /	

 L;;7< 
 #
$?@FB#
 
 P YYw{{#@AGRHP MP 	 	;;wu~./ 0;;7;< =;;tyy^)D)JKRsST U;;~./ 0;;w{{84;<= >	

 J<bA#2F 
z*P99[!%*;%7%<$=Qu[?QRU?V>W"XF;
F+;;uZ012 3;;tyy{);<=> ? KK-. /	

  2B7< 
j> 3 I;aS	{3 I;aS	{3	+
 
 z4>s+ST%%;;tH~./ 0;;tH~./ 0;;txx/6378 99+QtCyk *;;txx18S9: ; KK
34 5 KK45 6
	

& 6;CR@ 
z*@ST99[!%*;%7%<$=Qu[?QRU?V>W"XF;
F+"";;uZ012 3;;tyy{);<=> ? KK-. /	

  ;R@"E 
z4>S^a+bcj$x.Vc*de
z4>S^a+bc%%;;tH~./ 0;;tH~./ 0;;txx8?C@A B;;tyy2D)E)KLSPSTU V;;tyy+)>)D"ELMN O;;tyy.)A)GRHOCPQ R KK45 6 KK
34 5 KK45 6
	
	
" ?DSbI 

E*,=Z]  tA  %B  C"";;uZ012 3;;tyy{);<=> ? KK-. /	

 99 GG G 	+G 	r	G
 	%G 	CG 	 G 'wz':&;;[\G 'w/I'J&KKwxG 'w/C'D&EEpqG 'w/?'@&AA_`d`k`klst~l  aA  `B  BO  	PG 	G >gFV>W=XX]^G 	"G ykG  	#!G" 	k#G$ 			$NN%G& 	'G( 	,)G* 	W+G, 			,_#_-G. 	/G0 	*1G2 	g3G4 			*[![5G6 	7G8 	/9G: 	~;G< 	 =G> 'w{{3VXY'Z&[  \D  	E?G@ 'w{{3PRS'T&UU|}AGB 's7;;7]_a+b'c&d  eI  JN  JU  JU  V]  ^h  Vi  Jj  Ik  kx  	yCGD 	EGF 	mGGH 			*Q!QIGJ 	KGL 	)MGN 	kOGP 	 QGR 'w{{3PRS'T&U  VG  	HSGT 'w{{3JA'N&OO  	AUGV 'w{{3OQR'S&TT{  }A  }H  }H  IP  Q[  I\  }]  |^  ^k  	lWGX 	YGZ 	k[G\ 			()b-b]G^ 	_G` 	raGb 			%&]*]cGd 	eGf 	2gGh 	TiGj 	 kGl 'w{{3SUV'W&X  YR  	SmGn 'w{{3XZ['\&]  ^F  GK  GR  GR  SZ  [e  Sf  Gg  Fh  hu  	voGp 	qGr 	^sGt 			()g-guGv 	wGx 	wyGz 			%&b*b{G| 	}G~ 	*G@ 	tAGB 			)[ [CGD 	EGF 	0GGH 	yIGJ 			)U UKGL 	MG G Gr   c                    |j                  dd       |dz  j                  t        j                  | dd      dz   d	       |d
z  j                  t	        |       d	       y )NT)parentsexist_okzplayable_progress.jsonF   )ensure_asciiindentr   utf-8encodingplayable_progress.html)mkdir
write_textjsondumpsrB  )rd   out_dirs     r   write_outputsrR    sd    MM$M.''33

7q9D@ 4  ''33Ig4FQX3Yr   c                     t        j                         } | j                  dt        t        dz         | j                  dt        t        dz         | j                  dt        t        dz         | j                  dt        t        d	z         | j                  d
t        t        dz         | j                  dt        t        dz         | j                  dt        t        dz         | j                  dd       | j                  dt        t               | j                         }|j                  j                  d      }d}|j                  |      st        |j                   d      t        j                  |t        |      d  j                  d            }t        j                  |j                  j                  d            }t        j                  |j                  j                  d            }|j                   j#                         r/t        j                  |j                   j                  d            ng }|j$                  j#                         r/t        j                  |j$                  j                  d            ni }|j&                  j#                         r/t        j                  |j&                  j                  d            ng }	t)        ||||j*                  ||      }
t-        |
|	       |j.                  j#                         r:t1        |
t        j                  |j.                  j                  d            |       t3        |
|j4                         t7        d|j4                  dz          y )Nz--mapszmaps.js)typedefaultz--transitionszevent_transitions.jsonz	--reviewsztransition_reviews.jsonz--transition-gapsztransition_review_gaps.jsonz--save-selector-linkszsave_selector_scene_links.jsonz!--save-selector-frontier-branchesz$save_selector_frontier_branches.jsonz--map-exit-candidateszmap_exit_candidates.jsonz--start-mapmap1_02b)rU  z	--out-dirrI  rJ  zwindow.HWANSE_MAPS = z is not a maps.js filez;
)r   rX   zwrote playable progress -> rL  )argparseArgumentParseradd_argumentr   r   
parse_argsr+   	read_text
startswith
SystemExitrO  loadsr?   rstripr   r   transition_gapsr   save_selector_linkssave_selector_frontier_branchesr   r,   r   ry   r   rR  rQ  print)parserargs	maps_textprefixr+   r   r   r`  ra  rb  rd   s              r   mainrh    s   $$&F
tS9_E
dCBZ<Z[
$>W8WX
+$Fc@cd
/dCJjDjk
;$PSV|P|}
/dCJdDde
z:
$<D		##W#5I$F'DII;&<=>>::iF-44U;<D**T--777IJKjj///ABGVZVjVjVqVqVsdjj!5!5!?!?!?!QRy{O^b^v^v^}^}^$**T%=%=%G%GQX%G%YZ  FH //668 	

477AA7AST $
 +"5G *'3RS&&(&JJt//9979KL	

 '4<<(	'7O(O'P
QRr   __main__)r   rc   r   zdict[str, str]returnrc   )r   rc   rj  bool)r   rc   r   rc   rj  rc   )r*   dict[str, set[str]]r+   dictr,   rc   rj  	list[str])r*   rl  r+   rm  rC   z!dict[tuple[str, str], list[dict]]rj  
list[dict])rJ   rn  rj  rn  )rX   dict[str, dict] | Noner+   rm  rj  ro  )rd   rm  rj  z=tuple[dict[str, set[str]], dict[tuple[str, str], list[dict]]])ry   list[dict] | Noner+   rm  rj  ro  )rd   rm  ry   rq  r+   rm  rj  rm  )rV  NN)r+   rm  r   ro  r   zdict[str, dict]r,   rc   r   rq  rX   rp  rj  rm  )rd   rm  r   ro  rj  rm  )z../web)rd   rm  r   rc   rj  rc   )rd   rm  rQ  r   rj  None)rj  rr  )$__doc__
__future__r   rW  r    rO  collectionsr   r   pathlibr   urllib.parser   __file__resolverD  ROOTr   r   r   r   r"   r2   rH   rM   r\   rf   r{   r   r   r   r3  rB  rR  rh  __name__r7   r   r   <module>r|     s   N "    *  " H~''*
Ul9*$N U$.$!HJ  -18<c
cc c 	c
 +c  6c 
cL Fpftn 25 Z+S\ zF r   