\ProvidesFile{pgf-go-sgf.sty}[2026/10/30 v0.2026.10.30 pgf-go: SGF games] \ExplSyntaxOn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %-----------------------------------------COMUN-------------------------------------------------% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_generate_variant:Nn \msg_warning:nnn {nnV} \cs_generate_variant:Nn \msg_warning:nnnnn {nnnee} \cs_generate_variant:Nn \prop_if_in_p:Nn {NV} \cs_generate_variant:Nn \prop_item:Nn {NV} \cs_generate_variant:Nn \prop_put:Nnn {Nne} \cs_generate_variant:Nn \prop_gput:Nnn {Nne} \cs_generate_variant:Nn \str_case:nn {Vn} %LOS COMANDOS DE SGF NECESITAN UN KERNEL QUE LEA PARTIDAS (kernel = lua). \cs_new_protected:Npn \__pgfgo_sgf_if_kernel:n #1 { \pgfgo_kernel_if_feature:nTF {sgf} {#1} {\pgfgo_kernel_require:n {sgf}} } %EL TAMANO Y LOS PUNTOS blank DE LA ULTIMA PARTIDA LEIDA EN #1, COMO OPCIONES DE goban %(size = 19x19, blank = {...}). \tl_new:N \l__pgfgo_sgf_blank_tl \cs_new_protected:Npn \__pgfgo_sgf_board:N #1 { \pgfgo_goban_sgf_blank:N \l__pgfgo_sgf_blank_tl \tl_set:Ne #1 { size = \int_use:N \l_pgfgo_kernel_sgf_size_x_int x \int_use:N \l_pgfgo_kernel_sgf_size_y_int \tl_if_empty:NF \l__pgfgo_sgf_blank_tl {, blank = {\exp_not:V \l__pgfgo_sgf_blank_tl}} } } %LA CLAVE partial DE \sgfdiagrams, \sgfproblem Y \sgfanimation: auto (#1 VERDADERO), false O LAS ESQUINAS DE %UNA PARTE FIJA (B2:D4, COMO EN goban), QUE QUEDAN EN #2. LA PARTE FIJA ES LA DE TODOS LOS TABLEROS, AUNQUE %EL ARCHIVO TENGA VISTA. \cs_new_protected:Npn \__pgfgo_sgf_partial:NNn #1#2#3 { \bool_set_false:N #1 \tl_clear:N #2 \str_case:nnF {#3} { {auto} {\bool_set_true:N #1} {false} {} }{ \tl_set:Nn #2 {#3} } } %partial = auto EN \sgfdiagrams, \sgfproblem Y \sgfanimation: TODOS LOS TABLEROS TIENEN LA MISMA PARTE %VISIBLE, LA QUE USAN LAS LINEAS QUE SE DIBUJAN: TODO EL ARBOL DEL ARCHIVO #1 (\__pgfgo_sgf_extent:n, EN %\sgfproblem) O LAS LINEAS #2, SEPARADAS POR ; (\__pgfgo_sgf_extent:nn). \__pgfgo_sgf_extent_add: LA SUMA A LO %DIBUJADO DENTRO DE CADA goban (SI EL goban TODAVIA TIENE partial = auto). \tl_new:N \l__pgfgo_sgf_extent_tl \cs_new_protected:Npn \__pgfgo_sgf_extent:n #1 { \pgfgo_kernel_sgf_tree:n {#1} \tl_set_eq:NN \l__pgfgo_sgf_extent_tl \l_pgfgo_kernel_sgf_extent_tl } \cs_new_protected:Npn \__pgfgo_sgf_extent:nn #1#2 { \pgfgo_kernel_sgf_extent:nn {#1} {#2} \tl_set_eq:NN \l__pgfgo_sgf_extent_tl \l_pgfgo_kernel_sgf_extent_tl } \cs_generate_variant:Nn \__pgfgo_sgf_extent:nn {nV} \cs_new_protected:Npn \__pgfgo_sgf_extent_add: { \bool_lazy_and:nnT {\l_pgfgo_goban_partial_auto_bool} {! \tl_if_empty_p:N \l__pgfgo_sgf_extent_tl} {\exp_after:wN \__pgfgo_sgf_extent_add:nnnn \l__pgfgo_sgf_extent_tl} } \cs_new_protected:Npn \__pgfgo_sgf_extent_add:nnnn #1#2#3#4 { \pgfgo_kernel_extent_add:nn {#1} {#2} \pgfgo_kernel_extent_add:nn {#3} {#4} } %VERDADERO SI EL EVENTO {#1}{#2}{#3} DE \l_pgfgo_kernel_sgf_moves_seq ES UNA JUGADA (NO UN CAMBIO DE UN NODO %NI UN NUMERO). \prg_new_conditional:Npnn \__pgfgo_sgf_if_move:nnn #1#2#3 {T} { \str_case:nnF {#1} { {black} {\prg_return_true:} {white} {\prg_return_true:} }{ \prg_return_false: } } %DEJA EN #1 LA CANTIDAD DE JUGADAS DE LA ULTIMA PARTIDA LEIDA, SIN CONTAR MAS DE #2 (DEJA DE RECORRER AHI). \cs_new_protected:Npn \__pgfgo_sgf_count_moves:Nn #1#2 { \int_zero:N #1 \int_compare:nNnT {#2} > {0} { \seq_map_inline:Nn \l_pgfgo_kernel_sgf_moves_seq { \__pgfgo_sgf_if_move:nnnT ##1 { \int_incr:N #1 \int_compare:nNnF {#1} < {#2} {\seq_map_break:} } } } } %DEJA EN #1 EL NUMERO DE LA JUGADA #2 (SU POSICION EN EL ARCHIVO) DE LA ULTIMA PARTIDA LEIDA: EL QUE SIGUE A %MN, SIN restart. \int_new:N \l__pgfgo_sgf_moves_seen_int \cs_new_protected:Npn \__pgfgo_sgf_move_number:Nn #1#2 { \int_zero:N #1 \int_zero:N \l__pgfgo_sgf_moves_seen_int \seq_map_inline:Nn \l_pgfgo_kernel_sgf_moves_seq {\__pgfgo_sgf_move_number:Nnnnn #1 {#2} ##1} } \cs_new_protected:Npn \__pgfgo_sgf_move_number:Nnnnn #1#2#3#4#5 { \str_if_eq:nnTF {#3} {number} {\int_set:Nn #1 {#4 - 1}} { \__pgfgo_sgf_if_move:nnnT {#3} {#4} {#5} { \int_incr:N #1 \int_incr:N \l__pgfgo_sgf_moves_seen_int \int_compare:nNnF {\l__pgfgo_sgf_moves_seen_int} < {#2} {\seq_map_break:} } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %------------------------------------------\sgf-------------------------------------------------% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\sgf[from = , to = ]{} DIBUJA UNA PARTIDA EN EL goban ACTUAL. SOLO CON kernel = lua. %LAS PIEDRAS INICIALES (AB, AW) SON PIEDRAS COMO LAS DE \stones. LAS JUGADAS SON COMO LAS DE \moves: %ANTES DE from SIN NUMERO, DESDE from NUMERADAS, Y DESPUES DE to NO SE JUEGAN. AL TERMINAR, EL NUMERO %Y EL TURNO QUEDAN LISTOS PARA SEGUIR LA PARTIDA CON \moves. %from Y to SON POSICIONES DE JUGADA EN EL ARCHIVO (1, 2, 3...). EL NUMERO QUE SE MUESTRA PUEDE SER OTRO: %MN LO CAMBIA, Y restart LO REINICIA EN CADA TRAMO DE step JUGADAS (VER MAS ABAJO). restart = auto Y %numbers = auto HACEN LO QUE DICE PM: CON PM[2] SE REINICIA CADA 100, Y CON PM[0] NO SE NUMERA. \int_new:N \l__pgfgo_sgf_from_int \int_new:N \l__pgfgo_sgf_to_int \tl_new:N \l__pgfgo_sgf_last_mark_tl %LA CLAVE to: #1 = #3, O #2 SI #3 ES last O UN NUMERO NEGATIVO (HASTA LA ULTIMA JUGADA). \cs_new_protected:Npn \__pgfgo_sgf_set_to:Nnn #1#2#3 { \str_if_eq:nnTF {#3} {last} {\int_set:Nn #1 {#2}} { \int_compare:nNnTF {#3} < {0} {\int_set:Nn #1 {#2}} {\int_set:Nn #1 {#3}} } } \tl_new:N \l__pgfgo_sgf_variation_tl \bool_new:N \l__pgfgo_sgf_marks_bool \tl_new:N \l__pgfgo_sgf_numbers_tl \tl_new:N \l__pgfgo_sgf_variations_tl \tl_new:N \l__pgfgo_sgf_file_tl %restart Y numbers YA RESUELTOS (CON auto, SEGUN PM). restart: 0, NO SE REINICIA; 1, EN CADA TRAMO DE step; %2, CADA 100 (PM[2]). \int_new:N \l__pgfgo_sgf_restart_int \bool_new:N \l__pgfgo_sgf_numbers_bool %POSICION DE LA JUGADA EN EL ARCHIVO, NUMERO SIN REINICIAR (SIGUE A MN) Y NUMERO QUE SE MUESTRA. \int_new:N \l__pgfgo_sgf_count_int \int_new:N \l__pgfgo_sgf_number_int \int_new:N \l__pgfgo_sgf_shown_int %LA ULTIMA JUGADA QUE SE MUESTRA. \int_new:N \l__pgfgo_sgf_last_int %SI LA JUGADA QUE SE DIBUJA LLEVA NUMERO. \bool_new:N \l__pgfgo_sgf_numbered_bool %LO USA \sgfdiagrams: DESDE from, LAS PIEDRAS CAPTURADAS NO SE QUITAN DEL DIBUJO. \bool_new:N \l__pgfgo_sgf_keep_numbered_bool %LO USA \sgfdiagrams: SI NO ESTA VACIO, LA JUGADA from SE MUESTRA CON ESE NUMERO, Y LAS SIGUIENTES SIGUEN %DESDE AHI (SE SUMA \l__pgfgo_sgf_shift_int AL NUMERO). \tl_new:N \l__pgfgo_sgf_first_tl \int_new:N \l__pgfgo_sgf_shift_int %LAS ANIMACIONES SOLO COMPRUEBAN EL TAMANO EN EL PRIMER CUADRO. \bool_new:N \l__pgfgo_sgf_check_size_bool \bool_set_true:N \l__pgfgo_sgf_check_size_bool %LAS MARCAS Y LAS VARIANTES DE LA ULTIMA JUGADA QUE SE MUESTRA, "x,y" DE LOS PUNTOS QUE MARCAN (LES QUITAN %EL NUMERO) Y DE LOS QUE TIENEN UNA ETIQUETA DE LB (NO SE LO QUITAN). \seq_new:N \l__pgfgo_sgf_marks_seq \seq_new:N \l__pgfgo_sgf_variations_seq \prop_new:N \g__pgfgo_sgf_marked_prop \prop_new:N \g__pgfgo_sgf_labeled_prop %"x,y" DE LAS JUGADAS NUMERADAS (ANTES DE LAS MARCAS). \prop_new:N \l__pgfgo_sgf_numbered_prop \tl_new:N \l__pgfgo_sgf_mark_tl \bool_new:N \l__pgfgo_sgf_remove_warned_bool %LA NUMERACION DE \sgf, \sgfanimation Y \sgfdiagrams. LAS JUGADAS VAN EN TRAMOS DE step (UNA LISTA REPITE %EL ULTIMO TAMANO; EN \sgfdiagrams, CADA TRAMO ES UN DIAGRAMA). restart: true, DESDE EL SEGUNDO TRAMO CADA %UNO NUMERA DESDE from; false, LOS NUMEROS DE LA PARTIDA; auto, LO QUE PIDE PM (CON PM[2], CADA 100). %from TAMBIEN PRENDE restart. #1: EL ARBOL DE CLAVES, #2: EL PREFIJO DE LAS VARIABLES, #3: step INICIAL. %CLAVES: /pgfgo/{sgf, sgf animation, sgf diagrams}/{step, restart} %CLAVES: /pgfgo/{sgf, sgf animation, sgf diagrams}/restart/{true, false, auto, from} \cs_new_protected:Npn \__pgfgo_sgf_numbering_keys:nnn #1#2#3 { \clist_new:c {l__pgfgo_ #2 _step_clist} \tl_new:c {l__pgfgo_ #2 _restart_tl} \int_new:c {l__pgfgo_ #2 _restart_from_int} \keys_define:nn {#1} { step .clist_set:c = {l__pgfgo_ #2 _step_clist}, step .initial:n = {#3}, restart .code:n = {\keys_set:nn {#1 / restart} {##1}}, restart .default:n = {true}, } \keys_define:nn {#1 / restart} { true .code:n = {\tl_set:cn {l__pgfgo_ #2 _restart_tl} {true}}, false .code:n = {\tl_set:cn {l__pgfgo_ #2 _restart_tl} {false}}, auto .code:n = {\tl_set:cn {l__pgfgo_ #2 _restart_tl} {auto}}, from .code:n = { \tl_set:cn {l__pgfgo_ #2 _restart_tl} {true} \int_set:cn {l__pgfgo_ #2 _restart_from_int} {##1} }, } \tl_set:cn {l__pgfgo_ #2 _restart_tl} {auto} \int_set:cn {l__pgfgo_ #2 _restart_from_int} {1} } \__pgfgo_sgf_numbering_keys:nnn {pgfgo / sgf} {sgf} {100} \keys_define:nn {pgfgo / sgf} { from .int_set:N = \l__pgfgo_sgf_from_int, from .initial:n = {1}, %last (O UN NUMERO NEGATIVO): HASTA LA ULTIMA JUGADA. to .code:n = {\__pgfgo_sgf_set_to:Nnn \l__pgfgo_sgf_to_int {\c_max_int} {#1}}, to .initial:n = {last}, %OPCIONES DE UNA MARCA PARA LA ULTIMA JUGADA QUE SE MUESTRA. false: SIN MARCA. last~mark .code:n = { \str_if_eq:nnTF {#1} {false} {\tl_clear:N \l__pgfgo_sgf_last_mark_tl} {\tl_set:Nn \l__pgfgo_sgf_last_mark_tl {#1}} }, last~mark .initial:n = {false}, %2.1: EN LA PRIMERA BIFURCACION, LA SEGUNDA VARIANTE; EN LA SEGUNDA, LA PRIMERA. variation .tl_set:N = \l__pgfgo_sgf_variation_tl, marks .bool_set:N = \l__pgfgo_sgf_marks_bool, marks .default:n = {true}, marks .initial:n = {true}, numbers .choices:nn = {true, false, auto} {\tl_set_eq:NN \l__pgfgo_sgf_numbers_tl \l_keys_choice_tl}, numbers .default:n = {true}, numbers .initial:n = {auto}, %LA PARTIDA DEL ARCHIVO (1 ES LA PRIMERA). game .code:n = {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {#1}}, %LAS VARIANTES DE LA ULTIMA JUGADA, COMO LETRAS: none, children, siblings O auto (LO QUE DICE ST). variations .choices:nn = {none, children, siblings, auto} {\tl_set_eq:NN \l__pgfgo_sgf_variations_tl \l_keys_choice_tl}, variations .default:n = {auto}, variations .initial:n = {none}, } %\pgfgoset{sgf = {...}} FIJA LAS OPCIONES DE TODOS LOS \sgf (Y LA PARTIDA DE LOS DEMAS COMANDOS). %sgf charset: LA CODIFICACION DE LOS ARCHIVOS QUE NO SON UTF-8 (auto: LA DE CA). sgf syntax: LA SINTAXIS DE %LOS ARCHIVOS (auto: LA QUE PARECE; VER pgf-go-kernel.sty). \keys_define:nn {pgfgo} { sgf .code:n = {\keys_set:nn {pgfgo / sgf} {#1}}, sgf~charset .tl_set:N = \l_pgfgo_kernel_sgf_charset_tl, sgf~syntax .tl_set:N = \l_pgfgo_kernel_sgf_syntax_tl, } \msg_new:nnn {pgfgo} {sgf-size} {The~game~in~'#1'~is~for~a~#2~board,~but~the~goban~is~#3.} %AE: SOLO SE PUEDE QUITAR UNA PIEDRA CON goban/captures (LAS PIEDRAS SE DIBUJAN AL FINAL). SIN CAPTURAS, %\sgf AVISA UNA VEZ. \msg_new:nnn {pgfgo} {sgf-remove} {'#1'~removes~stones~(AE).~That~needs~goban/captures,~so~they~are~not~removed.} %PIEDRAS INICIALES. #1: black O white. #2: LISTA DE {x}{y}. \cs_new_protected:Npn \__pgfgo_sgf_stones:nn #1#2 { \tl_if_blank:nF {#2} { \bool_if:NT \l__pgfgo_sgf_cache_bool {\clist_map_inline:nn {#2} {\__pgfgo_sgf_cache_outside:nn ##1}} \pgfgo_remember:Nnn \l_pgfgo_goban_remember_stone_bool {stone} {\exp_not:N \pgfgo_stones_parsed:nn {#1} {\exp_not:n {#2}}} \pgfgo_stones_parsed:nn {#1} {#2} } } \cs_generate_variant:Nn \__pgfgo_sgf_stones:nn {nV} %LAS PIEDRAS INICIALES DE #1 (black O white), DE LA SECUENCIA #2 DEL KERNEL. \cs_new_protected:Npn \__pgfgo_sgf_setup_stones:nN #1#2 { \clist_set_from_seq:NN \l_tmpa_clist #2 \__pgfgo_sgf_stones:nV {#1} \l_tmpa_clist } %UN EVENTO DE LA PARTIDA: UNA JUGADA ({black | white}{x}{y}), UN CAMBIO DE UN NODO POSTERIOR A LA %PRIMERA JUGADA ({add-black | add-white | remove}{x}{y}), UN NUMERO DE JUGADA ({number}{n}{}, POR MN) O %UN TURNO ({player}{black | white}{}, POR PL). LAS JUGADAS, QUE SON LA MAYORIA, SE PRUEBAN PRIMERO. \cs_new_protected:Npn \__pgfgo_sgf_event:nnn #1#2#3 { \str_case:nnF {#1} { {black} {\__pgfgo_sgf_move:nnn {black} {#2} {#3}} {white} {\__pgfgo_sgf_move:nnn {white} {#2} {#3}} {add-black} {\__pgfgo_sgf_stones:nn {black} {{#2}{#3}}} {add-white} {\__pgfgo_sgf_stones:nn {white} {{#2}{#3}}} {remove} {\__pgfgo_sgf_remove:nn {#2} {#3}} {number} {\int_set:Nn \l__pgfgo_sgf_number_int {#2 - 1}} {player} {\pgfgo_kernel_move_set_player:n {#2}} }{ \__pgfgo_sgf_move:nnn {#1} {#2} {#3} } } \cs_new_protected:Npn \__pgfgo_sgf_remove:nn #1#2 { \bool_if:nTF {\l_pgfgo_goban_captures_bool && ! \l_pgfgo_captures_collect_bool} { \pgfgo_remember:Nnn \l_pgfgo_goban_remember_stone_bool {stone} {\exp_not:N \pgfgo_captures_remove:nn {#1} {#2}} \pgfgo_captures_remove:nn {#1} {#2} }{ \bool_if:NF \l__pgfgo_sgf_remove_warned_bool { \msg_warning:nnV {pgfgo} {sgf-remove} \l__pgfgo_sgf_file_tl \bool_set_true:N \l__pgfgo_sgf_remove_warned_bool } } } %EL NUMERO QUE SE MUESTRA DE CADA JUGADA DIBUJADA (CON restart NO ES EL DE LA PARTIDA), PARA LOS COMENTARIOS: %\__pgfgo_sgf_shown_: (UN prop SERIA CUADRATICO EN LAS PARTIDAS LARGAS) Y LA MAYOR JUGADA GUARDADA. \int_new:N \g__pgfgo_sgf_shown_max_int \cs_new_protected:Npn \__pgfgo_sgf_shown_clear: { \int_step_inline:nn {\g__pgfgo_sgf_shown_max_int} {\cs_undefine:c {__pgfgo_sgf_shown_ ##1 :}} \int_gzero:N \g__pgfgo_sgf_shown_max_int } %UNA JUGADA DE #1 (black O white) EN (#2,#3). x E y VACIOS: PASE. \cs_new_protected:Npn \__pgfgo_sgf_move:nnn #1#2#3 { \bool_if:NT \l__pgfgo_sgf_cache_bool { \bool_lazy_and:nnT {\int_compare_p:nNn {\l__pgfgo_sgf_count_int + 1} = {\l__pgfgo_sgf_from_int}} {! \int_compare_p:nNn {\l__pgfgo_sgf_from_int} > {\l__pgfgo_sgf_to_int}} {\__pgfgo_sgf_save:nn {a} {\l__pgfgo_sgf_index_int}} } \int_incr:N \l__pgfgo_sgf_count_int \int_compare:nNnTF {\l__pgfgo_sgf_count_int} > {\l__pgfgo_sgf_to_int} { \int_decr:N \l__pgfgo_sgf_count_int \int_set_eq:NN \l__pgfgo_sgf_resume_int \l__pgfgo_sgf_index_int \seq_map_break: }{ \int_incr:N \l__pgfgo_sgf_number_int \bool_lazy_and:nnT {! \tl_if_empty_p:N \l__pgfgo_sgf_first_tl} {\int_compare_p:nNn {\l__pgfgo_sgf_count_int} = {\l__pgfgo_sgf_from_int}} {\int_set:Nn \l__pgfgo_sgf_shift_int {\l__pgfgo_sgf_first_tl - \l__pgfgo_sgf_number_int}} \int_compare:nNnT {\l__pgfgo_sgf_restart_int} = {1} {\__pgfgo_sgf_block:n {\l__pgfgo_sgf_number_int}} \int_set:Nn \l__pgfgo_sgf_shown_int { \int_case:nnF {\l__pgfgo_sgf_restart_int} { {1} { \int_compare:nNnTF {\l__pgfgo_sgf_block_int} = {1} {\l__pgfgo_sgf_number_int} {\l__pgfgo_sgf_restart_from_int + \l__pgfgo_sgf_number_int - \l__pgfgo_sgf_block_int} } {2} {\int_mod:nn {\l__pgfgo_sgf_number_int - 1} {100} + 1} } {\l__pgfgo_sgf_number_int + \l__pgfgo_sgf_shift_int} } \pgfgo_kernel_move_set_number:n {\l__pgfgo_sgf_shown_int} \cs_gset:cpe {__pgfgo_sgf_shown_ \int_use:N \l__pgfgo_sgf_count_int :} {\int_use:N \l__pgfgo_sgf_shown_int} \int_gset:Nn \g__pgfgo_sgf_shown_max_int {\int_max:nn {\g__pgfgo_sgf_shown_max_int} {\l__pgfgo_sgf_count_int}} \pgfgo_kernel_move_set_player:n {#1} \tl_if_blank:nTF {#2} { %UN PASE CUENTA, PERO NO SE DIBUJA. CON goban/notes, SI SE NUMERARIA, SE ANOTA ("N: pass"), SALVO LOS %QUE TERMINAN LA LINEA (#3 = end). \bool_lazy_all:nT { {\l_pgfgo_goban_notes_bool} {\l__pgfgo_sgf_numbers_bool} {\tl_if_empty_p:n {#3}} {! \int_compare_p:nNn {\l__pgfgo_sgf_count_int} < {\l__pgfgo_sgf_from_int}} } {\pgfgo_notes_pass:} \pgfgo_kernel_move_set_number:n {\l__pgfgo_sgf_shown_int + 1} \pgfgo_kernel_move_set_player:n {\str_if_eq:nnTF {#1} {black} {white} {black}} }{ \__pgfgo_sgf_stone:nnn {#1} {#2} {#3} } } } %LA PIEDRA DE UNA JUGADA. SIN NUMERO ANTES DE from, Y TAMPOCO SI UNA MARCA DEL ARCHIVO CAE EN ESE PUNTO %(LA MARCA LO REEMPLAZA). \cs_new_protected:Npn \__pgfgo_sgf_stone:nnn #1#2#3 { \bool_set:Nn \l__pgfgo_sgf_numbered_bool {! \int_compare_p:nNn {\l__pgfgo_sgf_count_int} < {\l__pgfgo_sgf_from_int}} \bool_set:Nn \l__pgfgo_captures_keep_bool {\l__pgfgo_sgf_keep_numbered_bool && \l__pgfgo_sgf_numbered_bool} \__pgfgo_captures_key:nn {#2} {#3} \bool_if:NT \l__pgfgo_sgf_cache_bool {\__pgfgo_sgf_cache_outside:nn {#2} {#3}} \bool_if:nT {\l__pgfgo_sgf_numbers_bool && \l__pgfgo_sgf_numbered_bool} {\prop_put:NVn \l__pgfgo_sgf_numbered_prop \l__pgfgo_captures_key_tl {}} \bool_set:Nn \l__pgfgo_sgf_numbered_bool { \l__pgfgo_sgf_numbers_bool && \l__pgfgo_sgf_numbered_bool && ! \prop_if_in_p:NV \g__pgfgo_sgf_marked_prop \l__pgfgo_captures_key_tl } \pgfgo_remember:Nnn \l_pgfgo_goban_remember_move_bool {stone} { \bool_if:NF \l_pgfgo_goban_remember_move_label_bool {\exp_not:N \pgfgo_remember_numbers:n} { \__pgfgo_sgf_move_code:nnnn {\bool_if:NTF \l__pgfgo_sgf_numbered_bool {\exp_not:N \BooleanTrue} {\exp_not:N \BooleanFalse}} {#1} {#2} {#3} } } \bool_if:NTF \l__pgfgo_sgf_numbered_bool {\pgfgo_move:nnnn {\BooleanTrue} {} {#2} {#3}} {\pgfgo_move:nnnn {\BooleanFalse} {} {#2} {#3}} } %EL CODIGO QUE VUELVE A DIBUJAR LA JUGADA DE #2 EN (#3,#4) (#1: NUMERADA). PARA UNA EXPANSION e. \cs_new:Npn \__pgfgo_sgf_move_code:nnnn #1#2#3#4 { \exp_not:N \pgfgo_move_parsed:nnn {#1} {from = \int_use:N \l__pgfgo_sgf_shown_int, #2} {{#3}{#4}} } %MARCAS DEL ARCHIVO (TR, SQ, CR, MA, LB; TB Y TW SON TERRITORIO): #1 FORMA, (#2,#3) PUNTO, #4 COLOR DE LA %PIEDRA (black, white O neutral, PARA QUE LA MARCA SE VEA), #5 TEXTO DE LB. \cs_new_protected:Npn \__pgfgo_sgf_mark:nnnnn #1#2#3#4#5 { \str_case:nnF {#1} { {black-territory} {\__pgfgo_sgf_territory:nnn {black} {#2} {#3}} {white-territory} {\__pgfgo_sgf_territory:nnn {white} {#2} {#3}} {selected} {\__pgfgo_sgf_mark_draw:nnnnn {filled~square} {#2} {#3} {#4} {#5}} }{ \__pgfgo_sgf_mark_draw:nnnnn {#1} {#2} {#3} {#4} {#5} } } %TB Y TW: TERRITORIO DE #1 EN (#2,#3), COMO EL DE \territory (CUENTA PARA \pgfgoscore). UNA PIEDRA DEL %RIVAL EN ESE PUNTO ESTA MUERTA. \cs_new_protected:Npn \__pgfgo_sgf_territory:nnn #1#2#3 { \__pgfgo_captures_key:nn {#2} {#3} \prop_get:NVNT \g_pgfgo_points_prop \l__pgfgo_captures_key_tl \l__pgfgo_sgf_mark_tl { \str_if_eq:eeT {\l__pgfgo_sgf_mark_tl} {\str_if_eq:nnTF {#1} {black} {white} {black}} {\prop_gput:NVe \g_pgfgo_points_prop \l__pgfgo_captures_key_tl {dead- \l__pgfgo_sgf_mark_tl}} } \pgfgo_remember:Nnn \l_pgfgo_goban_remember_territory_bool {territory} {\exp_not:N \pgfgo_territory_parsed:nnnn {#1} {\l__pgfgo_territory_draw_tl} {} {{#2}{#3}}} \pgfgo_territory_parsed:nVnn {#1} \l__pgfgo_territory_draw_tl {} {{#2}{#3}} } \cs_generate_variant:Nn \prop_if_in:NnF {NV} %VERDADERO SI EL ARCHIVO MARCA (#1,#2), CON UNA FORMA O UNA ETIQUETA. DEJA LISTO \l__pgfgo_captures_key_tl. \prg_new_protected_conditional:Npnn \__pgfgo_sgf_if_file_marked:nn #1#2 {F} { \__pgfgo_captures_key:nn {#1} {#2} \bool_lazy_or:nnTF {\prop_if_in_p:NV \g__pgfgo_sgf_marked_prop \l__pgfgo_captures_key_tl} {\prop_if_in_p:NV \g__pgfgo_sgf_labeled_prop \l__pgfgo_captures_key_tl} {\prg_return_true:} {\prg_return_false:} } %UNA ETIQUETA NO TAPA EL NUMERO DE UNA JUGADA. \cs_new_protected:Npn \__pgfgo_sgf_mark_draw:nnnnn #1#2#3#4#5 { \str_if_eq:nnTF {#1} {label} {\__pgfgo_sgf_if_numbered_shown:nnF {#2} {#3} {\__pgfgo_sgf_mark_show:nnnnn {#1} {#2} {#3} {#4} {#5}}} {\__pgfgo_sgf_mark_show:nnnnn {#1} {#2} {#3} {#4} {#5}} } \cs_new_protected:Npn \__pgfgo_sgf_mark_show:nnnnn #1#2#3#4#5 { \tl_set:Ne \l__pgfgo_sgf_mark_tl { #4, \str_if_eq:nnTF {#1} {label} {custom = {\pgfgo_kernel_sgf_label:n {#5}}} {#1} } \__pgfgo_sgf_mark_put:Vn \l__pgfgo_sgf_mark_tl {{#2}{#3}} } %DIBUJA (Y RECUERDA) LA MARCA DE OPCIONES #1 EN EL PUNTO #2 ({x}{y}). \cs_new_protected:Npn \__pgfgo_sgf_mark_put:nn #1#2 { \pgfgo_remember:Nnn \l_pgfgo_goban_remember_mark_bool {mark} {\exp_not:N \pgfgo_marks_parsed:nn {\exp_not:n {#1}} {#2}} \pgfgo_marks_parsed:nn {#1} {#2} } \cs_generate_variant:Nn \__pgfgo_sgf_mark_put:nn {Vn} %LA LETRA #4 DE UNA VARIANTE EN (#1,#2), EN EL COLOR #3 DE LA PIEDRA QUE HAY AHI. \cs_new_protected:Npn \__pgfgo_sgf_variation:nnnn #1#2#3#4 { \__pgfgo_sgf_mark_put:nn {#3, custom = {#4}} {{#1}{#2}} } %FLECHAS Y LINEAS DEL ARCHIVO (AR, LN): #1 arrow O line, DE (#2,#3) A (#4,#5). \cs_new_protected:Npn \__pgfgo_sgf_line:nnnnn #1#2#3#4#5 { \pgfgo_remember:Nnn \l_pgfgo_goban_remember_mark_bool {#1} {\exp_not:N \pgfgo_line_parsed:nnnnnn {#1} {} {#2} {#3} {#4} {#5}} \pgfgo_line_parsed:nnnnnn {#1} {} {#2} {#3} {#4} {#5} } %LOS PUNTOS QUE MARCA EL ULTIMO NODO QUE SE MUESTRA. LOS PUNTOS ATENUADOS Y LAS ETIQUETAS NO REEMPLAZAN EL %NUMERO DE LA JUGADA. \cs_new_protected:Npn \__pgfgo_sgf_marked_point:nnnnn #1#2#3#4#5 { \__pgfgo_captures_key:nn {#2} {#3} \str_case:nnF {#1} { {dim} {} {label} {\prop_gput:NVn \g__pgfgo_sgf_labeled_prop \l__pgfgo_captures_key_tl {}} }{ \prop_gput:NVn \g__pgfgo_sgf_marked_prop \l__pgfgo_captures_key_tl {} } } %VERDADERO SI EN (#1,#2) SE VE UNA JUGADA NUMERADA (CON CAPTURAS, SI NO FUE CAPTURADA O SI SE CONSERVA). \prg_new_protected_conditional:Npnn \__pgfgo_sgf_if_numbered_shown:nn #1#2 {F} { \__pgfgo_captures_key:nn {#1} {#2} \bool_lazy_and:nnTF {\prop_if_in_p:NV \l__pgfgo_sgf_numbered_prop \l__pgfgo_captures_key_tl} { ! \l_pgfgo_goban_captures_bool || \prop_if_in_p:NV \g__pgfgo_captures_pending_prop \l__pgfgo_captures_key_tl } {\prg_return_true:} {\prg_return_false:} } %restart Y numbers SEGUN LA OPCION Y, CON auto, SEGUN PM. \cs_new_protected:Npn \__pgfgo_sgf_numbering: { \int_zero:N \l__pgfgo_sgf_restart_int \str_if_eq:VnT \l__pgfgo_sgf_restart_tl {true} {\int_set:Nn \l__pgfgo_sgf_restart_int {1}} \str_if_eq:VnT \l__pgfgo_sgf_restart_tl {auto} { \int_compare:nNnT {\l_pgfgo_kernel_sgf_print_int} = {2} {\int_set:Nn \l__pgfgo_sgf_restart_int {2}} } \clist_if_empty:NT \l__pgfgo_sgf_step_clist {\clist_set:Nn \l__pgfgo_sgf_step_clist {100}} \bool_set:Nn \l__pgfgo_sgf_numbers_bool { \str_if_eq_p:Vn \l__pgfgo_sgf_numbers_tl {true} || (\str_if_eq_p:Vn \l__pgfgo_sgf_numbers_tl {auto} && ! \int_compare_p:nNn {\l_pgfgo_kernel_sgf_print_int} = {0}) } } %EN \l__pgfgo_sgf_block_int, LA PRIMERA JUGADA DEL TRAMO DE step EN QUE CAE EL NUMERO #1. LOS TRAMOS QUE %REPITEN EL ULTIMO TAMANO DE LA LISTA SE SALTAN DE UNA VEZ. \int_new:N \l__pgfgo_sgf_block_int \int_new:N \l__pgfgo_sgf_block_size_int \int_new:N \l__pgfgo_sgf_block_index_int \cs_new_protected:Npn \__pgfgo_sgf_block:n #1 { \int_set:Nn \l__pgfgo_sgf_block_int {1} \int_set:Nn \l__pgfgo_sgf_block_index_int {1} \__pgfgo_sgf_block_loop:n {#1} } \cs_new_protected:Npn \__pgfgo_sgf_block_loop:n #1 { \int_set:Nn \l__pgfgo_sgf_block_size_int { \int_max:nn {1} { \clist_item:Nn \l__pgfgo_sgf_step_clist {\int_min:nn {\l__pgfgo_sgf_block_index_int} {\clist_count:N \l__pgfgo_sgf_step_clist}} } } \int_compare:nNnT {#1} > {\l__pgfgo_sgf_block_int + \l__pgfgo_sgf_block_size_int - 1} { \int_compare:nNnTF {\l__pgfgo_sgf_block_index_int} < {\clist_count:N \l__pgfgo_sgf_step_clist} { \int_add:Nn \l__pgfgo_sgf_block_int {\l__pgfgo_sgf_block_size_int} \int_incr:N \l__pgfgo_sgf_block_index_int \__pgfgo_sgf_block_loop:n {#1} } { \int_add:Nn \l__pgfgo_sgf_block_int { \int_div_truncate:nn {#1 - \l__pgfgo_sgf_block_int} {\l__pgfgo_sgf_block_size_int} * \l__pgfgo_sgf_block_size_int } } } } %AVISA SI LA PARTIDA DEL ARCHIVO #1 NO ES DEL TAMANO DEL goban. \cs_new_protected:Npn \__pgfgo_sgf_check_size:n #1 { \bool_lazy_and:nnF {\int_compare_p:nNn {\l_pgfgo_kernel_sgf_size_x_int} = {\l_pgfgo_goban_size_x_int}} {\int_compare_p:nNn {\l_pgfgo_kernel_sgf_size_y_int} = {\l_pgfgo_goban_size_y_int}} { \msg_warning:nnnee {pgfgo} {sgf-size} {#1} {\int_use:N \l_pgfgo_kernel_sgf_size_x_int x \int_use:N \l_pgfgo_kernel_sgf_size_y_int} {\int_use:N \l_pgfgo_goban_size_x_int x \int_use:N \l_pgfgo_goban_size_y_int} } } %LAS MARCAS Y LAS LETRAS DE LAS VARIANTES DE LA ULTIMA JUGADA QUE SE MUESTRA. SE AVERIGUAN ANTES DE JUGAR, %PORQUE REEMPLAZAN LOS NUMEROS, Y SE DIBUJAN DESPUES. \cs_new_protected:Npn \__pgfgo_sgf_marked: { \prop_gclear:N \g__pgfgo_sgf_marked_prop \prop_gclear:N \g__pgfgo_sgf_labeled_prop \seq_clear:N \l__pgfgo_sgf_marks_seq \bool_if:NT \l__pgfgo_sgf_marks_bool { \pgfgo_kernel_sgf_marks:n {\l__pgfgo_sgf_last_int} \seq_set_eq:NN \l__pgfgo_sgf_marks_seq \l_pgfgo_kernel_sgf_marks_seq \seq_map_inline:Nn \l__pgfgo_sgf_marks_seq {\__pgfgo_sgf_marked_point:nnnnn ##1} } \seq_clear:N \l__pgfgo_sgf_variations_seq \str_if_eq:VnF \l__pgfgo_sgf_variations_tl {none} { \exp_args:NnV \pgfgo_kernel_sgf_variations:nn {\l__pgfgo_sgf_last_int} \l__pgfgo_sgf_variations_tl \seq_set_eq:NN \l__pgfgo_sgf_variations_seq \l_pgfgo_kernel_sgf_variations_seq \seq_map_inline:Nn \l__pgfgo_sgf_variations_seq {\__pgfgo_sgf_marked_point:nnnnn {variation} ##1} } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %CON \l__pgfgo_sgf_cache_bool (\sgfanimation Y \sgfdiagrams, QUE DIBUJAN MUCHOS TABLEROS DE LA MISMA %PARTIDA) UN \sgf NO VUELVE A JUGAR LA PARTIDA DESDE EL PRINCIPIO: SIGUE DESDE LA POSICION QUE GUARDO %UN \sgf ANTERIOR. HAY DOS COPIAS: a, ANTES DE LA PRIMERA JUGADA NUMERADA (from), Y b, DESPUES DE LA %ULTIMA (to). CADA UNA TIENE LO QUE DEJARON LAS JUGADAS: EL TABLERO DEL KERNEL, LO QUE SE VA A DIBUJAR %(LAS PIEDRAS, LAS ATENUADAS Y LAS MARCAS), LOS PUNTOS DE \pgfgoscore, LAS NOTAS "N at M" Y EL NUMERO. % %UNA COPIA DE c JUGADAS SIRVE SI ES DEL MISMO ARCHIVO, CON LAS MISMAS OPCIONES Y EL MISMO TABLERO (EL %CONTEXTO), SI to NO ES MENOR QUE c, SI LAS JUGADAS 1 A c SON LAS MISMAS NUMERADAS (from IGUAL, O LOS DOS %MAYORES QUE c), Y SI NINGUNA DE ESAS JUGADAS NUMERADAS CAE EN UN PUNTO QUE MARCA EL ULTIMO NODO (LA %MARCA LE QUITA EL NUMERO). NO SE GUARDA NADA SI HUBO UN AVISO (PARA QUE CADA TABLERO AVISE IGUAL). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \bool_new:N \l__pgfgo_sgf_cache_bool \tl_new:N \l__pgfgo_sgf_context_tl %EL EVENTO QUE SE JUEGA, Y EL PRIMERO QUE NO SE JUGO (DONDE SIGUE UNA COPIA). \int_new:N \l__pgfgo_sgf_index_int \int_new:N \l__pgfgo_sgf_resume_int \int_new:N \l__pgfgo_sgf_start_int %SI UN PUNTO QUEDO FUERA DEL TABLERO. \bool_new:N \l__pgfgo_sgf_outside_bool \tl_new:N \l__pgfgo_sgf_slot_tl \clist_map_inline:nn {a, b} { \tl_new:c {g__pgfgo_sgf_#1_context_tl} \int_new:c {g__pgfgo_sgf_#1_count_int} \int_new:c {g__pgfgo_sgf_#1_index_int} \int_new:c {g__pgfgo_sgf_#1_from_int} \int_new:c {g__pgfgo_sgf_#1_number_int} \int_new:c {g__pgfgo_sgf_#1_shift_int} \seq_new:c {g__pgfgo_sgf_#1_captured_seq} \seq_new:c {g__pgfgo_sgf_#1_notes_seq} \clist_map_inline:nn {numbered, pending, faded, marks, points, notes_number, notes_code} {\prop_new:c {g__pgfgo_sgf_#1_##1_prop}} } %BORRA LAS COPIAS (AL EMPEZAR CADA \sgfanimation O \sgfdiagrams). \cs_new_protected:Npn \__pgfgo_sgf_cache_begin: { \bool_set_true:N \l__pgfgo_sgf_cache_bool \tl_gclear:c {g__pgfgo_sgf_a_context_tl} \tl_gclear:c {g__pgfgo_sgf_b_context_tl} } %UN PUNTO FUERA DEL TABLERO DA UN AVISO. \cs_new_protected:Npn \__pgfgo_sgf_cache_outside:nn #1#2 { \bool_lazy_and:nnF {\int_compare_p:n {1 <= #1 <= \l_pgfgo_goban_size_x_int}} {\int_compare_p:n {1 <= #2 <= \l_pgfgo_goban_size_y_int}} {\bool_set_true:N \l__pgfgo_sgf_outside_bool} } %VERDADERO SI ALGUNA JUGADA NUMERADA DE LA PROP #1 CAE EN UN PUNTO MARCADO. \prg_new_conditional:Npnn \__pgfgo_sgf_if_marked_conflict:N #1 {TF} { \bool_set_false:N \l_tmpa_bool \prop_map_inline:Nn \g__pgfgo_sgf_marked_prop { \prop_if_in:NnT #1 {##1} {\bool_set_true:N \l_tmpa_bool \prop_map_break:} } \bool_if:NTF \l_tmpa_bool {\prg_return_true:} {\prg_return_false:} } \prg_generate_conditional_variant:Nnn \__pgfgo_sgf_if_marked_conflict:N {c} {TF} %EL CONTEXTO DEL \sgf QUE EMPIEZA (DESPUES DE LEER LA PARTIDA Y DE \__pgfgo_sgf_numbering:). \cs_new_protected:Npn \__pgfgo_sgf_context: { \tl_set:Ne \l__pgfgo_sgf_context_tl { {\exp_not:V \l__pgfgo_sgf_file_tl} {\exp_not:V \l__pgfgo_sgf_variation_tl} {\exp_not:V \l_pgfgo_kernel_sgf_charset_tl} {\exp_not:V \l_pgfgo_kernel_sgf_syntax_tl} { \int_use:N \l_pgfgo_kernel_sgf_game_int , \int_use:N \l_pgfgo_goban_size_x_int , \int_use:N \l_pgfgo_goban_size_y_int , \int_use:N \l_pgfgo_goban_from_x_int , \int_use:N \l_pgfgo_goban_to_x_int , \int_use:N \l_pgfgo_goban_from_y_int , \int_use:N \l_pgfgo_goban_to_y_int , \int_use:N \l__pgfgo_sgf_restart_int , \int_use:N \l__pgfgo_sgf_restart_from_int , \clist_use:Nn \l__pgfgo_sgf_step_clist {;} , \tl_use:N \l__pgfgo_sgf_first_tl } \bool_to_str:N \l_pgfgo_goban_captures_bool \bool_to_str:N \l_pgfgo_captures_collect_bool \bool_to_str:N \l_pgfgo_goban_captures_fade_bool \bool_to_str:N \l_pgfgo_goban_notes_bool \bool_to_str:N \l__pgfgo_sgf_numbers_bool \bool_to_str:N \l__pgfgo_sgf_keep_numbered_bool } } %GUARDA LA COPIA #1 (a O b), QUE SIGUE EN EL EVENTO #2. \cs_new_protected:Npn \__pgfgo_sgf_save:nn #1#2 { \bool_if:nF { \g__pgfgo_captures_warned_bool || \l__pgfgo_sgf_remove_warned_bool || \l__pgfgo_sgf_outside_bool }{ \__pgfgo_sgf_if_marked_conflict:NTF \l__pgfgo_sgf_numbered_prop { \tl_gclear:c {g__pgfgo_sgf_#1_context_tl} }{ \tl_gset_eq:cN {g__pgfgo_sgf_#1_context_tl} \l__pgfgo_sgf_context_tl \int_gset_eq:cN {g__pgfgo_sgf_#1_count_int} \l__pgfgo_sgf_count_int \int_gset:cn {g__pgfgo_sgf_#1_index_int} {#2} \int_gset:cn {g__pgfgo_sgf_#1_from_int} {\int_min:nn {\l__pgfgo_sgf_from_int} {\l__pgfgo_sgf_count_int + 1}} \int_gset_eq:cN {g__pgfgo_sgf_#1_number_int} \l__pgfgo_sgf_number_int \int_gset_eq:cN {g__pgfgo_sgf_#1_shift_int} \l__pgfgo_sgf_shift_int \seq_gset_eq:cN {g__pgfgo_sgf_#1_captured_seq} \l_pgfgo_kernel_captured_seq \seq_gset_eq:cN {g__pgfgo_sgf_#1_notes_seq} \g_pgfgo_move_notes_seq \prop_gset_eq:cN {g__pgfgo_sgf_#1_numbered_prop} \l__pgfgo_sgf_numbered_prop \prop_gset_eq:cN {g__pgfgo_sgf_#1_pending_prop} \g__pgfgo_captures_pending_prop \prop_gset_eq:cN {g__pgfgo_sgf_#1_faded_prop} \g__pgfgo_captures_faded_prop \prop_gset_eq:cN {g__pgfgo_sgf_#1_marks_prop} \g__pgfgo_captures_marks_prop \prop_gset_eq:cN {g__pgfgo_sgf_#1_points_prop} \g_pgfgo_points_prop \prop_gset_eq:cN {g__pgfgo_sgf_#1_notes_number_prop} \g__pgfgo_notes_number_prop \prop_gset_eq:cN {g__pgfgo_sgf_#1_notes_code_prop} \g__pgfgo_notes_code_prop \pgfgo_kernel_board_save:n {sgf-#1} } } } %DEJA EN \l__pgfgo_sgf_slot_tl LA COPIA QUE SIRVE (LA DE MAS JUGADAS), O NADA. \cs_new_protected:Npn \__pgfgo_sgf_choose: { \tl_clear:N \l__pgfgo_sgf_slot_tl \clist_map_inline:nn {a, b} { \bool_lazy_all:nT { {\tl_if_eq_p:Nc \l__pgfgo_sgf_context_tl {g__pgfgo_sgf_##1_context_tl}} {! \int_compare_p:nNn {\int_use:c {g__pgfgo_sgf_##1_count_int}} > {\l__pgfgo_sgf_to_int}} { \int_compare_p:nNn {\int_use:c {g__pgfgo_sgf_##1_from_int}} = {\int_min:nn {\l__pgfgo_sgf_from_int} {\int_use:c {g__pgfgo_sgf_##1_count_int} + 1}} } { \bool_lazy_or_p:nn {\tl_if_empty_p:N \l__pgfgo_sgf_slot_tl} { \int_compare_p:nNn {\int_use:c {g__pgfgo_sgf_##1_count_int}} > {\int_use:c {g__pgfgo_sgf_ \l__pgfgo_sgf_slot_tl _count_int}} } } }{ \__pgfgo_sgf_if_marked_conflict:cTF {g__pgfgo_sgf_##1_numbered_prop} {} {\tl_set:Nn \l__pgfgo_sgf_slot_tl {##1}} } } } %VUELVE A LA COPIA #1. \cs_new_protected:Npn \__pgfgo_sgf_restore:n #1 { \int_set_eq:Nc \l__pgfgo_sgf_count_int {g__pgfgo_sgf_#1_count_int} \int_set_eq:Nc \l__pgfgo_sgf_number_int {g__pgfgo_sgf_#1_number_int} \int_set_eq:Nc \l__pgfgo_sgf_shift_int {g__pgfgo_sgf_#1_shift_int} \int_set_eq:Nc \l__pgfgo_sgf_start_int {g__pgfgo_sgf_#1_index_int} \seq_set_eq:Nc \l_pgfgo_kernel_captured_seq {g__pgfgo_sgf_#1_captured_seq} \seq_gset_eq:Nc \g_pgfgo_move_notes_seq {g__pgfgo_sgf_#1_notes_seq} \prop_set_eq:Nc \l__pgfgo_sgf_numbered_prop {g__pgfgo_sgf_#1_numbered_prop} \prop_gset_eq:Nc \g__pgfgo_captures_pending_prop {g__pgfgo_sgf_#1_pending_prop} \prop_gset_eq:Nc \g__pgfgo_captures_faded_prop {g__pgfgo_sgf_#1_faded_prop} \prop_gset_eq:Nc \g__pgfgo_captures_marks_prop {g__pgfgo_sgf_#1_marks_prop} \prop_gset_eq:Nc \g_pgfgo_points_prop {g__pgfgo_sgf_#1_points_prop} \prop_gset_eq:Nc \g__pgfgo_notes_number_prop {g__pgfgo_sgf_#1_notes_number_prop} \prop_gset_eq:Nc \g__pgfgo_notes_code_prop {g__pgfgo_sgf_#1_notes_code_prop} \pgfgo_kernel_board_restore:n {sgf-#1} } \cs_generate_variant:Nn \__pgfgo_sgf_restore:n {V} %LA ULTIMA JUGADA QUE SE MUESTRA, Y SUS MARCAS. \cs_new_protected:Npn \__pgfgo_sgf_last: { \__pgfgo_sgf_count_moves:Nn \l__pgfgo_sgf_last_int {\l__pgfgo_sgf_to_int} \int_set:Nn \l__pgfgo_sgf_last_int {\int_min:nn {\l__pgfgo_sgf_last_int} {\l__pgfgo_sgf_to_int}} \__pgfgo_sgf_marked: } %LAS PIEDRAS INICIALES Y LAS JUGADAS, DESDE EL PRINCIPIO O (CON \l__pgfgo_sgf_cache_bool) DESDE UNA COPIA. %LAS MARCAS SE AVERIGUAN ANTES, PORQUE DECIDEN SI UNA COPIA SIRVE (NO DAN AVISOS). \cs_new_protected:Npn \__pgfgo_sgf_play: { \int_zero:N \l__pgfgo_sgf_count_int \int_zero:N \l__pgfgo_sgf_number_int \int_zero:N \l__pgfgo_sgf_shift_int \tl_clear:N \l__pgfgo_sgf_slot_tl %SIN goban/captures LAS PIEDRAS SE DIBUJAN AL JUGARLAS: NO HAY NADA QUE GUARDAR. UN goban CON name TAMPOCO %USA LA COPIA: SU MEMORIA TIENE QUE TENER TODAS LAS JUGADAS, Y LA COPIA NO LAS TRAE. \bool_lazy_all:nTF {{\l__pgfgo_sgf_cache_bool} {\l_pgfgo_goban_captures_bool} {\tl_if_empty_p:N \l_pgfgo_goban_name_tl}} { \int_set:Nn \l__pgfgo_sgf_start_int {1} \int_set:Nn \l__pgfgo_sgf_resume_int {\seq_count:N \l_pgfgo_kernel_sgf_moves_seq + 1} \prop_clear:N \l__pgfgo_sgf_numbered_prop \bool_set_false:N \l__pgfgo_sgf_outside_bool \bool_gset_false:N \g__pgfgo_captures_warned_bool \__pgfgo_sgf_context: \__pgfgo_sgf_last: \__pgfgo_sgf_choose: \tl_if_empty:NTF \l__pgfgo_sgf_slot_tl { \__pgfgo_sgf_setup_stones:nN {black} \l_pgfgo_kernel_sgf_black_seq \__pgfgo_sgf_setup_stones:nN {white} \l_pgfgo_kernel_sgf_white_seq }{ \__pgfgo_sgf_restore:V \l__pgfgo_sgf_slot_tl } \seq_map_indexed_inline:Nn \l_pgfgo_kernel_sgf_moves_seq { \int_compare:nNnF {##1} < {\l__pgfgo_sgf_start_int} { \int_set:Nn \l__pgfgo_sgf_index_int {##1} \__pgfgo_sgf_event:nnn ##2 } } \__pgfgo_sgf_save:nn {b} {\l__pgfgo_sgf_resume_int} }{ \bool_set_false:N \l__pgfgo_sgf_cache_bool \prop_clear:N \l__pgfgo_sgf_numbered_prop \__pgfgo_sgf_setup_stones:nN {black} \l_pgfgo_kernel_sgf_black_seq \__pgfgo_sgf_setup_stones:nN {white} \l_pgfgo_kernel_sgf_white_seq \__pgfgo_sgf_last: \seq_map_inline:Nn \l_pgfgo_kernel_sgf_moves_seq {\__pgfgo_sgf_event:nnn ##1} } } %\pgfgodefinesgf[game = , charset = , syntax = , origin = , %transpose]{}{}: SIRVE DONDE VA UN ARCHIVO SGF (\sgf, \sgfinfo, sgf size, ...). EL %KERNEL LO TRADUCE AL ARCHIVO; LAS OPCIONES QUEDAN EN \g__pgfgo_sgf_names_prop %({game}{charset}{origin}{transpose}{syntax}; game, charset Y syntax VACIOS SI NO SE DIERON) Y CADA COMANDO %LAS PONE ANTES DE SUS OPCIONES, QUE GANAN. UN NOMBRE QUE NO ESTA DEFINIDO ES UN ARCHIVO. %origin: LA ESQUINA DONDE VA EL PUNTO aa DEL ARCHIVO. transpose: LA PRIMERA LETRA DE CADA PUNTO ES LA FILA %Y NO LA COLUMNA. ENTRE LAS DOS, LAS OCHO SIMETRIAS DEL TABLERO. SOLO VALEN PARA EL NOMBRE: UN ARCHIVO SE %LEE COMO DICE SGF (aa ARRIBA A LA IZQUIERDA, LA PRIMERA LETRA ES LA COLUMNA). \prop_new:N \g__pgfgo_sgf_names_prop \tl_new:N \l__pgfgo_sgf_name_game_tl \tl_new:N \l__pgfgo_sgf_name_charset_tl \tl_new:N \l__pgfgo_sgf_name_origin_tl \tl_new:N \l__pgfgo_sgf_name_transpose_tl \tl_new:N \l__pgfgo_sgf_name_syntax_tl \tl_new:N \l__pgfgo_sgf_name_tl \keys_define:nn {pgfgo / define~sgf} { game .tl_set:N = \l__pgfgo_sgf_name_game_tl, charset .tl_set:N = \l__pgfgo_sgf_name_charset_tl, syntax .tl_set:N = \l__pgfgo_sgf_name_syntax_tl, origin .choices:nn = {top~left, top~right, bottom~left, bottom~right} {\tl_set_eq:NN \l__pgfgo_sgf_name_origin_tl \l_keys_choice_tl}, origin .initial:n = {top~left}, transpose .choices:nn = {true, false} {\tl_set_eq:NN \l__pgfgo_sgf_name_transpose_tl \l_keys_choice_tl}, transpose .default:n = {true}, transpose .initial:n = {false}, } %GUARDA LAS OPCIONES #1 DEL NOMBRE #2. \cs_new_protected:Npn \__pgfgo_sgf_name:nn #1#2 { \keys_set:nn {pgfgo / define~sgf} {#1} \prop_gput:Nee \g__pgfgo_sgf_names_prop {\text_expand:n {#2}} {{\exp_not:V \l__pgfgo_sgf_name_game_tl} {\exp_not:V \l__pgfgo_sgf_name_charset_tl} {\exp_not:V \l__pgfgo_sgf_name_origin_tl} {\exp_not:V \l__pgfgo_sgf_name_transpose_tl} {\exp_not:V \l__pgfgo_sgf_name_syntax_tl}} } \NewDocumentCommand \pgfgodefinesgf {O{}mm} { \group_begin: \__pgfgo_sgf_name:nn {#1} {#2} \pgfgo_kernel_if_feature:nT {sgf} {\pgfgo_kernel_sgf_define:nn {#2} {#3}} \group_end: } %\begin{pgfgosgf}[]{} ... \end{pgfgosgf}: UN ARCHIVO ESCRITO EN EL DOCUMENTO (EN CUALQUIER %SINTAXIS), QUE LOS COMANDOS DE SGF LEEN COMO EL ARCHIVO . LAS OPCIONES SON LAS DE \pgfgodefinesgf. %LAS LINEAS SE LEEN TAL CUAL (VER \pgfgo_kernel_sgf_text:nn): \begin{pgfgosgf}[]{} TERMINA SU %LINEA. SIN UN KERNEL QUE LEA PARTIDAS, EL CONTENIDO SE SALTEA. \pgfgo_kernel_if_feature:nTF {sgf} { \NewDocumentEnvironment {pgfgosgf} {O{}m} { \__pgfgo_sgf_name:nn {#1} {#2} \pgfgo_kernel_sgf_text:nn {#2} {\c_backslash_str end \c_left_brace_str pgfgosgf \c_right_brace_str} \ignorespaces } {\ignorespacesafterend} } { \NewDocumentEnvironment {pgfgosgf} {O{}m +b} {\pgfgo_kernel_require:n {sgf}} {\ignorespacesafterend} } %SI #1 ES UN NOMBRE DE \pgfgodefinesgf, PONE SU game, SU charset, SU syntax Y SU ORIENTACION. SI NO, LA %ORIENTACION DE SGF. \cs_new_protected:Npn \pgfgo_sgf_use_name:n #1 { \tl_set:Nn \l_pgfgo_kernel_sgf_origin_tl {top~left} \tl_set:Nn \l_pgfgo_kernel_sgf_transpose_tl {false} \prop_get:NeNT \g__pgfgo_sgf_names_prop {\text_expand:n {#1}} \l__pgfgo_sgf_name_tl {\exp_after:wN \__pgfgo_sgf_use_name:nnnnn \l__pgfgo_sgf_name_tl} } \cs_new_protected:Npn \__pgfgo_sgf_use_name:nnnnn #1#2#3#4#5 { \tl_if_empty:nF {#1} {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {#1}} \tl_if_empty:nF {#2} {\tl_set:Nn \l_pgfgo_kernel_sgf_charset_tl {#2}} \tl_set:Nn \l_pgfgo_kernel_sgf_origin_tl {#3} \tl_set:Nn \l_pgfgo_kernel_sgf_transpose_tl {#4} \tl_if_empty:nF {#5} {\tl_set:Nn \l_pgfgo_kernel_sgf_syntax_tl {#5}} } \cs_generate_variant:Nn \pgfgo_sgf_use_name:n {V} \prg_generate_conditional_variant:Nnn \prop_get:NnN {NeN} {T} %EJECUTA #2 CON EL game, EL charset, LA syntax Y LA ORIENTACION DEL NOMBRE #1, Y DESPUES VUELVE A LOS DE %ANTES (PARA LAS CLAVES DE goban, QUE NO ESTAN EN UN GRUPO PROPIO). \int_new:N \l__pgfgo_sgf_saved_game_int \tl_new:N \l__pgfgo_sgf_saved_charset_tl \tl_new:N \l__pgfgo_sgf_saved_origin_tl \tl_new:N \l__pgfgo_sgf_saved_transpose_tl \tl_new:N \l__pgfgo_sgf_saved_syntax_tl \cs_new_protected:Npn \pgfgo_sgf_with_name:nn #1#2 { \int_set_eq:NN \l__pgfgo_sgf_saved_game_int \l_pgfgo_kernel_sgf_game_int \tl_set_eq:NN \l__pgfgo_sgf_saved_charset_tl \l_pgfgo_kernel_sgf_charset_tl \tl_set_eq:NN \l__pgfgo_sgf_saved_origin_tl \l_pgfgo_kernel_sgf_origin_tl \tl_set_eq:NN \l__pgfgo_sgf_saved_transpose_tl \l_pgfgo_kernel_sgf_transpose_tl \tl_set_eq:NN \l__pgfgo_sgf_saved_syntax_tl \l_pgfgo_kernel_sgf_syntax_tl \pgfgo_sgf_use_name:n {#1} #2 \int_set_eq:NN \l_pgfgo_kernel_sgf_game_int \l__pgfgo_sgf_saved_game_int \tl_set_eq:NN \l_pgfgo_kernel_sgf_charset_tl \l__pgfgo_sgf_saved_charset_tl \tl_set_eq:NN \l_pgfgo_kernel_sgf_origin_tl \l__pgfgo_sgf_saved_origin_tl \tl_set_eq:NN \l_pgfgo_kernel_sgf_transpose_tl \l__pgfgo_sgf_saved_transpose_tl \tl_set_eq:NN \l_pgfgo_kernel_sgf_syntax_tl \l__pgfgo_sgf_saved_syntax_tl } \cs_generate_variant:Nn \pgfgo_sgf_with_name:nn {V} \cs_new_protected:Npn \pgfgo_sgf:nn #1#2 { \group_begin: \pgfgo_sgf_use_name:n {#2} \keys_set:nn {pgfgo / sgf} {#1} \tl_set:Nn \l__pgfgo_sgf_file_tl {#2} \exp_args:NnV \pgfgo_kernel_sgf_read:nn {#2} \l__pgfgo_sgf_variation_tl \__pgfgo_sgf_numbering: \bool_if:NT \l__pgfgo_sgf_check_size_bool {\__pgfgo_sgf_check_size:n {#2}} \__pgfgo_sgf_play: %LAS MARCAS, LAS FLECHAS Y LAS VARIANTES DE LA ULTIMA JUGADA. \seq_map_inline:Nn \l__pgfgo_sgf_marks_seq {\__pgfgo_sgf_mark:nnnnn ##1} \bool_if:NT \l__pgfgo_sgf_marks_bool { \pgfgo_kernel_sgf_lines:n {\l__pgfgo_sgf_last_int} \seq_map_inline:Nn \l_pgfgo_kernel_sgf_lines_seq {\__pgfgo_sgf_line:nnnnn ##1} } \seq_map_inline:Nn \l__pgfgo_sgf_variations_seq {\__pgfgo_sgf_variation:nnnn ##1} \__pgfgo_sgf_last_mark: \group_end: } %CON last~mark: LA MARCA DE LA ULTIMA JUGADA QUE SE MUESTRA (NO SI ES UN PASE, SI TIENE NUMERO NI SI EL %ARCHIVO MARCA ESE PUNTO). \cs_new_protected:Npn \__pgfgo_sgf_last_mark: { \bool_lazy_and:nnT {! \tl_if_empty_p:N \l__pgfgo_sgf_last_mark_tl} {\int_compare_p:nNn {\l__pgfgo_sgf_last_int} > {0}} { \int_zero:N \l_tmpa_int \seq_map_inline:Nn \l_pgfgo_kernel_sgf_moves_seq { \__pgfgo_sgf_if_move:nnnT ##1 { \int_incr:N \l_tmpa_int \int_compare:nNnT {\l_tmpa_int} = {\l__pgfgo_sgf_last_int} { \__pgfgo_sgf_last_mark:nnn ##1 \seq_map_break: } } } } } \cs_new_protected:Npn \__pgfgo_sgf_last_mark:nnn #1#2#3 { \tl_if_blank:nF {#2} { \__pgfgo_sgf_if_file_marked:nnF {#2} {#3} { \prop_if_in:NVF \l__pgfgo_sgf_numbered_prop \l__pgfgo_captures_key_tl { \use:e { \exp_not:N \__pgfgo_sgf_mark_put:nn {#1, \exp_not:V \l__pgfgo_sgf_last_mark_tl} {\exp_not:n {{#2}{#3}}} } } } } } %\sgf SOLO EXISTE DENTRO DE goban (VER pgf-go-goban.sty). \NewDocumentCommand{\__pgfgo_sgf_command}{O{}m}{ \__pgfgo_sgf_if_kernel:n {\pgfgo_sgf:nn {#1} {#2}} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %--------------------------------COMENTARIOS Y ANOTACIONES--------------------------------------% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %EL COMENTARIO DE UNA JUGADA ES SU NOMBRE (N, EN NEGRITA), SUS ANOTACIONES (TE, BM, DO, IT, GB, GW, DM, %UC, CON LOS TEXTOS DE /pgfgo/sgf annotations) Y SU COMENTARIO (C). \bool_new:N \l__pgfgo_sgf_annotations_bool \bool_set_true:N \l__pgfgo_sgf_annotations_bool %CADA COMANDO TIENE SU PROPIA OPCION annotations, QUE COPIA EN LA DE ARRIBA AL EMPEZAR. \bool_new:N \l__pgfgo_sgfcomment_annotations_bool \bool_set_true:N \l__pgfgo_sgfcomment_annotations_bool \bool_new:N \l__pgfgo_sgfanim_annotations_bool \bool_set_true:N \l__pgfgo_sgfanim_annotations_bool \bool_new:N \l__pgfgo_sgfdiag_annotations_bool \bool_set_true:N \l__pgfgo_sgfdiag_annotations_bool \bool_new:N \l__pgfgo_sgfprob_annotations_bool \bool_set_true:N \l__pgfgo_sgfprob_annotations_bool %CON chat = false, LOS COMENTARIOS PIERDEN EL CHAT DE KGS Y OGS (IGUAL: UNA OPCION POR COMANDO). \bool_new:N \l__pgfgo_sgf_chat_bool \bool_set_true:N \l__pgfgo_sgf_chat_bool \bool_new:N \l__pgfgo_sgfcomment_chat_bool \bool_set_true:N \l__pgfgo_sgfcomment_chat_bool \bool_new:N \l__pgfgo_sgfanim_chat_bool \bool_set_true:N \l__pgfgo_sgfanim_chat_bool \bool_new:N \l__pgfgo_sgfdiag_chat_bool \bool_set_true:N \l__pgfgo_sgfdiag_chat_bool \bool_new:N \l__pgfgo_sgfprob_chat_bool \bool_set_true:N \l__pgfgo_sgfprob_chat_bool %EL COMENTARIO LEIDO: SUS ANOTACIONES COMO TEXTOS, SI TIENE ANOTACIONES Y EL TEXTO DE C. \seq_new:N \l__pgfgo_sgf_note_seq \bool_new:N \l__pgfgo_sgf_annotated_bool \tl_new:N \l__pgfgo_sgf_comment_tl \keys_define:nn {pgfgo / sgf~annotations} { tesuji .tl_set:N = \l__pgfgo_sgf_note_TE_i_tl, tesuji .initial:n = {\pgfgo_text:n {tesuji}}, very~good~tesuji .tl_set:N = \l__pgfgo_sgf_note_TE_ii_tl, very~good~tesuji .initial:n = {\pgfgo_text:n {very~good~tesuji}}, bad~move .tl_set:N = \l__pgfgo_sgf_note_BM_i_tl, bad~move .initial:n = {\pgfgo_text:n {bad~move}}, very~bad~move .tl_set:N = \l__pgfgo_sgf_note_BM_ii_tl, very~bad~move .initial:n = {\pgfgo_text:n {very~bad~move}}, doubtful .tl_set:N = \l__pgfgo_sgf_note_DO_i_tl, doubtful .initial:n = {\pgfgo_text:n {doubtful}}, interesting .tl_set:N = \l__pgfgo_sgf_note_IT_i_tl, interesting .initial:n = {\pgfgo_text:n {interesting}}, good~for~black .tl_set:N = \l__pgfgo_sgf_note_GB_i_tl, good~for~black .initial:n = {\pgfgo_text:n {good~for~black}}, very~good~for~black .tl_set:N = \l__pgfgo_sgf_note_GB_ii_tl, very~good~for~black .initial:n = {\pgfgo_text:n {very~good~for~black}}, good~for~white .tl_set:N = \l__pgfgo_sgf_note_GW_i_tl, good~for~white .initial:n = {\pgfgo_text:n {good~for~white}}, very~good~for~white .tl_set:N = \l__pgfgo_sgf_note_GW_ii_tl, very~good~for~white .initial:n = {\pgfgo_text:n {very~good~for~white}}, even .tl_set:N = \l__pgfgo_sgf_note_DM_i_tl, even .initial:n = {\pgfgo_text:n {even}}, unclear .tl_set:N = \l__pgfgo_sgf_note_UC_i_tl, unclear .initial:n = {\pgfgo_text:n {unclear}}, } %DM Y UC ENFATIZADOS USAN EL MISMO TEXTO; DO E IT NO TIENEN VALOR. \clist_map_inline:nn {DM, UC, DO, IT} { \tl_new:c {l__pgfgo_sgf_note_ #1 _ii_tl} \tl_set:ce {l__pgfgo_sgf_note_ #1 _ii_tl} {\exp_not:c {l__pgfgo_sgf_note_ #1 _i_tl}} } \keys_define:nn {pgfgo} { sgf~annotations .code:n = {\keys_set:nn {pgfgo / sgf~annotations} {#1}}, } \cs_new_protected:Npn \__pgfgo_sgf_note:nn #1#2 { \str_if_eq:nnTF {#1} {N} {\seq_put_right:Nn \l__pgfgo_sgf_note_seq {\textbf{\pgfgo_kernel_sgf_name:n {#2}}}} { \cs_if_exist:cT {l__pgfgo_sgf_note_ #1 _ \int_to_roman:n {#2} _tl} {\seq_put_right:Nv \l__pgfgo_sgf_note_seq {l__pgfgo_sgf_note_ #1 _ \int_to_roman:n {#2} _tl}} } } %LEE EL COMENTARIO DE LA JUGADA #1 DE LA ULTIMA PARTIDA LEIDA (0: EL DE ANTES DE LA PRIMERA JUGADA), PARA %PREGUNTAR SI TIENE (\__pgfgo_sgf_if_comment:nT) Y ESCRIBIRLO (\__pgfgo_sgf_comment_use:) SIN VOLVER A PEDIRLO. \cs_new_protected:Npn \__pgfgo_sgf_comment_get:n #1 { \seq_clear:N \l__pgfgo_sgf_note_seq \bool_set_false:N \l__pgfgo_sgf_annotated_bool \bool_if:NT \l__pgfgo_sgf_annotations_bool { \pgfgo_kernel_sgf_annotations:n {#1} \seq_if_empty:NF \l_pgfgo_kernel_sgf_annotations_seq { \bool_set_true:N \l__pgfgo_sgf_annotated_bool \seq_map_inline:Nn \l_pgfgo_kernel_sgf_annotations_seq {\__pgfgo_sgf_note:nn ##1} } } \tl_set:Ne \l__pgfgo_sgf_comment_tl {\pgfgo_kernel_sgf_comment:nn {#1} {\bool_if:NTF \l__pgfgo_sgf_chat_bool {true} {false}}} } %UN TEXTO DEL ARCHIVO (COMENTARIO, PROPIEDAD): SE ESCRIBE, CON EL AVISO sgf-glyphs SI A LA FUENTE LE FALTAN %CARACTERES CJK (LaTeX SOLO LO ANOTA EN EL .log). CON luatexja, ctex, luatexko O xeCJK NO SE MIRA: ESCRIBEN ESOS %CARACTERES CON OTRA FUENTE, QUE NO ES LA ACTUAL. \msg_new:nnn {pgfgo} {sgf-glyphs} {The~font~'#1'~has~no~glyph~for~#2~(and~maybe~other~CJK~characters)~of~an~SGF~text.~Load~a~font~with~them,~for~example~with~ctex,~luatexja~or~luatexko.} \cs_new_protected:Npn \__pgfgo_sgf_text:n #1 { \bool_lazy_any:nF { {\cs_if_exist_p:N \ltjsetparameter} {\cs_if_exist_p:N \ctexset} {\cs_if_exist_p:N \hangulfontspec} {\cs_if_exist_p:N \setCJKmainfont} }{ \pgfgo_kernel_sgf_glyphs:n {#1} } #1 } \cs_generate_variant:Nn \__pgfgo_sgf_text:n {V} \cs_new_protected:Npn \__pgfgo_sgf_comment_use: { \seq_if_empty:NF \l__pgfgo_sgf_note_seq { \seq_use:Nn \l__pgfgo_sgf_note_seq {.~}. \tl_if_blank:VF \l__pgfgo_sgf_comment_tl {~} } \__pgfgo_sgf_text:V \l__pgfgo_sgf_comment_tl } %ESCRIBE EL COMENTARIO DE LA JUGADA #1 DE LA ULTIMA PARTIDA LEIDA. \cs_new_protected:Npn \pgfgo_sgf_comment:n #1 { \__pgfgo_sgf_comment_get:n {#1} \__pgfgo_sgf_comment_use: } %VERDADERO SI LA JUGADA #1 TIENE COMENTARIO O ANOTACIONES. DEJA EL COMENTARIO LISTO PARA %\__pgfgo_sgf_comment_use:. \prg_new_protected_conditional:Npnn \__pgfgo_sgf_if_comment:n #1 {T} { \__pgfgo_sgf_comment_get:n {#1} \bool_lazy_or:nnTF {\l__pgfgo_sgf_annotated_bool} {! \tl_if_blank_p:V \l__pgfgo_sgf_comment_tl} {\prg_return_true:} {\prg_return_false:} } %\sgfcomment[]{}{} ESCRIBE EL COMENTARIO DE UNA JUGADA. \tl_new:N \l__pgfgo_sgfcomment_variation_tl \keys_define:nn {pgfgo / sgf~comment} { game .code:n = {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {#1}}, variation .tl_set:N = \l__pgfgo_sgfcomment_variation_tl, annotations .bool_set:N = \l__pgfgo_sgfcomment_annotations_bool, annotations .default:n = {true}, chat .bool_set:N = \l__pgfgo_sgfcomment_chat_bool, chat .default:n = {true}, } \NewDocumentCommand \sgfcomment {O{}mm} { \__pgfgo_sgf_if_kernel:n { \group_begin: \pgfgo_sgf_use_name:n {#2} \keys_set:nn {pgfgo / sgf~comment} {#1} \bool_set_eq:NN \l__pgfgo_sgf_annotations_bool \l__pgfgo_sgfcomment_annotations_bool \bool_set_eq:NN \l__pgfgo_sgf_chat_bool \l__pgfgo_sgfcomment_chat_bool \exp_args:NnV \pgfgo_kernel_sgf_read:nn {#2} \l__pgfgo_sgfcomment_variation_tl \pgfgo_sgf_comment:n {#3} \group_end: } } %\sgfinfo{}{} ESCRIBE UNA PROPIEDAD DE LA RAIZ (PB, PW, RE, KM, DT, ...) O, CON move, %DE UNA JUGADA (BL Y WL: EL TIEMPO QUE LE QUEDA A CADA JUGADOR) DE LA LINEA variation. \int_new:N \l__pgfgo_sgfinfo_move_int \tl_new:N \l__pgfgo_sgfinfo_variation_tl \keys_define:nn {pgfgo / sgf~info} { game .code:n = {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {#1}}, move .int_set:N = \l__pgfgo_sgfinfo_move_int, variation .tl_set:N = \l__pgfgo_sgfinfo_variation_tl, } \NewDocumentCommand \sgfinfo {O{}mm} { \__pgfgo_sgf_if_kernel:n { \group_begin: \pgfgo_sgf_use_name:n {#2} \keys_set:nn {pgfgo / sgf~info} {#1} \bool_lazy_and:nnTF {\int_compare_p:nNn {\l__pgfgo_sgfinfo_move_int} = {0}} {\tl_if_empty_p:N \l__pgfgo_sgfinfo_variation_tl} {\tl_set:Ne \l_tmpa_tl {\pgfgo_kernel_sgf_info:nn {#2} {#3}}} { \tl_set:Ne \l_tmpa_tl { \pgfgo_kernel_sgf_move_info:nnnn {#2} {\l__pgfgo_sgfinfo_variation_tl} {\l__pgfgo_sgfinfo_move_int} {#3} } } \__pgfgo_sgf_text:V \l_tmpa_tl \group_end: } } \keys_define:nn {pgfgo} { sgf~comment .code:n = {\keys_set:nn {pgfgo / sgf~comment} {#1}}, sgf~info .code:n = {\keys_set:nn {pgfgo / sgf~info} {#1}}, } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %---------------------------------------ANIMACION-----------------------------------------------% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\sgfanimation[]{} RECORRE LA PARTIDA CON EL PAQUETE animate: UN goban POR CUADRO. %EL CUADRO k MUESTRA LA POSICION DESPUES DE LA JUGADA k (EL 0, LA DE ANTES DE LA PRIMERA JUGADA). %SE USA FUERA DE goban. NECESITA kernel = lua Y \usepackage{animate}. \int_new:N \l__pgfgo_sgfanim_from_int \int_new:N \l__pgfgo_sgfanim_to_int \tl_new:N \l__pgfgo_sgfanim_fps_tl \tl_new:N \l__pgfgo_sgfanim_goban_tl \tl_new:N \l__pgfgo_sgfanim_animate_tl \tl_new:N \l__pgfgo_sgfanim_last_tl \bool_new:N \l__pgfgo_sgfanim_numbers_bool \bool_new:N \l__pgfgo_sgfanim_comments_bool \dim_new:N \l__pgfgo_sgfanim_comment_height_dim \tl_new:N \l__pgfgo_sgfanim_comment_font_tl \tl_new:N \l__pgfgo_sgfanim_variation_tl \bool_new:N \l__pgfgo_sgfanim_marks_bool \bool_new:N \l__pgfgo_sgfanim_view_bool \bool_new:N \l__pgfgo_sgfanim_partial_bool \tl_new:N \l__pgfgo_sgfanim_partial_tl \bool_new:N \l__pgfgo_sgfanim_layers_bool \tl_new:N \l__pgfgo_sgfanim_file_tl \tl_new:N \l__pgfgo_sgfanim_board_tl %LAS JUGADAS (SIN LOS CAMBIOS DE NODOS NI LOS NUMEROS), {black | white}{x}{y}: LA JUGADA DE CADA CUADRO. \seq_new:N \l__pgfgo_sgfanim_moves_seq \box_new:N \l__pgfgo_sgfanim_box \keys_define:nn {pgfgo / sgf~animation} { from .int_set:N = \l__pgfgo_sgfanim_from_int, from .initial:n = {0}, %last (-1): LA ULTIMA JUGADA. to .code:n = {\__pgfgo_sgf_set_to:Nnn \l__pgfgo_sgfanim_to_int {-1} {#1}}, to .initial:n = {last}, fps .tl_set:N = \l__pgfgo_sgfanim_fps_tl, fps .initial:n = {1}, goban .tl_set:N = \l__pgfgo_sgfanim_goban_tl, animate .tl_set:N = \l__pgfgo_sgfanim_animate_tl, animate .initial:n = {controls}, numbers .bool_set:N = \l__pgfgo_sgfanim_numbers_bool, numbers .default:n = {true}, %OPCIONES DE LA MARCA DE LA ULTIMA JUGADA (SIN numbers). false: SIN MARCA. last~mark .code:n = { \str_if_eq:nnTF {#1} {false} {\tl_clear:N \l__pgfgo_sgfanim_last_tl} {\tl_set:Nn \l__pgfgo_sgfanim_last_tl {#1}} }, last~mark .initial:n = {circle}, comments .code:n = {\keys_set:nn {pgfgo / sgf~animation / comments} {#1}}, comments .default:n = {true}, %COMO EN \sgf. variation .tl_set:N = \l__pgfgo_sgfanim_variation_tl, marks .bool_set:N = \l__pgfgo_sgfanim_marks_bool, marks .default:n = {true}, marks .initial:n = {true}, %LAS ANOTACIONES (TE, BM, GB, ...) Y EL NOMBRE DEL NODO, CON EL COMENTARIO. annotations .bool_set:N = \l__pgfgo_sgfanim_annotations_bool, annotations .default:n = {true}, chat .bool_set:N = \l__pgfgo_sgfanim_chat_bool, chat .default:n = {true}, game .code:n = {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {#1}}, %SI EL ARCHIVO TIENE VISTA (VW), LOS TABLEROS MUESTRAN SOLO ESA PARTE. view .bool_set:N = \l__pgfgo_sgfanim_view_bool, view .default:n = {true}, view .initial:n = {true}, %auto: LOS TABLEROS MUESTRAN SOLO LA PARTE QUE USA LA PARTIDA (SI NO HAY VISTA). partial .code:n = {\__pgfgo_sgf_partial:NNn \l__pgfgo_sgfanim_partial_bool \l__pgfgo_sgfanim_partial_tl {#1}}, partial .initial:n = {false}, %POR CAPAS: CADA PIEDRA SE DIBUJA UNA SOLA VEZ (VER MAS ABAJO). layers .bool_set:N = \l__pgfgo_sgfanim_layers_bool, layers .default:n = {true}, layers .initial:n = {true}, } %COMO EN \sgf. \__pgfgo_sgf_numbering_keys:nnn {pgfgo / sgf~animation} {sgfanim} {100} %LOS COMENTARIOS DE CADA CUADRO, DEBAJO DEL TABLERO, EN UNA CAJA DE ALTO height. \keys_define:nn {pgfgo / sgf~animation / comments} { true .code:n = {\bool_set_true:N \l__pgfgo_sgfanim_comments_bool}, false .code:n = {\bool_set_false:N \l__pgfgo_sgfanim_comments_bool}, height .dim_set:N = \l__pgfgo_sgfanim_comment_height_dim, height .initial:n = {4em}, font .tl_set:N = \l__pgfgo_sgfanim_comment_font_tl, font .initial:n = {\small}, } \keys_define:nn {pgfgo} { sgf~animation .code:n = {\keys_set:nn {pgfgo / sgf~animation} {#1}} } \msg_new:nnn {pgfgo} {sgf-animation-animate} {\iow_char:N\\sgfanimation~needs~the~animate~package.~Add~\iow_char:N\\usepackage{animate}.} \cs_new_protected:Npn \__pgfgo_sgfanim_keep_move:nnn #1#2#3 { \__pgfgo_sgf_if_move:nnnT {#1} {#2} {#3} {\seq_put_right:Nn \l__pgfgo_sgfanim_moves_seq {{#1}{#2}{#3}}} } %LEE LA PARTIDA Y FIJA LOS CUADROS. SEPARADO DE \pgfgo_sgfanimation:nn PARA PODER DIBUJAR CUADROS SUELTOS. \cs_new_protected:Npn \pgfgo_sgfanimation_setup:nn #1#2 { \pgfgo_sgf_use_name:n {#2} \keys_set:nn {pgfgo / sgf~animation} {#1} \bool_set_eq:NN \l__pgfgo_sgf_annotations_bool \l__pgfgo_sgfanim_annotations_bool \bool_set_eq:NN \l__pgfgo_sgf_chat_bool \l__pgfgo_sgfanim_chat_bool %CADA CUADRO SIGUE LA PARTIDA DESDE EL ANTERIOR (VER \__pgfgo_sgf_play:). \__pgfgo_sgf_cache_begin: \tl_set:Nn \l__pgfgo_sgfanim_file_tl {#2} \tl_clear:N \l__pgfgo_sgf_extent_tl \bool_if:NT \l__pgfgo_sgfanim_partial_bool {\__pgfgo_sgf_extent:nV {#2} \l__pgfgo_sgfanim_variation_tl} \exp_args:NnV \pgfgo_kernel_sgf_read:nn {#2} \l__pgfgo_sgfanim_variation_tl %LOS TABLEROS TIENEN EL TAMANO DE LA PARTIDA (goban = {...} PUEDE CAMBIARLO). \__pgfgo_sgf_board:N \l__pgfgo_sgfanim_board_tl %UN CUADRO POR JUGADA. \seq_clear:N \l__pgfgo_sgfanim_moves_seq \seq_map_inline:Nn \l_pgfgo_kernel_sgf_moves_seq {\__pgfgo_sgfanim_keep_move:nnn ##1} \int_set:Nn \l__pgfgo_sgfanim_to_int { \int_compare:nNnTF {\l__pgfgo_sgfanim_to_int} < {0} {\seq_count:N \l__pgfgo_sgfanim_moves_seq} {\int_min:nn {\l__pgfgo_sgfanim_to_int} {\seq_count:N \l__pgfgo_sgfanim_moves_seq}} } \int_set:Nn \l__pgfgo_sgfanim_from_int {\int_max:nn {0} {\int_min:nn {\l__pgfgo_sgfanim_from_int} {\l__pgfgo_sgfanim_to_int}}} %TODOS LOS CUADROS TIENEN EL MISMO TABLERO: SI LA VISTA (VW) CAMBIA, EL QUE ABARCA TODAS. \int_set_eq:NN \l_pgfgo_goban_sgf_view_from_int \l__pgfgo_sgfanim_from_int \int_set_eq:NN \l_pgfgo_goban_sgf_view_to_int \l__pgfgo_sgfanim_to_int \tl_set_eq:NN \l_pgfgo_goban_sgf_view_variation_tl \l__pgfgo_sgfanim_variation_tl } %MARCA LA JUGADA #2,#3 DE #1. UN PASE NO SE MARCA, NI UN PUNTO QUE YA MARCA EL ARCHIVO. \cs_new_protected:Npn \__pgfgo_sgfanim_mark:nnn #1#2#3 { \tl_if_blank:nF {#2} { \bool_if:NTF \l__pgfgo_sgfanim_marks_bool {\__pgfgo_sgf_if_file_marked:nnF {#2} {#3} {\__pgfgo_sgfanim_mark_put:nnn {#1} {#2} {#3}}} {\__pgfgo_sgfanim_mark_put:nnn {#1} {#2} {#3}} } } \cs_new_protected:Npn \__pgfgo_sgfanim_mark_put:nnn #1#2#3 { \use:e { \exp_not:N \pgfgo_marks_parsed:nn {#1, \exp_not:V \l__pgfgo_sgfanim_last_tl} {\exp_not:n {{#2}{#3}}} } } %ARMA UN CUADRO (O UNA LAMINA): EL goban CON #1 ADENTRO Y, CON comments, EL COMENTARIO #2 DEBAJO. \cs_new_protected:Npn \__pgfgo_sgfanim_wrap:nn #1#2 { \hbox_set:Nn \l__pgfgo_sgfanim_box { \use:e { \exp_not:N \begin{goban} [ \l__pgfgo_sgfanim_board_tl, \tl_if_empty:NTF \l__pgfgo_sgfanim_partial_tl { \bool_if:NT \l__pgfgo_sgfanim_partial_bool {partial = auto,} \bool_if:NT \l__pgfgo_sgfanim_view_bool {sgf~view = {\exp_not:V \l__pgfgo_sgfanim_file_tl},} }{ partial = {\exp_not:V \l__pgfgo_sgfanim_partial_tl}, } \exp_not:V \l__pgfgo_sgfanim_goban_tl ] } \__pgfgo_sgf_extent_add: #1 \end{goban} } \bool_if:NTF \l__pgfgo_sgfanim_comments_bool { \vbox:n { \box_use:N \l__pgfgo_sgfanim_box \skip_vertical:n {0.5em} \hbox:n { %EL \strut DA LA MISMA ALTURA A LA PRIMERA LINEA, HAYA COMENTARIO O NO: TODOS LOS CUADROS %MIDEN LO MISMO (SI NO, animate LOS ESTIRA PARA QUE ENTREN EN LA ANIMACION). \parbox[t][\l__pgfgo_sgfanim_comment_height_dim][t]{\box_wd:N \l__pgfgo_sgfanim_box} {\raggedright \l__pgfgo_sgfanim_comment_font_tl \strut #2} } } }{ \box_use:N \l__pgfgo_sgfanim_box } } %LA PARTIDA HASTA LA JUGADA #1, CON LA MARCA DE LA ULTIMA JUGADA. \cs_new_protected:Npn \__pgfgo_sgfanim_game:n #1 { \bool_set:Nn \l__pgfgo_sgf_check_size_bool {\int_compare_p:nNn {#1} = {\l__pgfgo_sgfanim_from_int}} \use:e { \exp_not:N \pgfgo_sgf:nn { to = \int_eval:n {#1}, from = \bool_if:NTF \l__pgfgo_sgfanim_numbers_bool {1} {\int_eval:n {#1 + 1}}, variation = {\exp_not:V \l__pgfgo_sgfanim_variation_tl}, marks = \bool_if:NTF \l__pgfgo_sgfanim_marks_bool {true} {false}, step = {\exp_not:V \l__pgfgo_sgfanim_step_clist}, restart = { from = \int_use:N \l__pgfgo_sgfanim_restart_from_int, \exp_not:V \l__pgfgo_sgfanim_restart_tl }, numbers = true, last~mark = false } {\exp_not:V \l__pgfgo_sgfanim_file_tl} } \bool_if:nT { ! \l__pgfgo_sgfanim_numbers_bool && ! \tl_if_empty_p:N \l__pgfgo_sgfanim_last_tl && \int_compare_p:nNn {#1} > {0} }{ \use:e { \exp_not:N \__pgfgo_sgfanim_mark:nnn \seq_item:Nn \l__pgfgo_sgfanim_moves_seq {#1} } } } %DIBUJA EL CUADRO #1: LA POSICION DESPUES DE LA JUGADA #1. \cs_new_protected:Npn \pgfgo_sgfanimation_frame:n #1 { \group_begin: \mode_leave_vertical: \__pgfgo_sgfanim_wrap:nn {\__pgfgo_sgfanim_game:n {#1}} {\pgfgo_sgf_comment:n {#1}} \group_end: } %POR CAPAS (layers): CADA PIEDRA SE DIBUJA UNA SOLA VEZ, EN UNA LAMINA QUE animate MUESTRA (CON UN %timeline) DESDE EL CUADRO EN QUE APARECE HASTA EL ULTIMO EN QUE SIGUE IGUAL. EL PDF CRECE CON LA CANTIDAD %DE JUGADAS, Y NO CON SU CUADRADO. LAS LAMINAS SE NUMERAN EN EL ORDEN EN QUE SE ARMAN: LA 0 ES EL %TABLERO; DESPUES, POR CADA CUADRO, LO QUE SOLO ESTA EN ESE CUADRO (MARCAS Y COMENTARIO) Y LAS PIEDRAS %QUE APARECEN EN EL. TODAS TIENEN EL TAMANO DEL TABLERO. \int_new:N \g__pgfgo_sgfanim_layer_int \int_new:N \g__pgfgo_sgfanim_file_int \tl_new:N \l__pgfgo_sgfanim_old_tl %LAS PIEDRAS ("x,y" -> CODIGO) DEL CUADRO ANTERIOR Y DEL ACTUAL. \prop_new:N \l__pgfgo_sgfanim_prev_prop \prop_new:N \l__pgfgo_sgfanim_cur_prop %LA FIRMA DE LO QUE SE DIBUJA EN CADA PUNTO ({codigo}{atenuada}{marcas}) Y EL CUADRO AL QUE PERTENECE %("ANIMACION.CUADRO"), EN EL CUADRO ANTERIOR (old) Y EN EL ACTUAL (new): \l__pgfgo_sgfanim_old_sig_x,y_tl, ETC. \int_new:N \g__pgfgo_sgfanim_run_int \tl_new:N \l__pgfgo_sgfanim_stamp_tl \tl_new:N \l__pgfgo_sgfanim_last_stamp_tl \cs_new_protected:Npn \__pgfgo_sgfanim_point_vars:n #1 { \tl_if_exist:cF {l__pgfgo_sgfanim_old_sig_ #1 _tl} { \tl_new:c {l__pgfgo_sgfanim_old_sig_ #1 _tl} \tl_new:c {l__pgfgo_sgfanim_old_stamp_ #1 _tl} \tl_new:c {l__pgfgo_sgfanim_new_sig_ #1 _tl} \tl_new:c {l__pgfgo_sgfanim_new_stamp_ #1 _tl} } } %"x,y" -> LAMINA DE LA PIEDRA QUE SE VE AHORA, Y LAMINA -> CUADRO EN QUE APARECIO. \prop_new:N \l__pgfgo_sgfanim_active_prop \prop_new:N \l__pgfgo_sgfanim_start_prop %"x,y" -> LAMINA DE LAS PIEDRAS QUE APARECEN EN EL CUADRO QUE SE ARMA. \prop_new:N \g__pgfgo_sgfanim_new_prop %{LAMINA}{CUADRO EN QUE APARECE}{CANTIDAD DE CUADROS} DE CADA PIEDRA, Y CUADRO -> LAMINA DEL CUADRO. \seq_new:N \l__pgfgo_sgfanim_stones_seq \prop_new:N \l__pgfgo_sgfanim_own_prop \iow_new:N \g__pgfgo_sgfanim_iow \tl_new:N \l__pgfgo_sgfanim_timeline_tl %LAS CAPAS DE PGF DE LAS LAMINAS: EL TABLERO, Y TODO LO DEMAS. \clist_const:Nn \c__pgfgo_sgfanim_board_layers_clist {pgfgo_layer_goban_border, pgfgo_layer_goban_grid, pgfgo_layer_goban_labels} \clist_const:Nn \c__pgfgo_sgfanim_top_layers_clist {pgfgo_layer_territory, pgfgo_layer_mark_shadow, pgfgo_layer_stone, pgfgo_layer_stone_mark, pgfgo_layer_mark, main} %GUARDA LA LAMINA SIGUIENTE (#1: goban, #2: COMENTARIO). \cs_new_protected:Npn \__pgfgo_sgfanim_layer:nn #1#2 { \box_if_exist:cF {g__pgfgo_sgfanim_ \int_use:N \g__pgfgo_sgfanim_layer_int _box} {\box_new:c {g__pgfgo_sgfanim_ \int_use:N \g__pgfgo_sgfanim_layer_int _box}} \hbox_gset:cn {g__pgfgo_sgfanim_ \int_use:N \g__pgfgo_sgfanim_layer_int _box} {\__pgfgo_sgfanim_wrap:nn {#1} {#2}} \int_gincr:N \g__pgfgo_sgfanim_layer_int } %SIN goban/captures, LAS PIEDRAS SE GUARDAN IGUAL (PARA DIBUJARLAS EN SUS LAMINAS), PERO NO SE QUITA NINGUNA. \cs_new_protected:Npn \__pgfgo_sgfanim_collect: { \bool_if:NF \l_pgfgo_goban_captures_bool { \bool_set_true:N \l_pgfgo_goban_captures_bool \bool_set_true:N \l_pgfgo_captures_collect_bool \pgfgo_captures_begin: } } %UNA PIEDRA QUE APARECE EN EL PUNTO #1 CON LA FIRMA #2: SU LAMINA. \cs_new_protected:Npn \__pgfgo_sgfanim_new_stone:nn #1#2 { \prop_gput:Nne \g__pgfgo_sgfanim_new_prop {#1} {\int_use:N \g__pgfgo_sgfanim_layer_int} \__pgfgo_sgfanim_layer:nn { \__pgfgo_sgfanim_collect: \__pgfgo_sgfanim_put:nnnn {#1} #2 } {} } \cs_new_protected:Npn \__pgfgo_sgfanim_put:nnnn #1#2#3#4 { \prop_gput:Nnn \g__pgfgo_captures_pending_prop {#1} {#2} \int_compare:nNnT {#3} = {1} {\prop_gput:Nnn \g__pgfgo_captures_faded_prop {#1} {}} \tl_if_empty:nF {#4} {\prop_gput:Nnn \g__pgfgo_captures_marks_prop {#1} {#4}} } %TERMINA LA LAMINA DE LA PIEDRA QUE SE VEIA EN #1; #2 ES EL ULTIMO CUADRO EN QUE SE VE. \cs_new_protected:Npn \__pgfgo_sgfanim_end_stone:nn #1#2 { \prop_pop:NnNT \l__pgfgo_sgfanim_active_prop {#1} \l__pgfgo_sgfanim_old_tl { \seq_put_right:Ne \l__pgfgo_sgfanim_stones_seq { {\l__pgfgo_sgfanim_old_tl} {\prop_item:NV \l__pgfgo_sgfanim_start_prop \l__pgfgo_sgfanim_old_tl} {\int_eval:n {#2 - \prop_item:NV \l__pgfgo_sgfanim_start_prop \l__pgfgo_sgfanim_old_tl + 1}} } } } %EL CUADRO #1: SU LAMINA, Y LAS LAMINAS DE LAS PIEDRAS QUE CAMBIARON. \cs_new_protected:Npn \__pgfgo_sgfanim_layers_frame:n #1 { \prop_put:Nne \l__pgfgo_sgfanim_own_prop {#1} {\int_use:N \g__pgfgo_sgfanim_layer_int} \group_begin: \bool_set_true:N \l_pgfgo_captures_overlay_bool \clist_set_eq:NN \l_pgfgo_goban_layers_clist \c__pgfgo_sgfanim_top_layers_clist \__pgfgo_sgfanim_layer:nn {\__pgfgo_sgfanim_collect: \__pgfgo_sgfanim_game:n {#1}} {\pgfgo_sgf_comment:n {#1}} \group_end: %LO QUE QUEDO EN CADA PUNTO (LAS PROPIEDADES DE LAS CAPTURAS SON GLOBALES; LAS LAMINAS DE LAS PIEDRAS %LAS VACIAN). LA FIRMA DE CADA PUNTO VA EN SU PROPIA VARIABLE, CON EL CUADRO AL QUE PERTENECE, PARA %COMPARAR LOS DOS CUADROS SIN BUSCAR EN LISTAS LARGAS. \tl_set:Ne \l__pgfgo_sgfanim_stamp_tl {\int_use:N \g__pgfgo_sgfanim_run_int . \int_eval:n {#1}} \tl_set:Ne \l__pgfgo_sgfanim_last_stamp_tl {\int_use:N \g__pgfgo_sgfanim_run_int . \int_eval:n {#1 - 1}} \prop_set_eq:NN \l__pgfgo_sgfanim_cur_prop \g__pgfgo_captures_pending_prop \prop_map_inline:Nn \l__pgfgo_sgfanim_cur_prop { \__pgfgo_sgfanim_point_vars:n {##1} \tl_set_eq:cN {l__pgfgo_sgfanim_new_stamp_ ##1 _tl} \l__pgfgo_sgfanim_stamp_tl \tl_set:ce {l__pgfgo_sgfanim_new_sig_ ##1 _tl} { {\exp_not:n {##2}} {\prop_if_in:NnTF \g__pgfgo_captures_faded_prop {##1} {1} {0}} {\prop_item:Nn \g__pgfgo_captures_marks_prop {##1}} } } %LAS PIEDRAS QUE YA NO SE VEN IGUAL TERMINAN EN EL CUADRO ANTERIOR. \prop_map_inline:Nn \l__pgfgo_sgfanim_prev_prop { \bool_lazy_and:nnF {\tl_if_eq_p:cN {l__pgfgo_sgfanim_new_stamp_ ##1 _tl} \l__pgfgo_sgfanim_stamp_tl} {\tl_if_eq_p:cc {l__pgfgo_sgfanim_new_sig_ ##1 _tl} {l__pgfgo_sgfanim_old_sig_ ##1 _tl}} {\__pgfgo_sgfanim_end_stone:nn {##1} {#1 - 1}} } %LAS QUE APARECEN O CAMBIAN, EMPIEZAN. \group_begin: \clist_set_eq:NN \l_pgfgo_goban_layers_clist \c__pgfgo_sgfanim_top_layers_clist \prop_map_inline:Nn \l__pgfgo_sgfanim_cur_prop { \bool_lazy_and:nnF {\tl_if_eq_p:cN {l__pgfgo_sgfanim_old_stamp_ ##1 _tl} \l__pgfgo_sgfanim_last_stamp_tl} {\tl_if_eq_p:cc {l__pgfgo_sgfanim_new_sig_ ##1 _tl} {l__pgfgo_sgfanim_old_sig_ ##1 _tl}} {\exp_args:Nnv \__pgfgo_sgfanim_new_stone:nn {##1} {l__pgfgo_sgfanim_new_sig_ ##1 _tl}} } \group_end: \prop_map_inline:Nn \l__pgfgo_sgfanim_cur_prop { \tl_set_eq:cc {l__pgfgo_sgfanim_old_stamp_ ##1 _tl} {l__pgfgo_sgfanim_new_stamp_ ##1 _tl} \tl_set_eq:cc {l__pgfgo_sgfanim_old_sig_ ##1 _tl} {l__pgfgo_sgfanim_new_sig_ ##1 _tl} } \prop_map_inline:Nn \g__pgfgo_sgfanim_new_prop { \prop_put:Nnn \l__pgfgo_sgfanim_active_prop {##1} {##2} \prop_put:Nnn \l__pgfgo_sgfanim_start_prop {##2} {#1} } \prop_gclear:N \g__pgfgo_sgfanim_new_prop \prop_set_eq:NN \l__pgfgo_sgfanim_prev_prop \l__pgfgo_sgfanim_cur_prop } %ARMA TODAS LAS LAMINAS (DESPUES DE \pgfgo_sgfanimation_setup:nn). \cs_new_protected:Npn \pgfgo_sgfanimation_layers: { \int_gincr:N \g__pgfgo_sgfanim_run_int \int_gzero:N \g__pgfgo_sgfanim_layer_int \prop_clear:N \l__pgfgo_sgfanim_prev_prop \prop_clear:N \l__pgfgo_sgfanim_active_prop \prop_clear:N \l__pgfgo_sgfanim_start_prop \prop_clear:N \l__pgfgo_sgfanim_own_prop \seq_clear:N \l__pgfgo_sgfanim_stones_seq %LA LAMINA 0, EL TABLERO, DA EL TAMANO DE TODAS. \group_begin: \clist_set_eq:NN \l_pgfgo_goban_layers_clist \c__pgfgo_sgfanim_board_layers_clist \__pgfgo_sgfanim_layer:nn {} {} \group_end: \tl_set_eq:NN \l_pgfgo_goban_bbox_tl \g_pgfgo_goban_bbox_tl \int_step_inline:nnn {\l__pgfgo_sgfanim_from_int} {\l__pgfgo_sgfanim_to_int} {\__pgfgo_sgfanim_layers_frame:n {##1}} \prop_map_inline:Nn \l__pgfgo_sgfanim_active_prop {\__pgfgo_sgfanim_end_stone:nn {##1} {\l__pgfgo_sgfanim_to_int}} } %EL timeline DE animate: UNA LINEA POR CUADRO, CON TRES PILAS (TABLERO; PIEDRAS; LAMINA DEL CUADRO). \cs_new_protected:Npn \__pgfgo_sgfanim_timeline:n #1 { \prop_clear:N \l_tmpa_prop \seq_map_inline:Nn \l__pgfgo_sgfanim_stones_seq {\__pgfgo_sgfanim_timeline_stone:nnn ##1} \iow_open:Nn \g__pgfgo_sgfanim_iow {#1} \int_step_inline:nnn {\l__pgfgo_sgfanim_from_int} {\l__pgfgo_sgfanim_to_int} { \iow_now:Ne \g__pgfgo_sgfanim_iow { :: \int_compare:nNnT {##1} = {\l__pgfgo_sgfanim_from_int} {0x0} ; \prop_item:Nn \l_tmpa_prop {##1} ; \prop_item:Nn \l__pgfgo_sgfanim_own_prop {##1} } } \iow_close:N \g__pgfgo_sgfanim_iow } \cs_generate_variant:Nn \__pgfgo_sgfanim_timeline:n {V} \cs_new_protected:Npn \__pgfgo_sgfanim_timeline_stone:nnn #1#2#3 { \prop_get:NnNTF \l_tmpa_prop {#2} \l_tmpa_tl {\prop_put:Nne \l_tmpa_prop {#2} {\l_tmpa_tl , #1x#3}} {\prop_put:Nnn \l_tmpa_prop {#2} {#1x#3}} } %EL CUADRO #1 ARMADO CON SUS LAMINAS, UNA SOBRE OTRA (PARA COMPROBAR QUE ES IGUAL AL CUADRO ENTERO). \cs_new_protected:Npn \pgfgo_sgfanimation_layers_frame:n #1 { \mode_leave_vertical: \hbox:n { \hbox_overlap_right:n {\box_use:c {g__pgfgo_sgfanim_0_box}} \seq_map_inline:Nn \l__pgfgo_sgfanim_stones_seq {\__pgfgo_sgfanim_overlap:nnnn {#1} ##1} \box_use:c {g__pgfgo_sgfanim_ \prop_item:Nn \l__pgfgo_sgfanim_own_prop {#1} _box} } } \cs_new_protected:Npn \__pgfgo_sgfanim_overlap:nnnn #1#2#3#4 { \int_compare:nT {#3 <= #1 < #3 + #4} {\hbox_overlap_right:n {\box_use:c {g__pgfgo_sgfanim_ #2 _box}}} } %UNA LAMINA Y EL CAMBIO DE CUADRO (ARMADAS DE UNA VEZ: SUMARLAS UNA POR UNA ES CUADRATICO). \cs_new:Npn \__pgfgo_sgfanim_frame_item:n #1 {\exp_not:n {\box_use:c {g__pgfgo_sgfanim_ #1 _box} \newframe}} %LA ANIMACION POR CAPAS: LAS LAMINAS, UNA POR CUADRO DE animate, Y EL timeline QUE DICE CUALES SE VEN. \cs_new_protected:Npn \__pgfgo_sgfanim_layered: { \pgfgo_sgfanimation_layers: \int_gincr:N \g__pgfgo_sgfanim_file_int \tl_set:Ne \l__pgfgo_sgfanim_timeline_tl {\c_sys_jobname_str -pgfgo- \int_use:N \g__pgfgo_sgfanim_file_int .tln} %animate LEE EL timeline SIN COMILLAS: UN ESPACIO EN EL NOMBRE DEL ARCHIVO LO CORTA. LAS LLAVES %DE timeline = {...} PROTEGEN LAS COMAS Y LOS = DEL NOMBRE. \tl_replace_all:Nnn \l__pgfgo_sgfanim_timeline_tl {~} {_} \__pgfgo_sgfanim_timeline:V \l__pgfgo_sgfanim_timeline_tl \tl_set:Ne \l_tmpb_tl {\int_step_function:nnN {0} {\g__pgfgo_sgfanim_layer_int - 2} \__pgfgo_sgfanim_frame_item:n} \mode_leave_vertical: \use:e { \exp_not:N \begin{animateinline} [\exp_not:V \l__pgfgo_sgfanim_animate_tl, timeline = {\l__pgfgo_sgfanim_timeline_tl}] {\exp_not:V \l__pgfgo_sgfanim_fps_tl} \exp_not:V \l_tmpb_tl \exp_not:N \box_use:c {g__pgfgo_sgfanim_ \int_eval:n {\g__pgfgo_sgfanim_layer_int - 1} _box} \exp_not:N \end{animateinline} } } %LA ANIMACION SIN CAPAS: CADA CUADRO ES UN goban ENTERO. \cs_new_protected:Npn \__pgfgo_sgfanim_frames: { \use:e { \exp_not:N \begin{animateinline} [\exp_not:V \l__pgfgo_sgfanim_animate_tl] {\exp_not:V \l__pgfgo_sgfanim_fps_tl} \exp_not:N \multiframe {\int_eval:n {\l__pgfgo_sgfanim_to_int - \l__pgfgo_sgfanim_from_int + 1}} {iPgfgoFrame = \int_use:N \l__pgfgo_sgfanim_from_int + 1} {\exp_not:N \pgfgo_sgfanimation_frame:n {\exp_not:N \iPgfgoFrame}} \exp_not:N \end{animateinline} } } \cs_new_protected:Npn \pgfgo_sgfanimation:nn #1#2 { \group_begin: \pgfgo_sgfanimation_setup:nn {#1} {#2} \bool_if:NTF \l__pgfgo_sgfanim_layers_bool {\__pgfgo_sgfanim_layered:} {\__pgfgo_sgfanim_frames:} \group_end: } \NewDocumentCommand{\sgfanimation}{O{}m}{ \__pgfgo_sgf_if_kernel:n { \cs_if_exist:NTF \animateinline {\pgfgo_sgfanimation:nn {#1} {#2}} {\msg_error:nn {pgfgo} {sgf-animation-animate}} } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %--------------------------------SERIE DE DIAGRAMAS---------------------------------------------% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\sgfdiagrams[]{} DIBUJA LA PARTIDA COMO EN LOS LIBROS: UN DIAGRAMA CADA step JUGADAS %(1-50, 51-100, ...). CADA UNO PARTE DE LA POSICION REAL (LAS JUGADAS ANTERIORES SIN NUMERO, CON LAS %CAPTURAS), Y DEBAJO LLEVA SU EPIGRAFE ("Diagram 2 (51-100)") Y SUS NOTAS "N at M". SE USA FUERA DE goban. \int_new:N \l__pgfgo_sgfdiag_from_int \int_new:N \l__pgfgo_sgfdiag_to_int \tl_new:N \l__pgfgo_sgfdiag_layout_tl \tl_new:N \l__pgfgo_sgfdiag_goban_tl \tl_new:N \l__pgfgo_sgfdiag_variation_tl \tl_new:N \l__pgfgo_sgfdiag_title_tl \tl_new:N \l__pgfgo_sgfdiag_font_tl \bool_new:N \l__pgfgo_sgfdiag_numbers_bool \tl_new:N \l__pgfgo_sgfdiag_last_tl \bool_new:N \l__pgfgo_sgfdiag_notes_bool \bool_new:N \l__pgfgo_sgfdiag_comments_bool \tl_new:N \l__pgfgo_sgfdiag_comment_font_tl \tl_new:N \l__pgfgo_sgfdiag_comment_align_tl \bool_new:N \l__pgfgo_sgfdiag_root_bool \tl_new:N \l__pgfgo_sgfdiag_comment_separator_tl \tl_new:N \l__pgfgo_sgfdiag_comment_position_tl \tl_new:N \l__pgfgo_sgfdiag_comment_width_tl \dim_new:N \l__pgfgo_sgfdiag_comment_sep_dim \tl_new:N \l__pgfgo_sgfdiag_comment_height_tl \bool_new:N \l__pgfgo_sgfdiag_comment_first_bool %EL NUMERO DELANTE DE CADA COMENTARIO (comments/number). \cs_new:Npn \__pgfgo_sgfdiag_comment_number:n #1 {} \bool_new:N \l__pgfgo_sgfdiag_view_bool \bool_new:N \l__pgfgo_sgfdiag_partial_bool \tl_new:N \l__pgfgo_sgfdiag_partial_tl \bool_new:N \l__pgfgo_sgfdiag_figures_bool \bool_new:N \l__pgfgo_sgfdiag_result_bool \tl_new:N \l__pgfgo_sgfdiag_result_title_tl \tl_new:N \l__pgfgo_sgfdiag_result_format_tl \tl_new:N \l__pgfgo_sgfdiag_black_tl \tl_new:N \l__pgfgo_sgfdiag_white_tl %LAS VARIANTES QUE SE DIBUJAN: LAS COMENTADAS O TODAS (HASTA LA PROFUNDIDAD depth) Y LAS DE LA LISTA. \bool_new:N \l__pgfgo_sgfdiag_var_commented_bool \bool_new:N \l__pgfgo_sgfdiag_var_all_bool \int_new:N \l__pgfgo_sgfdiag_var_depth_int \bool_new:N \l__pgfgo_sgfdiag_marks_bool \int_new:N \l__pgfgo_sgfdiag_var_from_int \seq_new:N \l__pgfgo_sgfdiag_var_paths_seq \tl_new:N \l__pgfgo_sgfdiag_var_title_tl %LA PARTIDA: EL ARCHIVO, SU TAMANO, SU komi, SUS JUGADAS Y LA ULTIMA QUE SE DIBUJA. \tl_new:N \l__pgfgo_sgfdiag_file_tl \tl_new:N \l__pgfgo_sgfdiag_board_tl \tl_new:N \l__pgfgo_sgfdiag_komi_tl \int_new:N \l__pgfgo_sgfdiag_total_int \int_new:N \l__pgfgo_sgfdiag_last_int %LA ALINEACION #2 DE LOS COMENTARIOS (left, right, center O justify), COMO CODIGO EN #1. \msg_new:nnn {pgfgo} {comments-align} {Unknown~comments~align~'#1':~use~left,~right,~center~or~justify.} \cs_new_protected:Npn \__pgfgo_sgfdiag_comment_align:Nn #1#2 { \str_case:nnF {#2} { {left} {\tl_set:Nn #1 {\raggedright}} {right} {\tl_set:Nn #1 {\raggedleft}} {center} {\tl_set:Nn #1 {\centering}} {justify} {\tl_clear:N #1} }{ \msg_error:nnn {pgfgo} {comments-align} {#2} } } \keys_define:nn {pgfgo / sgf~diagrams} { %LOS DIAGRAMAS SON LOS MISMOS (Y CON EL MISMO NUMERO) QUE SIN from: SOLO SE DIBUJAN LOS QUE TIENEN JUGADAS %DESDE from, Y EL PRIMERO EMPIEZA EN from. from .int_set:N = \l__pgfgo_sgfdiag_from_int, from .initial:n = {1}, %last (-1): LA ULTIMA JUGADA. to .code:n = {\__pgfgo_sgf_set_to:Nnn \l__pgfgo_sgfdiag_to_int {-1} {#1}}, to .initial:n = {last}, %SIN numbers, LAS JUGADAS DE CADA DIAGRAMA NO LLEVAN NUMERO. last~mark: COMO EN \sgf, EN CADA DIAGRAMA. numbers .bool_set:N = \l__pgfgo_sgfdiag_numbers_bool, numbers .default:n = {true}, numbers .initial:n = {true}, %marks: COMO EN \sgf, EN CADA DIAGRAMA. marks .bool_set:N = \l__pgfgo_sgfdiag_marks_bool, marks .default:n = {true}, marks .initial:n = {true}, last~mark .code:n = { \str_if_eq:nnTF {#1} {false} {\tl_clear:N \l__pgfgo_sgfdiag_last_tl} {\tl_set:Nn \l__pgfgo_sgfdiag_last_tl {#1}} }, last~mark .initial:n = {false}, goban .tl_set:N = \l__pgfgo_sgfdiag_goban_tl, %CADA DIAGRAMA ES UN goban CON NOMBRE: EL DE name Y EL NUMERO DE SU EPIGRAFE (tablero1, tablero3a). name .tl_set:N = \l__pgfgo_sgfdiag_name_tl, variation .tl_set:N = \l__pgfgo_sgfdiag_variation_tl, notes .bool_set:N = \l__pgfgo_sgfdiag_notes_bool, notes .default:n = {true}, notes .initial:n = {true}, title .tl_set:N = \l__pgfgo_sgfdiag_title_tl, title .initial:n = {\pgfgo_text:n {diagram}}, caption .code:n = {\keys_set:nn {pgfgo / sgf~diagrams / caption} {#1}}, %LOS COMENTARIOS DE LAS JUGADAS DEL DIAGRAMA, DEBAJO DE SUS NOTAS. comments .code:n = {\keys_set:nn {pgfgo / sgf~diagrams / comments} {#1}}, comments .default:n = {true}, game .code:n = {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {#1}}, view .bool_set:N = \l__pgfgo_sgfdiag_view_bool, view .default:n = {true}, view .initial:n = {true}, %auto: LOS TABLEROS MUESTRAN SOLO LA PARTE QUE USA LA PARTIDA (SI NO HAY VISTA). partial .code:n = {\__pgfgo_sgf_partial:NNn \l__pgfgo_sgfdiag_partial_bool \l__pgfgo_sgfdiag_partial_tl {#1}}, partial .initial:n = {false}, %SI EL ARCHIVO TIENE FIGURAS (FG), CADA FIGURA ES UN DIAGRAMA (CON SU NOMBRE COMO EPIGRAFE). figures .bool_set:N = \l__pgfgo_sgfdiag_figures_bool, figures .default:n = {true}, figures .initial:n = {true}, annotations .bool_set:N = \l__pgfgo_sgfdiag_annotations_bool, annotations .default:n = {true}, chat .bool_set:N = \l__pgfgo_sgfdiag_chat_bool, chat .default:n = {true}, %EL RESULTADO Y EL PUNTAJE DEBAJO DEL ULTIMO DIAGRAMA. result .code:n = {\keys_set:nn {pgfgo / sgf~diagrams / result} {#1}}, result .default:n = {true}, black~name .tl_set:N = \l__pgfgo_sgfdiag_black_tl, black~name .initial:n = {\pgfgo_text:n {black}}, white~name .tl_set:N = \l__pgfgo_sgfdiag_white_tl, white~name .initial:n = {\pgfgo_text:n {white}}, %LAS VARIANTES COMO DIAGRAMAS, DESPUES DEL DIAGRAMA DONDE NACEN (VER /pgfgo/sgf diagrams/variations). variations .code:n = {\keys_set:nn {pgfgo / sgf~diagrams / variations} {#1}}, variations .default:n = {commented}, variation~title .tl_set:N = \l__pgfgo_sgfdiag_var_title_tl, variation~title .initial:n = {\pgfgo_text:n {variation~at}}, %OPCIONES DE /pgfgo/layout SOLO PARA \sgfdiagrams (SE SUMAN A LAS DE TODO EL DOCUMENTO). layout .code:n = {\tl_put_right:Nn \l__pgfgo_sgfdiag_layout_tl {, #1}}, } %{5, 10, 3}: DIAGRAMAS DE 5, 10, 3, 3, 3... JUGADAS. CON restart, DESDE EL SEGUNDO, CADA DIAGRAMA NUMERA %DESDE restart/from. \__pgfgo_sgf_numbering_keys:nnn {pgfgo / sgf~diagrams} {sgfdiag} {50} \keys_define:nn {pgfgo / sgf~diagrams / caption} { font .tl_set:N = \l__pgfgo_sgfdiag_font_tl, font .initial:n = {\small}, %UN EPIGRAFE MAS ANCHO QUE SU TABLERO (CON columns = auto) SE CORTA A ESTE ANCHO, SI EL TABLERO ES MAS ANGOSTO. min~width .tl_set:N = \l__pgfgo_sgfdiag_caption_min_tl, min~width .initial:n = {8em}, } %font: LA DE LOS COMENTARIOS (VACIA: LA DEL EPIGRAFE). align: left, right, center O justify. root: EL %COMENTARIO DE LA RAIZ (JUGADA 0), SIN NUMERO, ANTES DE LOS DEL DIAGRAMA QUE EMPIEZA EN LA JUGADA 1. %number: LO QUE VA DELANTE DE CADA COMENTARIO (#1: EL NUMERO). separator: LO QUE VA ENTRE LOS COMENTARIOS. %position: below, O right O left: AL COSTADO DEL DIAGRAMA, DE ANCHO width Y A sep DE EL (width = auto: LO %QUE QUEDA DE LA CELDA O DE LA LINEA), O after: TODOS JUNTOS DESPUES DE LOS DIAGRAMAS. height: DEBAJO O AL %COSTADO, LO QUE PASA ESA ALTURA VA DESPUES DE LOS DIAGRAMAS (none: NADA). \keys_define:nn {pgfgo / sgf~diagrams / comments} { true .code:n = {\bool_set_true:N \l__pgfgo_sgfdiag_comments_bool}, false .code:n = {\bool_set_false:N \l__pgfgo_sgfdiag_comments_bool}, font .tl_set:N = \l__pgfgo_sgfdiag_comment_font_tl, align .code:n = {\__pgfgo_sgfdiag_comment_align:Nn \l__pgfgo_sgfdiag_comment_align_tl {#1}}, align .initial:n = {left}, root .bool_set:N = \l__pgfgo_sgfdiag_root_bool, root .default:n = {true}, number .code:n = {\cs_set:Npn \__pgfgo_sgfdiag_comment_number:n ##1 {#1}}, number .initial:n = {\textbf{#1}:~}, separator .tl_set:N = \l__pgfgo_sgfdiag_comment_separator_tl, separator .initial:n = {\par}, position .choices:nn = {below, right, left, after} {\tl_set_eq:NN \l__pgfgo_sgfdiag_comment_position_tl \l_keys_choice_tl}, height .tl_set:N = \l__pgfgo_sgfdiag_comment_height_tl, height .initial:n = {none}, position .initial:n = {below}, width .tl_set:N = \l__pgfgo_sgfdiag_comment_width_tl, width .initial:n = {auto}, sep .dim_set:N = \l__pgfgo_sgfdiag_comment_sep_dim, sep .initial:n = {1em}, } %none: NINGUNA. commented: LAS QUE TIENEN COMENTARIOS. all: TODAS. depth: HASTA QUE PROFUNDIDAD; from: LAS QUE %NACEN EN ESA JUGADA O DESPUES (commented Y all). OTRA COSA ES EL CAMINO DE UNA VARIANTE (2, 2.3.1, {R16 P17}), %QUE SE DIBUJA SIEMPRE. \keys_define:nn {pgfgo / sgf~diagrams / variations} { none .code:n = { \bool_set_false:N \l__pgfgo_sgfdiag_var_commented_bool \bool_set_false:N \l__pgfgo_sgfdiag_var_all_bool \seq_clear:N \l__pgfgo_sgfdiag_var_paths_seq }, commented .code:n = {\bool_set_true:N \l__pgfgo_sgfdiag_var_commented_bool}, all .code:n = {\bool_set_true:N \l__pgfgo_sgfdiag_var_all_bool}, depth .int_set:N = \l__pgfgo_sgfdiag_var_depth_int, depth .initial:n = {1}, from .int_set:N = \l__pgfgo_sgfdiag_var_from_int, from .initial:n = {1}, unknown .code:n = { \seq_put_right:NV \l__pgfgo_sgfdiag_var_paths_seq \l_keys_key_str }, } \keys_define:nn {pgfgo / sgf~diagrams / result} { true .code:n = {\bool_set_true:N \l__pgfgo_sgfdiag_result_bool}, false .code:n = {\bool_set_false:N \l__pgfgo_sgfdiag_result_bool}, title .tl_set:N = \l__pgfgo_sgfdiag_result_title_tl, title .initial:n = {\pgfgo_text:n {result}}, %text: EL RESULTADO EN PALABRAS ("Black wins by resignation"); raw: COMO ESTA EN EL ARCHIVO ("B+R"). format .choices:nn = {text, raw} {\tl_set_eq:NN \l__pgfgo_sgfdiag_result_format_tl \l_keys_choice_tl}, format .initial:n = {text}, } \bool_set_true:N \l__pgfgo_sgfdiag_result_bool \keys_define:nn {pgfgo} { sgf~diagrams .code:n = {\keys_set:nn {pgfgo / sgf~diagrams} {#1}} } %UN DIAGRAMA (DE \sgfdiagrams O DE \sgfproblem) SE ARMA EN \l__pgfgo_sgfdiag_cell_box: EL goban CON LAS %JUGADAS #1 A #2 (NUMERADAS DESDE #1) DE LA LINEA \l__pgfgo_sgfdiag_variation_tl, Y DEBAJO EL EPIGRAFE #3 Y %LO QUE DIGA #4 (SE EJECUTA DESPUES DEL goban). LAS OPCIONES DEL goban QUE ELIGEN LA PARTE VISIBLE ESTAN EN %\l__pgfgo_sgfdiag_window_tl, Y restart EN \l__pgfgo_sgfdiag_sgf_restart_tl. EN LA GRILLA (VER pgf-go-layout.sty) %EL DIAGRAMA TIENE EL ANCHO DE LA CELDA, Y CON fit TODOS LOS TABLEROS USAN LA ESCALA QUE LLENA LA CELDA CON %EL PRIMERO (\l__pgfgo_sgfdiag_scale_tl). \l__pgfgo_sgfdiag_align_tl ES LA ALINEACION DE LO QUE VA DEBAJO. \tl_new:N \l__pgfgo_sgfdiag_window_tl \tl_new:N \l__pgfgo_sgfdiag_sgf_restart_tl \tl_new:N \l__pgfgo_sgfdiag_scale_tl \tl_new:N \l__pgfgo_sgfdiag_align_tl \dim_new:N \l__pgfgo_sgfdiag_width_dim \box_new:N \l__pgfgo_sgfdiag_box \box_new:N \l__pgfgo_sgfdiag_caption_box \box_new:N \l__pgfgo_sgfdiag_cell_box \box_new:N \l__pgfgo_sgfdiag_below_box \box_new:N \g__pgfgo_sgfdiag_fit_box %EMPIEZA UNA SERIE DE DIAGRAMAS DEL ARCHIVO #2, CON LAS OPCIONES DE layout #1. \cs_new_protected:Npn \__pgfgo_sgfdiag_begin:Nn #1#2 { \box_gclear:N \g__pgfgo_sgfdiag_after_box \dim_set_eq:NN \l__pgfgo_sgfdiag_after_dim \linewidth \pgfgo_layout_begin:V #1 \tl_clear:N \l__pgfgo_sgfdiag_scale_tl \tl_set:Nn \l__pgfgo_sgfdiag_file_tl {#2} } %CON LOS COMENTARIOS AL COSTADO, EL TABLERO Y LO QUE VA DEBAJO OCUPAN UNA COLUMNA MAS ANGOSTA: EN LA GRILLA, %EL TABLERO (CON fit Y width = auto, LA MITAD DE LA CELDA), O LA CELDA MENOS width. \dim_new:N \l__pgfgo_sgfdiag_total_dim \bool_new:N \l__pgfgo_sgfdiag_side_bool \tl_new:N \l__pgfgo_sgfdiag_caption_tl \tl_new:N \l__pgfgo_sgfdiag_caption_code_tl \cs_new_protected:Npn \__pgfgo_sgfdiag_draw:nnnn #1#2#3#4 { \box_clear:N \l__pgfgo_sgfdiag_below_box \tl_set:Nn \l__pgfgo_sgfdiag_caption_tl {#3} \bool_set:Nn \l__pgfgo_sgfdiag_side_bool { \l__pgfgo_sgfdiag_comments_bool && ( \str_if_eq_p:Vn \l__pgfgo_sgfdiag_comment_position_tl {right} || \str_if_eq_p:Vn \l__pgfgo_sgfdiag_comment_position_tl {left} ) } \bool_lazy_and:nnT {\l__pgfgo_sgfdiag_side_bool} {\pgfgo_layout_if_grid_p:} { \dim_set_eq:NN \l__pgfgo_sgfdiag_total_dim \l_pgfgo_layout_cell_dim \str_if_eq:VnTF \l__pgfgo_sgfdiag_comment_width_tl {auto} { \pgfgo_layout_if_fit:T {\dim_set:Nn \l_pgfgo_layout_cell_dim {(\l__pgfgo_sgfdiag_total_dim - \l__pgfgo_sgfdiag_comment_sep_dim) / 2}} } { \dim_set:Nn \l_pgfgo_layout_cell_dim {\l__pgfgo_sgfdiag_total_dim - \l__pgfgo_sgfdiag_comment_sep_dim - (\l__pgfgo_sgfdiag_comment_width_tl)} } } \pgfgo_layout_if_fit:T { \tl_if_empty:NT \l__pgfgo_sgfdiag_scale_tl { \pgfgo_layout_fit:nN { \tl_set:Nn \l__pgfgo_sgfdiag_scale_tl {scale = ##1} \__pgfgo_sgfdiag_board:nn {#1} {#2} } \l__pgfgo_sgfdiag_box \tl_set:Ne \l__pgfgo_sgfdiag_scale_tl {scale = \l_pgfgo_layout_scale_tl} } } \__pgfgo_sgfdiag_board:nn {#1} {#2} %UN TABLERO MAS ANCHO QUE EL PRIMERO (OTRO PROBLEMA, OTRA VISTA) NO ENTRA CON ESA ESCALA: SOLO ESE SE ACHICA. \pgfgo_layout_if_fit:T { \dim_compare:nNnT {\box_wd:N \l__pgfgo_sgfdiag_box} > {\l_pgfgo_layout_cell_dim + 0.1pt} { \group_begin: \pgfgo_layout_fit:nN { \tl_set:Nn \l__pgfgo_sgfdiag_scale_tl {scale = ##1} \__pgfgo_sgfdiag_board:nn {#1} {#2} } \l__pgfgo_sgfdiag_box \tl_set:Ne \l__pgfgo_sgfdiag_scale_tl {scale = \l_pgfgo_layout_scale_tl} \__pgfgo_sgfdiag_board:nn {#1} {#2} \box_gset_eq:NN \g__pgfgo_sgfdiag_fit_box \l__pgfgo_sgfdiag_box \group_end: \box_set_eq:NN \l__pgfgo_sgfdiag_box \g__pgfgo_sgfdiag_fit_box \box_gclear:N \g__pgfgo_sgfdiag_fit_box } } \bool_lazy_and:nnT {\l__pgfgo_sgfdiag_side_bool} {\pgfgo_layout_if_grid_p:} { \str_if_eq:VnT \l__pgfgo_sgfdiag_comment_width_tl {auto} {\pgfgo_layout_if_fit:F {\dim_set:Nn \l_pgfgo_layout_cell_dim {\box_wd:N \l__pgfgo_sgfdiag_box}}} } \box_gclear:N \g__pgfgo_sgfdiag_side_box \pgfgo_layout_if_cells:TF { \__pgfgo_sgfdiag_side_width:n {\l_pgfgo_layout_cell_dim} \tl_set:Nn \l__pgfgo_sgfdiag_align_tl {\pgfgo_layout_par_align:} \dim_set_eq:NN \l__pgfgo_sgfdiag_width_dim \l_pgfgo_layout_cell_dim \bool_lazy_and:nnTF {! \l__pgfgo_sgfdiag_side_bool} {\pgfgo_layout_if_below_p:} { %LO DE ABAJO VA APARTE (layout/align captions), CON EL MISMO ESPACIO QUE DEBAJO DEL TABLERO. \hbox_set:Nn \l__pgfgo_sgfdiag_cell_box {\pgfgo_layout_place:n {\box_use:N \l__pgfgo_sgfdiag_box}} \vbox_set_top:Nn \l__pgfgo_sgfdiag_below_box { \tex_prevdepth:D \box_dp:N \l__pgfgo_sgfdiag_cell_box \skip_vertical:n {0.3em} \__pgfgo_sgfdiag_below:nn {\pgfgo_layout_par_align:} {#3} #4 } } { \vbox_set_top:Nn \l__pgfgo_sgfdiag_cell_box { \pgfgo_layout_place:n {\box_use:N \l__pgfgo_sgfdiag_box} \skip_vertical:n {0.3em} \__pgfgo_sgfdiag_below:nn {\pgfgo_layout_par_align:} {#3} #4 } } } { \tl_set:Nn \l__pgfgo_sgfdiag_align_tl {\centering} %EL DIAGRAMA TIENE EL ANCHO DEL TABLERO. UN EPIGRAFE MAS ANCHO SE CORTA EN LINEAS (COMO EN LA GRILLA), %PERO EL DIAGRAMA NO ES MAS ANGOSTO QUE SU PALABRA MAS LARGA NI QUE caption/min width (SI ENTRA ASI EN %UNA LINEA, NO SE CORTA). EL EPIGRAFE CORTADO ES UN PARRAFO DE LA CELDA (NO UNA CAJA): SUS LINEAS Y LO %QUE SIGUE LLEVAN EL INTERLINEADO DE SIEMPRE. \hbox_set:Nn \l__pgfgo_sgfdiag_caption_box {\l__pgfgo_sgfdiag_font_tl #3} \dim_set:Nn \l__pgfgo_sgfdiag_width_dim {\box_wd:N \l__pgfgo_sgfdiag_box} \dim_compare:nNnT {\box_wd:N \l__pgfgo_sgfdiag_caption_box} > {\l__pgfgo_sgfdiag_width_dim} { \__pgfgo_sgfdiag_widest_word:n {#3} \__pgfgo_sgfdiag_caption_min: \dim_set:Nn \l__pgfgo_sgfdiag_width_dim { \dim_max:nn {\l__pgfgo_sgfdiag_width_dim} {\dim_max:nn {\g__pgfgo_sgfdiag_word_dim} {\g__pgfgo_sgfdiag_caption_min_dim}} } } \dim_compare:nNnTF {\box_wd:N \l__pgfgo_sgfdiag_caption_box} > {\l__pgfgo_sgfdiag_width_dim} { \box_clear:N \l__pgfgo_sgfdiag_caption_box \tl_set:Nn \l__pgfgo_sgfdiag_caption_code_tl { \group_begin: \__pgfgo_sgfdiag_par_setup:N \l__pgfgo_sgfdiag_width_dim \centering \l__pgfgo_sgfdiag_font_tl #3 \par \group_end: } } { \tl_set:Nn \l__pgfgo_sgfdiag_caption_code_tl { \hbox_to_wd:nn {\l__pgfgo_sgfdiag_width_dim} {\hfil \box_use:N \l__pgfgo_sgfdiag_caption_box \hfil} } } \__pgfgo_sgfdiag_side_width:n {\l__pgfgo_sgfdiag_width_dim} \vbox_set_top:Nn \l__pgfgo_sgfdiag_cell_box { \hbox_to_wd:nn {\l__pgfgo_sgfdiag_width_dim} {\hfil \box_use:N \l__pgfgo_sgfdiag_box \hfil} \skip_vertical:n {0.3em} \l__pgfgo_sgfdiag_caption_code_tl #4 } } \bool_if:NT \l__pgfgo_sgfdiag_side_bool {\__pgfgo_sgfdiag_side:} %LA CELDA VUELVE A SU ANCHO (LA USAN LA DISPOSICION Y EL DIAGRAMA SIGUIENTE). \bool_lazy_and:nnT {\l__pgfgo_sgfdiag_side_bool} {\pgfgo_layout_if_grid_p:} {\dim_set_eq:NN \l_pgfgo_layout_cell_dim \l__pgfgo_sgfdiag_total_dim} } %EL ANCHO DE LA PALABRA MAS LARGA DEL EPIGRAFE #1 (EN \g__pgfgo_sgfdiag_word_dim): CON \hsize = 0pt CADA %PALABRA VA EN SU LINEA (SIN GUIONES); SE SACAN LAS LINEAS DE ABAJO HACIA ARRIBA Y SE MIDE CADA UNA. \dim_new:N \g__pgfgo_sgfdiag_word_dim \box_new:N \l__pgfgo_sgfdiag_words_box \cs_new_protected:Npn \__pgfgo_sgfdiag_widest_word:n #1 { \dim_gzero:N \g__pgfgo_sgfdiag_word_dim \vbox_set:Nn \l__pgfgo_sgfdiag_words_box { \dim_set_eq:NN \hsize \c_zero_dim \int_set:Nn \hyphenpenalty {10000} \int_set:Nn \exhyphenpenalty {10000} \dim_set:Nn \hfuzz {\c_max_dim} \int_set:Nn \hbadness {10000} \noindent \l__pgfgo_sgfdiag_font_tl #1 \par \__pgfgo_sgfdiag_widest_word_loop: } } %EL ANCHO MINIMO DEL EPIGRAFE CORTADO (EN \g__pgfgo_sgfdiag_caption_min_dim): min width EN LA FUENTE DEL %EPIGRAFE, PERO NO MAS QUE EL EPIGRAFE EN UNA LINEA (\l__pgfgo_sgfdiag_caption_box). \dim_new:N \g__pgfgo_sgfdiag_caption_min_dim \cs_new_protected:Npn \__pgfgo_sgfdiag_caption_min: { \group_begin: \l__pgfgo_sgfdiag_font_tl \dim_gset:Nn \g__pgfgo_sgfdiag_caption_min_dim {\dim_min:nn {\l__pgfgo_sgfdiag_caption_min_tl} {\box_wd:N \l__pgfgo_sgfdiag_caption_box}} \group_end: } \cs_new_protected:Npn \__pgfgo_sgfdiag_widest_word_loop: { \tex_unskip:D \tex_unpenalty:D \tex_unskip:D \box_set_to_last:N \l_tmpa_box \box_if_empty:NF \l_tmpa_box { \hbox_set:Nn \l_tmpa_box {\hbox_unpack:N \l_tmpa_box} \dim_gset:Nn \g__pgfgo_sgfdiag_word_dim {\dim_max:nn {\g__pgfgo_sgfdiag_word_dim} {\box_wd:N \l_tmpa_box}} \__pgfgo_sgfdiag_widest_word_loop: } } %EL ANCHO DE LOS COMENTARIOS AL COSTADO DE UNA COLUMNA DE ANCHO #1: width, O CON auto LO QUE QUEDA DE LA %CELDA O DE LA LINEA. AL MENOS 3em. \cs_new_protected:Npn \__pgfgo_sgfdiag_side_width:n #1 { \bool_if:NT \l__pgfgo_sgfdiag_side_bool { \str_if_eq:VnTF \l__pgfgo_sgfdiag_comment_width_tl {auto} { \dim_set:Nn \l__pgfgo_sgfdiag_side_dim { \pgfgo_layout_if_grid:TF {\l__pgfgo_sgfdiag_total_dim} {\linewidth} - #1 - \l__pgfgo_sgfdiag_comment_sep_dim } } {\dim_set:Nn \l__pgfgo_sgfdiag_side_dim {\l__pgfgo_sgfdiag_comment_width_tl}} \dim_compare:nNnT {\l__pgfgo_sgfdiag_side_dim} < {3em} {\dim_set:Nn \l__pgfgo_sgfdiag_side_dim {3em}} } } %PONE LOS COMENTARIOS AL COSTADO DE LA CELDA, CON SU PRIMERA LINEA ARRIBA, A LA ALTURA DEL TABLERO. LA CELDA %CONSERVA SU LINEA DE BASE; EN LA GRILLA, OCUPA EL ANCHO DE LA CELDA ENTERA. \cs_new_protected:Npn \__pgfgo_sgfdiag_side: { \box_if_empty:NF \g__pgfgo_sgfdiag_side_box { \hbox_set:Nn \l_tmpb_box { \box_move_up:nn {\box_ht:N \l__pgfgo_sgfdiag_cell_box - \box_ht:N \g__pgfgo_sgfdiag_side_box} {\box_use:N \g__pgfgo_sgfdiag_side_box} } \hbox_set:Nn \l__pgfgo_sgfdiag_cell_box { \str_if_eq:VnTF \l__pgfgo_sgfdiag_comment_position_tl {right} {\box_use:N \l__pgfgo_sgfdiag_cell_box \skip_horizontal:N \l__pgfgo_sgfdiag_comment_sep_dim \box_use:N \l_tmpb_box} {\box_use:N \l_tmpb_box \skip_horizontal:N \l__pgfgo_sgfdiag_comment_sep_dim \box_use:N \l__pgfgo_sgfdiag_cell_box} } \pgfgo_layout_if_cells:T { \hbox_set_to_wd:Nnn \l__pgfgo_sgfdiag_cell_box {\l__pgfgo_sgfdiag_total_dim} {\box_use:N \l__pgfgo_sgfdiag_cell_box \hfil} } } } %EL MISMO DIAGRAMA, PUESTO EN LA DISPOSICION. \cs_new_protected:Npn \__pgfgo_sgfdiag_add:nnnn #1#2#3#4 { \__pgfgo_sgfdiag_draw:nnnn {#1} {#2} {#3} {#4} \pgfgo_layout_add:NN \l__pgfgo_sgfdiag_cell_box \l__pgfgo_sgfdiag_below_box } %UN DIAGRAMA SOLO EN SU FILA: LO DE ABAJO, SI VINO APARTE, VUELVE A LA CELDA. \cs_new_protected:Npn \__pgfgo_sgfdiag_join: { \box_if_empty:NF \l__pgfgo_sgfdiag_below_box { \vbox_set_top:Nn \l__pgfgo_sgfdiag_cell_box { \box_use:N \l__pgfgo_sgfdiag_cell_box \nointerlineskip \box_use_drop:N \l__pgfgo_sgfdiag_below_box } } } %EL goban DEL DIAGRAMA (JUGADAS #1 A #2) EN \l__pgfgo_sgfdiag_box. CON name, SE LLAMA name SEGUIDO DE %\l__pgfgo_sgfdiag_suffix_tl. \tl_new:N \l__pgfgo_sgfdiag_suffix_tl \cs_new_protected:Npn \__pgfgo_sgfdiag_board:nn #1#2 { \__pgfgo_sgf_shown_clear: \hbox_set:Nn \l__pgfgo_sgfdiag_box { \pgfgo_layout_restore_goban: %LA ESCALA DE fit NO CAMBIA EL GROSOR DE LAS LINEAS (VER pgf-go-goban.sty). \tl_if_empty:NF \l__pgfgo_sgfdiag_scale_tl {\bool_set_true:N \l_pgfgo_goban_fit_bool} \use:e { \exp_not:N \begin{goban} [ \l__pgfgo_sgfdiag_board_tl, captures, notes, \exp_not:V \l__pgfgo_sgfdiag_window_tl, \exp_not:V \l__pgfgo_sgfdiag_goban_tl, \exp_not:V \l__pgfgo_sgfdiag_scale_tl \tl_if_empty:NF \l__pgfgo_sgfdiag_name_tl {, name = {\exp_not:V \l__pgfgo_sgfdiag_name_tl \exp_not:V \l__pgfgo_sgfdiag_suffix_tl}} ] } %COMO EN LOS LIBROS, LAS CAPTURAS DEL TRAMO NUMERADO NO SE QUITAN (SE VEN EN EL DIAGRAMA SIGUIENTE). \bool_set_true:N \l__pgfgo_sgf_keep_numbered_bool \tl_set_eq:NN \l__pgfgo_sgf_first_tl \l__pgfgo_sgfdiag_first_tl \__pgfgo_sgf_extent_add: \use:e { \exp_not:N \pgfgo_sgf:nn { from = \int_eval:n {#1}, to = \int_eval:n {#2}, variation = {\exp_not:V \l__pgfgo_sgfdiag_variation_tl}, restart = {\exp_not:V \l__pgfgo_sgfdiag_sgf_restart_tl}, numbers = \bool_if:NTF \l__pgfgo_sgfdiag_numbers_bool {true} {false}, marks = \bool_if:NTF \l__pgfgo_sgfdiag_marks_bool {true} {false}, last~mark = {\tl_if_empty:NTF \l__pgfgo_sgfdiag_last_tl {false} {\exp_not:V \l__pgfgo_sgfdiag_last_tl}} } {\exp_not:V \l__pgfgo_sgfdiag_file_tl} } \end{goban} } } %DEBAJO DEL EPIGRAFE: UN PARRAFO DEL ANCHO DEL DIAGRAMA (#1: \centering, \raggedright, ETC.). \cs_new_protected:Npn \__pgfgo_sgfdiag_below:nn #1#2 { \hbox:n {\parbox[t]{\l__pgfgo_sgfdiag_width_dim} {#1 \l__pgfgo_sgfdiag_font_tl #2}} } %LOS COMENTARIOS #1 CON SU ALINEACION Y SU FUENTE (SI NO TIENEN, LA DEL EPIGRAFE): DEBAJO DEL EPIGRAFE, O AL %COSTADO, EN \g__pgfgo_sgfdiag_side_box (DE ANCHO \l__pgfgo_sgfdiag_side_dim), QUE PONE \__pgfgo_sgfdiag_side:. \box_new:N \g__pgfgo_sgfdiag_side_box \dim_new:N \l__pgfgo_sgfdiag_side_dim %LOS COMENTARIOS SE ARMAN EN UNA CAJA VERTICAL DE PARRAFOS (COMO LOS DE UN \parbox), QUE SE PUEDE CORTAR: %CON height, LO QUE NO ENTRA VA A \g__pgfgo_sgfdiag_after_box, QUE SE ESCRIBE DESPUES DE LOS DIAGRAMAS. \box_new:N \l__pgfgo_sgfdiag_comments_box \box_new:N \l__pgfgo_sgfdiag_top_box \box_new:N \g__pgfgo_sgfdiag_after_box \dim_new:N \l__pgfgo_sgfdiag_after_dim \cs_new_protected:Npn \__pgfgo_sgfdiag_comments_below:n #1 { \str_case:VnF \l__pgfgo_sgfdiag_comment_position_tl { {after} { \__pgfgo_sgfdiag_comments_set:Nn \l__pgfgo_sgfdiag_after_dim {#1} \__pgfgo_sgfdiag_after_add: } {below} { \__pgfgo_sgfdiag_comments_set:Nn \l__pgfgo_sgfdiag_width_dim {#1} \__pgfgo_sgfdiag_comments_cut: \__pgfgo_sgfdiag_comments_use: } }{ \__pgfgo_sgfdiag_comments_set:Nn \l__pgfgo_sgfdiag_side_dim {#1} \__pgfgo_sgfdiag_comments_cut: \hbox_gset:Nn \g__pgfgo_sgfdiag_side_box {\__pgfgo_sgfdiag_comments_use:} } } %LA CAJA DE LOS COMENTARIOS CON LA LINEA DE BASE EN SU PRIMER RENGLON (COMO UN \parbox[t]). \cs_new_protected:Npn \__pgfgo_sgfdiag_comments_use: { \vbox_top:n {\vbox_unpack:N \l__pgfgo_sgfdiag_comments_box} } %LOS COMENTARIOS #2 EN \l__pgfgo_sgfdiag_comments_box, DE ANCHO #1, CON SU ALINEACION Y SU FUENTE. \cs_new_protected:Npn \__pgfgo_sgfdiag_comments_set:Nn #1#2 { \vbox_set:Nn \l__pgfgo_sgfdiag_comments_box { \__pgfgo_sgfdiag_par_setup:N #1 \l__pgfgo_sgfdiag_comment_align_tl \__pgfgo_sgfdiag_comment_font: #2 \par } } \cs_new_protected:Npn \__pgfgo_sgfdiag_par_setup:N #1 { \use:c {@parboxrestore} \dim_set_eq:NN \hsize #1 \dim_set_eq:NN \linewidth #1 } \cs_new_protected:Npn \__pgfgo_sgfdiag_comment_font: { \tl_if_empty:NTF \l__pgfgo_sgfdiag_comment_font_tl {\l__pgfgo_sgfdiag_font_tl} {\l__pgfgo_sgfdiag_comment_font_tl} } %CON height: SI LA CAJA ES MAS ALTA, QUEDA LO QUE ENTRA Y EL RESTO VA DESPUES DE LOS DIAGRAMAS. \cs_new_protected:Npn \__pgfgo_sgfdiag_comments_cut: { \str_if_eq:VnF \l__pgfgo_sgfdiag_comment_height_tl {none} { \dim_compare:nNnT {\box_ht:N \l__pgfgo_sgfdiag_comments_box + \box_dp:N \l__pgfgo_sgfdiag_comments_box} > {\l__pgfgo_sgfdiag_comment_height_tl} { \vbox_set_split_to_ht:NNn \l__pgfgo_sgfdiag_top_box \l__pgfgo_sgfdiag_comments_box {\l__pgfgo_sgfdiag_comment_height_tl} \__pgfgo_sgfdiag_after_add: \box_set_eq:NN \l__pgfgo_sgfdiag_comments_box \l__pgfgo_sgfdiag_top_box } } } %AGREGA \l__pgfgo_sgfdiag_comments_box (SI NO ESTA VACIA) A LOS COMENTARIOS DE DESPUES, CON EL EPIGRAFE DEL %DIAGRAMA COMO ENCABEZADO. \cs_new_protected:Npn \__pgfgo_sgfdiag_after_add: { \dim_compare:nNnT {\box_ht:N \l__pgfgo_sgfdiag_comments_box + \box_dp:N \l__pgfgo_sgfdiag_comments_box} > {0pt} { \vbox_gset:Nn \g__pgfgo_sgfdiag_after_box { \vbox_unpack:N \g__pgfgo_sgfdiag_after_box \group_begin: \__pgfgo_sgfdiag_par_setup:N \l__pgfgo_sgfdiag_after_dim \__pgfgo_sgfdiag_comment_font: \bfseries \l__pgfgo_sgfdiag_caption_tl \par \group_end: \vbox_unpack:N \l__pgfgo_sgfdiag_comments_box \skip_vertical:N \smallskipamount } } } %DESPUES DE LOS DIAGRAMAS: LOS COMENTARIOS DE after O LOS QUE NO ENTRARON (SE PUEDEN CORTAR ENTRE PAGINAS). \cs_new_protected:Npn \__pgfgo_sgfdiag_after_flush: { \box_if_empty:NF \g__pgfgo_sgfdiag_after_box { \par \skip_vertical:N \medskipamount \vbox_unpack:N \g__pgfgo_sgfdiag_after_box \box_gclear:N \g__pgfgo_sgfdiag_after_box } } %EL NUMERO QUE SE MOSTRO DE LA JUGADA #1 (EL DE LA PARTIDA SI NO SE DIBUJO). \cs_new:Npn \__pgfgo_sgfdiag_shown:n #1 { \cs_if_exist:cTF {__pgfgo_sgf_shown_ #1 :} {\use:c {__pgfgo_sgf_shown_ #1 :}} {#1} } %separator ANTES DE CADA COMENTARIO MENOS EL PRIMERO. \cs_new_protected:Npn \__pgfgo_sgfdiag_comment_separator: { \bool_if:NTF \l__pgfgo_sgfdiag_comment_first_bool {\bool_set_false:N \l__pgfgo_sgfdiag_comment_first_bool} {\l__pgfgo_sgfdiag_comment_separator_tl} } %LAS NOTAS "N at M" Y LOS COMENTARIOS DE LAS JUGADAS #1 A #2 (CON root, SI #1 ES 1, ANTES EL DE LA RAIZ). \cs_new_protected:Npn \__pgfgo_sgfdiag_notes:nn #1#2 { \bool_if:nT {\l__pgfgo_sgfdiag_notes_bool && ! \seq_if_empty_p:N \g_pgfgo_move_notes_seq} {\__pgfgo_sgfdiag_below:nn {\l__pgfgo_sgfdiag_align_tl} {\pgfgomovenotes}} \bool_if:NT \l__pgfgo_sgfdiag_comments_bool { \__pgfgo_sgfdiag_comments_below:n { \bool_set_true:N \l__pgfgo_sgfdiag_comment_first_bool \bool_lazy_and:nnT {\l__pgfgo_sgfdiag_root_bool} {\int_compare_p:nNn {#1} = {1}} {\__pgfgo_sgf_if_comment:nT {0} {\__pgfgo_sgfdiag_comment_separator: \__pgfgo_sgf_comment_use:}} \int_step_inline:nnn {#1} {#2} { \__pgfgo_sgf_if_comment:nT {##1} { \__pgfgo_sgfdiag_comment_separator: \exp_args:Ne \__pgfgo_sgfdiag_comment_number:n {\__pgfgo_sgfdiag_shown:n {##1}} \__pgfgo_sgf_comment_use: } } } } } %EL DIAGRAMA #1, CON LAS JUGADAS #2 A #3. #4: EL NUMERO DEL NOMBRE DE SU FIGURA (0: SIN NOMBRE). EL EPIGRAFE %DICE LOS NUMEROS DE LA PRIMERA Y LA ULTIMA JUGADA (LOS QUE SIGUEN A MN); SIN JUGADAS (#3 MENOR QUE #2), NADA. \int_new:N \l__pgfgo_sgfdiag_first_number_int \int_new:N \l__pgfgo_sgfdiag_last_number_int \cs_new_protected:Npn \__pgfgo_sgfdiag_diagram:nnnn #1#2#3#4 { %LA VISTA QUE ABARCA LAS DE TODAS LAS JUGADAS DEL DIAGRAMA. \int_set:Nn \l_pgfgo_goban_sgf_view_from_int {#2} \int_set:Nn \l_pgfgo_goban_sgf_view_to_int {#3} \tl_set:Ne \l__pgfgo_sgfdiag_suffix_tl {\int_eval:n {#1}} \__pgfgo_sgf_move_number:Nn \l__pgfgo_sgfdiag_first_number_int {#2} \__pgfgo_sgf_move_number:Nn \l__pgfgo_sgfdiag_last_number_int {#3} \use:e { \exp_not:N \__pgfgo_sgfdiag_add:nnnn {#2} {#3} { \exp_not:n { \int_compare:nNnTF {#4} > {0} {\pgfgo_kernel_sgf_name:n {#4}} {\l__pgfgo_sgfdiag_title_tl \nobreakspace \int_eval:n {#1}} } \int_compare:nNnF {#3} < {#2} { \exp_not:N \nobreakspace (\int_use:N \l__pgfgo_sgfdiag_first_number_int--\int_use:N \l__pgfgo_sgfdiag_last_number_int) } } { \exp_not:n { \__pgfgo_sgfdiag_notes:nn {#2} {#3} \bool_lazy_and:nnT {\l__pgfgo_sgfdiag_result_bool} {\int_compare_p:nNn {#3} = {\l__pgfgo_sgfdiag_total_int}} {\__pgfgo_sgfdiag_result:} } } } } %UNA PARTIDA SIN JUGADAS ES UN DIAGRAMA DE SU POSICION, CON EL NOMBRE DE SU FIGURA (SI TIENE). \cs_new_protected:Npn \__pgfgo_sgfdiag_position: { \tl_clear:N \l__pgfgo_sgfdiag_first_tl \tl_set:Nn \l_tmpa_tl {{1}{0}} \bool_lazy_and:nnT {\l__pgfgo_sgfdiag_figures_bool} {! \seq_if_empty_p:N \l_pgfgo_kernel_sgf_figures_seq} {\seq_get_left:NN \l_pgfgo_kernel_sgf_figures_seq \l_tmpa_tl} \use:e {\exp_not:N \__pgfgo_sgfdiag_diagram:nnnn {1} {1} {0} {\exp_after:wN \use_ii:nn \l_tmpa_tl}} } %EL DIAGRAMA #1 (JUGADAS #2 A #3, CON EL NOMBRE #4), SI TIENE JUGADAS DESDE from: EMPIEZA EN from O DESPUES. %CON restart, SI NO EMPIEZA EN LA JUGADA 1, LA JUGADA #2 SE MUESTRA COMO restart/from (AUNQUE NO SE DIBUJE). \tl_new:N \l__pgfgo_sgfdiag_first_tl \cs_new_protected:Npn \__pgfgo_sgfdiag_range:nnnn #1#2#3#4 { \int_compare:nNnF {#3} < {\l__pgfgo_sgfdiag_from_int} { \bool_lazy_and:nnTF {\str_if_eq_p:Vn \l__pgfgo_sgfdiag_restart_tl {true}} {\int_compare_p:nNn {#2} > {1}} { \tl_set:Ne \l__pgfgo_sgfdiag_first_tl { \int_eval:n { \l__pgfgo_sgfdiag_restart_from_int + \int_max:nn {#2} {\l__pgfgo_sgfdiag_from_int} - (#2) } } } {\tl_clear:N \l__pgfgo_sgfdiag_first_tl} \__pgfgo_sgfdiag_diagram:nnnn {#1} {\int_max:nn {#2} {\l__pgfgo_sgfdiag_from_int}} {#3} {#4} \__pgfgo_sgfdiag_variations:nnn {#1} {#2} {#3} } } %LAS VARIANTES QUE NACEN EN LAS JUGADAS #2 A #3 DEL DIAGRAMA #1, CADA UNA CON SU LETRA (3a, 3b, ...). LAS %VARIANTES DE UNA VARIANTE VAN DONDE VA LA VARIANTE DE LA QUE SALEN (NACEN EN LA MISMA JUGADA). \int_new:N \l__pgfgo_sgfdiag_var_count_int \cs_new_protected:Npn \__pgfgo_sgfdiag_variations:nnn #1#2#3 { \int_zero:N \l__pgfgo_sgfdiag_var_count_int \seq_map_inline:Nn \l__pgfgo_sgfdiag_var_seq {\__pgfgo_sgfdiag_var_if:nnnnnnnnn {#1} {#2} {#3} ##1} } %#4: CAMINO, #5: PROFUNDIDAD, #6: NACE, #7: EMPIEZA, #8: ULTIMA, #9: COMENTADA. SE DIBUJA SI ESTA EN LA %LISTA, O SI commented O all LA INCLUYEN (HASTA LA PROFUNDIDAD depth). \bool_new:N \l__pgfgo_sgfdiag_var_wanted_bool %#1: CAMINO, #2: PROFUNDIDAD, #3: NACE, #4: COMENTADA. \cs_new_protected:Npn \__pgfgo_sgfdiag_var_wanted:nnnn #1#2#3#4 { \seq_if_in:NnTF \l__pgfgo_sgfdiag_var_found_seq {#1} {\bool_set_true:N \l__pgfgo_sgfdiag_var_wanted_bool} { \bool_set:Nn \l__pgfgo_sgfdiag_var_wanted_bool { \int_compare_p:nNn {#2} < {\l__pgfgo_sgfdiag_var_depth_int + 1} && ! \int_compare_p:nNn {#3} < {\l__pgfgo_sgfdiag_var_from_int} && ( \l__pgfgo_sgfdiag_var_all_bool || (\l__pgfgo_sgfdiag_var_commented_bool && \int_compare_p:nNn {#4} = {1}) ) } } } \cs_new_protected:Npn \__pgfgo_sgfdiag_var_if:nnnnnnnnn #1#2#3#4#5#6#7#8#9 { \int_compare:nT {#2 <= #6 <= #3} { \__pgfgo_sgfdiag_var_wanted:nnnn {#4} {#5} {#6} {#9} \bool_if:NT \l__pgfgo_sgfdiag_var_wanted_bool { \int_incr:N \l__pgfgo_sgfdiag_var_count_int \__pgfgo_sgfdiag_variation:nnnnn {\int_eval:n {#1} \int_to_alph:n {\l__pgfgo_sgfdiag_var_count_int}} {#4} {#7} {#7} {#8} } } } %EL DIAGRAMA #1 (3a) DE LA VARIANTE #2, QUE REEMPLAZA LA JUGADA #3 DE LA LINEA DE LA QUE SALE: SUS JUGADAS #4 A #5, %NUMERADAS DESDE 1. SIN LA COPIA DE \sgfdiagrams (LA DE LA LINEA PRINCIPAL QUEDA COMO ESTABA). \int_new:N \l__pgfgo_sgfdiag_var_move_int \NewDocumentCommand \pgfgovariationmove {} {\int_use:N \l__pgfgo_sgfdiag_var_move_int} \cs_new_protected:Npn \__pgfgo_sgfdiag_variation:nnnnn #1#2#3#4#5 { \group_begin: \bool_set_false:N \l__pgfgo_sgf_cache_bool \bool_set_false:N \l__pgfgo_sgfdiag_root_bool \bool_set_false:N \l__pgfgo_sgfdiag_result_bool \tl_set:Nn \l__pgfgo_sgfdiag_variation_tl {#2} \tl_set:Nn \l_pgfgo_goban_sgf_view_variation_tl {#2} \tl_set:Nn \l__pgfgo_sgfdiag_first_tl {1} \int_set:Nn \l__pgfgo_sgfdiag_var_move_int {#3} \int_set:Nn \l_pgfgo_goban_sgf_view_from_int {#4} \int_set:Nn \l_pgfgo_goban_sgf_view_to_int {#5} \tl_set:Ne \l__pgfgo_sgfdiag_suffix_tl {#1} \__pgfgo_sgfdiag_add:nnnn {#4} {#5} {\l__pgfgo_sgfdiag_title_tl \nobreakspace #1 \nobreakspace (\l__pgfgo_sgfdiag_var_title_tl)} {\__pgfgo_sgfdiag_notes:nn {#4} {#5}} \group_end: } %DEBAJO DEL ULTIMO DIAGRAMA: EL RESULTADO (RE) Y, SI EL ARCHIVO MARCA EL TERRITORIO (TB, TW), EL PUNTAJE DE %CADA JUGADOR COMO EL DE \pgfgoscore (CON EL komi DE KM). \tl_new:N \l__pgfgo_sgfdiag_re_tl \cs_new_protected:Npn \__pgfgo_sgfdiag_result: { \tl_set:Ne \l__pgfgo_sgfdiag_re_tl {\exp_args:NV \pgfgo_kernel_sgf_info:nn \l__pgfgo_sgfdiag_file_tl {RE}} \bool_lazy_or:nnT {! \tl_if_blank_p:V \l__pgfgo_sgfdiag_re_tl} {! \prop_if_empty_p:N \g_pgfgo_territory_prop} { \__pgfgo_sgfdiag_below:nn {\l__pgfgo_sgfdiag_align_tl} { \l__pgfgo_sgfdiag_result_title_tl :~ \tl_if_blank:VF \l__pgfgo_sgfdiag_re_tl { \str_if_eq:VnTF \l__pgfgo_sgfdiag_result_format_tl {raw} {\tl_use:N \l__pgfgo_sgfdiag_re_tl} {\exp_args:NV \__pgfgo_sgfdiag_result_text:n \l__pgfgo_sgfdiag_re_tl} } \prop_if_empty:NF \g_pgfgo_territory_prop { \tl_if_blank:VTF \l__pgfgo_sgfdiag_re_tl {\__pgfgo_sgfdiag_score:n {}} {\__pgfgo_sgfdiag_score:n {~(} )} } } } } \cs_new_protected:Npn \__pgfgo_sgfdiag_score:n #1 { #1 \l__pgfgo_sgfdiag_black_tl \nobreakspace \pgfgoscore{black},~ \l__pgfgo_sgfdiag_white_tl \nobreakspace \__pgfgo_sgfdiag_white_score:V \l__pgfgo_sgfdiag_komi_tl } \cs_new_protected:Npn \__pgfgo_sgfdiag_white_score:n #1 {\pgfgoscore[komi = {#1}]{white}} \cs_generate_variant:Nn \__pgfgo_sgfdiag_white_score:n {V} %EL RESULTADO #1 (RE) EN PALABRAS, CON LOS TEXTOS DEL IDIOMA (VER pgf-go-lang.sty): 0 O Draw, Void, ?, Y B+ %O W+ SEGUIDO DE NADA, DE LA DIFERENCIA, DE R (Resign), T (Time) O F (Forfeit). OTRA COSA SE ESCRIBE COMO ESTA. %EN LOS TEXTOS, \pgfgowinner ES EL NOMBRE DEL GANADOR (black name O white name) Y \pgfgopoints LA DIFERENCIA. \tl_new:N \l__pgfgo_sgfdiag_winner_tl \tl_new:N \l__pgfgo_sgfdiag_points_tl \seq_new:N \l__pgfgo_sgfdiag_re_seq \NewDocumentCommand \pgfgowinner {} {\l__pgfgo_sgfdiag_winner_tl} \NewDocumentCommand \pgfgopoints {} {\l__pgfgo_sgfdiag_points_tl} \cs_new_protected:Npn \__pgfgo_sgfdiag_result_text:n #1 { \str_case_e:nnF {\str_lowercase:n {#1}} { {0} {\pgfgo_text:n {draw}} {draw} {\pgfgo_text:n {draw}} {void} {\pgfgo_text:n {void}} {?} {\pgfgo_text:n {unknown~result}} }{ \regex_extract_once:nnNTF {\A([BbWw])\+(.*)\Z} {#1} \l__pgfgo_sgfdiag_re_seq { \str_if_eq:eeTF {\str_uppercase:f {\seq_item:Nn \l__pgfgo_sgfdiag_re_seq {2}}} {B} {\tl_set_eq:NN \l__pgfgo_sgfdiag_winner_tl \l__pgfgo_sgfdiag_black_tl} {\tl_set_eq:NN \l__pgfgo_sgfdiag_winner_tl \l__pgfgo_sgfdiag_white_tl} \tl_set:Ne \l__pgfgo_sgfdiag_points_tl {\seq_item:Nn \l__pgfgo_sgfdiag_re_seq {3}} \str_case_e:nnF {\str_lowercase:f {\l__pgfgo_sgfdiag_points_tl}} { {} {\pgfgo_text:n {win}} {r} {\pgfgo_text:n {win~by~resignation}} {resign} {\pgfgo_text:n {win~by~resignation}} {t} {\pgfgo_text:n {win~on~time}} {time} {\pgfgo_text:n {win~on~time}} {f} {\pgfgo_text:n {win~by~forfeit}} {forfeit} {\pgfgo_text:n {win~by~forfeit}} }{ \regex_match:nVTF {\A\d+(\.\d*)?\Z} \l__pgfgo_sgfdiag_points_tl {\pgfgo_text:n {win~by~points}} {#1} } } {#1} } } %UN DIAGRAMA POR FIGURA (FG): DESDE DONDE EMPIEZA HASTA LA JUGADA ANTERIOR A LA FIGURA SIGUIENTE. SI LA %PRIMERA FIGURA NO EMPIEZA EN LA JUGADA 1, LAS JUGADAS ANTERIORES SON UN DIAGRAMA MAS. \int_new:N \l__pgfgo_sgfdiag_count_int \seq_new:N \l__pgfgo_sgfdiag_figures_seq \cs_new_protected:Npn \__pgfgo_sgfdiag_figures: { \seq_set_eq:NN \l__pgfgo_sgfdiag_figures_seq \l_pgfgo_kernel_sgf_figures_seq \seq_get_left:NN \l__pgfgo_sgfdiag_figures_seq \l_tmpa_tl \int_compare:nNnT {\exp_after:wN \use_i:nn \l_tmpa_tl} > {1} {\seq_put_left:Nn \l__pgfgo_sgfdiag_figures_seq {{1}{0}}} \seq_put_right:Ne \l__pgfgo_sgfdiag_figures_seq {{\int_eval:n {\l__pgfgo_sgfdiag_last_int + 1}}{0}} \int_zero:N \l__pgfgo_sgfdiag_count_int \int_step_inline:nn {\seq_count:N \l__pgfgo_sgfdiag_figures_seq - 1} { \use:e { \exp_not:N \__pgfgo_sgfdiag_figure:nnnn \seq_item:Nn \l__pgfgo_sgfdiag_figures_seq {##1} \seq_item:Nn \l__pgfgo_sgfdiag_figures_seq {##1 + 1} } } } %#1#2: {JUGADA}{NOMBRE} DE LA FIGURA, #3#4: LOS DE LA SIGUIENTE. \cs_new_protected:Npn \__pgfgo_sgfdiag_figure:nnnn #1#2#3#4 { \int_compare:nNnT {#1} < {#3} { \int_compare:nNnF {#1} > {\l__pgfgo_sgfdiag_last_int} { \int_incr:N \l__pgfgo_sgfdiag_count_int \__pgfgo_sgfdiag_range:nnnn {\l__pgfgo_sgfdiag_count_int} {#1} {\int_min:nn {#3 - 1} {\l__pgfgo_sgfdiag_last_int}} {#2} } } } %UN DIAGRAMA CADA step JUGADAS: EL DIAGRAMA n TIENE TANTAS COMO EL ELEMENTO n DE step (O EL ULTIMO). \int_new:N \l__pgfgo_sgfdiag_start_int \int_new:N \l__pgfgo_sgfdiag_length_int \cs_new_protected:Npn \__pgfgo_sgfdiag_steps: { \clist_if_empty:NT \l__pgfgo_sgfdiag_step_clist {\clist_set:Nn \l__pgfgo_sgfdiag_step_clist {50}} \int_zero:N \l__pgfgo_sgfdiag_count_int \int_set:Nn \l__pgfgo_sgfdiag_start_int {1} \int_until_do:nNnn {\l__pgfgo_sgfdiag_start_int} > {\l__pgfgo_sgfdiag_last_int} { \int_incr:N \l__pgfgo_sgfdiag_count_int \int_set:Nn \l__pgfgo_sgfdiag_length_int { \int_max:nn {1} { \clist_item:Nn \l__pgfgo_sgfdiag_step_clist {\int_min:nn {\l__pgfgo_sgfdiag_count_int} {\clist_count:N \l__pgfgo_sgfdiag_step_clist}} } } \use:e { \exp_not:N \__pgfgo_sgfdiag_range:nnnn {\int_use:N \l__pgfgo_sgfdiag_count_int} {\int_use:N \l__pgfgo_sgfdiag_start_int} {\int_min:nn {\l__pgfgo_sgfdiag_start_int + \l__pgfgo_sgfdiag_length_int - 1} {\l__pgfgo_sgfdiag_last_int}} {0} } \int_add:Nn \l__pgfgo_sgfdiag_start_int {\l__pgfgo_sgfdiag_length_int} } } \cs_new_protected:Npn \pgfgo_sgfdiagrams:nn #1#2 { \group_begin: \pgfgo_sgf_use_name:n {#2} \keys_set:nn {pgfgo / sgf~diagrams} {#1} \bool_set_eq:NN \l__pgfgo_sgf_annotations_bool \l__pgfgo_sgfdiag_annotations_bool \bool_set_eq:NN \l__pgfgo_sgf_chat_bool \l__pgfgo_sgfdiag_chat_bool %CADA DIAGRAMA SIGUE LA PARTIDA DESDE EL ANTERIOR (VER \__pgfgo_sgf_play:). \__pgfgo_sgf_cache_begin: \__pgfgo_sgfdiag_begin:Nn \l__pgfgo_sgfdiag_layout_tl {#2} \tl_clear:N \l__pgfgo_sgf_extent_tl \exp_args:NnV \pgfgo_kernel_sgf_read:nn {#2} \l__pgfgo_sgfdiag_variation_tl \__pgfgo_sgf_board:N \l__pgfgo_sgfdiag_board_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_komi_tl \l_pgfgo_kernel_sgf_komi_tl \__pgfgo_sgfdiag_var_setup:n {#2} %CON true, CADA DIAGRAMA SE NUMERA CON \l__pgfgo_sgfdiag_first_tl: \sgf NO REINICIA. \tl_set:Ne \l__pgfgo_sgfdiag_sgf_restart_tl {\str_if_eq:VnTF \l__pgfgo_sgfdiag_restart_tl {auto} {auto} {false}} \tl_set:Ne \l__pgfgo_sgfdiag_window_tl { \tl_if_empty:NTF \l__pgfgo_sgfdiag_partial_tl { \bool_if:NT \l__pgfgo_sgfdiag_partial_bool {partial = auto,} \bool_if:NT \l__pgfgo_sgfdiag_view_bool {sgf~view = {\exp_not:n {#2}}} }{ partial = {\exp_not:V \l__pgfgo_sgfdiag_partial_tl} } } \tl_set_eq:NN \l_pgfgo_goban_sgf_view_variation_tl \l__pgfgo_sgfdiag_variation_tl \__pgfgo_sgf_count_moves:Nn \l__pgfgo_sgfdiag_total_int {\c_max_int} \int_set:Nn \l__pgfgo_sgfdiag_last_int { \int_compare:nNnTF {\l__pgfgo_sgfdiag_to_int} < {0} {\l__pgfgo_sgfdiag_total_int} {\int_min:nn {\l__pgfgo_sgfdiag_to_int} {\l__pgfgo_sgfdiag_total_int}} } \bool_if:NT \l__pgfgo_sgfdiag_partial_bool {\__pgfgo_sgfdiag_extent:n {#2}} \bool_lazy_and:nnTF {\l__pgfgo_sgfdiag_figures_bool} {! \seq_if_empty_p:N \l_pgfgo_kernel_sgf_figures_seq} {\__pgfgo_sgfdiag_figures:} {\__pgfgo_sgfdiag_steps:} \int_compare:nNnT {\l__pgfgo_sgfdiag_total_int} = {0} {\__pgfgo_sgfdiag_position:} \pgfgo_layout_end: \__pgfgo_sgfdiag_after_flush: \group_end: } %LAS VARIANTES DEL ARCHIVO #1 QUE PUEDEN DIBUJARSE: LAS QUE SE APARTAN DE LA LINEA QUE SE DIBUJA (LA DE %variation). LOS CAMINOS DE LA LISTA, %COMO NUMEROS SIN LOS 1 DEL FINAL (2.3.1 ES LA MISMA LINEA QUE 2.3), QUEDAN EN \l__pgfgo_sgfdiag_var_found_seq. %UN CAMINO QUE NO ES UNA VARIANTE DA UN AVISO. \msg_new:nnn {pgfgo} {sgf-no-variation} {'#1'~has~no~variation~'#2':~it~is~not~drawn.} \seq_new:N \l__pgfgo_sgfdiag_var_seq \seq_new:N \l__pgfgo_sgfdiag_var_found_seq \cs_new_protected:Npn \__pgfgo_sgfdiag_var_setup:n #1 { \seq_clear:N \l__pgfgo_sgfdiag_var_seq \seq_clear:N \l__pgfgo_sgfdiag_var_found_seq \bool_lazy_or:nnT {\l__pgfgo_sgfdiag_var_commented_bool || \l__pgfgo_sgfdiag_var_all_bool} {! \seq_if_empty_p:N \l__pgfgo_sgfdiag_var_paths_seq} { \exp_args:NnV \pgfgo_kernel_sgf_branches:nn {#1} \l__pgfgo_sgfdiag_variation_tl \seq_set_eq:NN \l__pgfgo_sgfdiag_var_seq \l_pgfgo_kernel_sgf_branches_seq \seq_map_inline:Nn \l__pgfgo_sgfdiag_var_paths_seq { \pgfgo_kernel_sgf_path:nn {#1} {##1} \seq_put_right:NV \l__pgfgo_sgfdiag_var_found_seq \l_pgfgo_kernel_sgf_path_tl \bool_set_false:N \l_tmpa_bool \seq_map_inline:Nn \l__pgfgo_sgfdiag_var_seq { \str_if_eq:eeT {\use_i:nnnnnn ####1} {\l_pgfgo_kernel_sgf_path_tl} {\bool_set_true:N \l_tmpa_bool \seq_map_break:} } \bool_if:NF \l_tmpa_bool {\msg_warning:nnnn {pgfgo} {sgf-no-variation} {#1} {##1}} } %LA LECTURA DE LA LINEA QUE SE DIBUJA QUEDA COMO ESTABA. \exp_args:NnV \pgfgo_kernel_sgf_read:nn {#1} \l__pgfgo_sgfdiag_variation_tl } } %partial = auto: LA PARTE VISIBLE DE LA LINEA QUE SE DIBUJA Y DE LAS VARIANTES QUE SE DIBUJAN (LAS QUE %NACEN HASTA LA ULTIMA JUGADA), DEL ARCHIVO #1. \tl_new:N \l__pgfgo_sgfdiag_extent_tl \cs_new_protected:Npn \__pgfgo_sgfdiag_extent:n #1 { \tl_set_eq:NN \l__pgfgo_sgfdiag_extent_tl \l__pgfgo_sgfdiag_variation_tl \seq_map_inline:Nn \l__pgfgo_sgfdiag_var_seq {\__pgfgo_sgfdiag_extent:nnnnnn ##1} \__pgfgo_sgf_extent:nV {#1} \l__pgfgo_sgfdiag_extent_tl } \cs_new_protected:Npn \__pgfgo_sgfdiag_extent:nnnnnn #1#2#3#4#5#6 { \int_compare:nNnF {#3} > {\l__pgfgo_sgfdiag_last_int} { \__pgfgo_sgfdiag_var_wanted:nnnn {#1} {#2} {#3} {#6} \bool_if:NT \l__pgfgo_sgfdiag_var_wanted_bool {\tl_put_right:Nn \l__pgfgo_sgfdiag_extent_tl {; #1}} } } \NewDocumentCommand{\sgfdiagrams}{O{}m}{ \__pgfgo_sgf_if_kernel:n {\pgfgo_sgfdiagrams:nn {#1} {#2}} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %---------------------------------------PROBLEMAS-----------------------------------------------% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %\sgfproblem[]{} DIBUJA UN PROBLEMA (TSUMEGO): EL ENUNCIADO (LA POSICION INICIAL CON %SUS MARCAS, QUIEN JUEGA Y EL COMENTARIO DE LA RAIZ) Y UN DIAGRAMA POR CADA LINEA DEL ARBOL (CADA VARIANTE %DE LA SOLUCION), NUMERADA DESDE 1, CON SUS NOTAS Y SUS COMENTARIOS. SE USA FUERA DE goban. LOS DIAGRAMAS %SE DIBUJAN COMO LOS DE \sgfdiagrams. \bool_new:N \l__pgfgo_sgfprob_statement_bool \bool_new:N \l__pgfgo_sgfprob_alone_bool \tl_new:N \l__pgfgo_sgfprob_layout_tl \bool_new:N \l__pgfgo_sgfprob_solutions_bool \bool_new:N \l__pgfgo_sgfprob_view_bool \bool_new:N \l__pgfgo_sgfprob_partial_bool \tl_new:N \l__pgfgo_sgfprob_partial_tl \int_new:N \l__pgfgo_sgfprob_last_int \tl_new:N \l__pgfgo_sgfprob_title_tl \tl_new:N \l__pgfgo_sgfprob_goban_tl \tl_new:N \l__pgfgo_sgfprob_font_tl \tl_new:N \l__pgfgo_sgfprob_caption_min_tl \bool_new:N \l__pgfgo_sgfprob_notes_bool \bool_new:N \l__pgfgo_sgfprob_comments_bool \tl_new:N \l__pgfgo_sgfprob_comment_font_tl \tl_new:N \l__pgfgo_sgfprob_comment_align_tl \tl_new:N \l__pgfgo_sgfprob_comment_separator_tl \tl_new:N \l__pgfgo_sgfprob_comment_position_tl \tl_new:N \l__pgfgo_sgfprob_comment_width_tl \dim_new:N \l__pgfgo_sgfprob_comment_sep_dim \tl_new:N \l__pgfgo_sgfprob_comment_height_tl \cs_new:Npn \__pgfgo_sgfprob_comment_number:n #1 {} \tl_new:N \l__pgfgo_sgfprob_variation_title_tl \tl_new:N \l__pgfgo_sgfprob_black_tl \tl_new:N \l__pgfgo_sgfprob_white_tl \tl_new:N \l__pgfgo_sgfprob_player_tl %LAS PARTIDAS DEL ARCHIVO (game = {1:20, 25}: UNA COLECCION DE PROBLEMAS), QUIEN JUEGA (to play) Y EL %COMIENZO DEL EPIGRAFE DE CADA PROBLEMA ("Problem 3"). \seq_new:N \l__pgfgo_sgfprob_games_seq \tl_new:N \l__pgfgo_sgfprob_to_play_tl \tl_new:N \l__pgfgo_sgfprob_head_tl %verdict: SI CADA SOLUCION ES CORRECTA O NO (\l__pgfgo_sgfprob_verdict_tl: correct, wrong O NADA). \bool_new:N \l__pgfgo_sgfprob_verdict_bool \tl_new:N \l__pgfgo_sgfprob_verdict_tl \tl_new:N \l__pgfgo_sgfprob_position_tl \tl_new:N \l__pgfgo_sgfprob_moves_tl \bool_new:N \l__pgfgo_sgfprob_right_bool \seq_new:N \l__pgfgo_sgfprob_paths_seq \bool_new:N \l__pgfgo_sgfprob_links_bool \keys_define:nn {pgfgo / sgf~problem} { %alone: EL ENUNCIADO VA SOLO EN SU FILA, Y LAS VARIANTES DEBAJO. statement .choices:nn = {true, false, alone} { \bool_set:Nn \l__pgfgo_sgfprob_statement_bool {! \str_if_eq_p:Vn \l_keys_choice_tl {false}} \bool_set:Nn \l__pgfgo_sgfprob_alone_bool {\str_if_eq_p:Vn \l_keys_choice_tl {alone}} }, statement .default:n = {true}, statement .initial:n = {true}, solutions .bool_set:N = \l__pgfgo_sgfprob_solutions_bool, solutions .default:n = {true}, solutions .initial:n = {true}, %EPIGRAFE DEL ENUNCIADO, ANTES DE QUIEN JUEGA ("Problem 3: Black to play"). title .tl_set:N = \l__pgfgo_sgfprob_title_tl, variation~title .tl_set:N = \l__pgfgo_sgfprob_variation_title_tl, variation~title .initial:n = {\pgfgo_text:n {variation}}, black~to~play .tl_set:N = \l__pgfgo_sgfprob_black_tl, black~to~play .initial:n = {\pgfgo_text:n {black~to~play}}, white~to~play .tl_set:N = \l__pgfgo_sgfprob_white_tl, white~to~play .initial:n = {\pgfgo_text:n {white~to~play}}, %COMO EN \sgfdiagrams (PERO CON LOS COMENTARIOS: ASI SE VE CUALES LINEAS SON CORRECTAS). goban .tl_set:N = \l__pgfgo_sgfprob_goban_tl, %EL ENUNCIADO SE LLAMA name, Y CADA SOLUCION name SEGUIDO DE SU NUMERO. CON VARIAS PARTIDAS, name Y LA %PARTIDA (problema3), Y name, LA PARTIDA, - Y EL NUMERO (problema3-1). name .tl_set:N = \l__pgfgo_sgfprob_name_tl, caption .code:n = {\keys_set:nn {pgfgo / sgf~problem / caption} {#1}}, notes .bool_set:N = \l__pgfgo_sgfprob_notes_bool, notes .default:n = {true}, notes .initial:n = {true}, comments .code:n = {\keys_set:nn {pgfgo / sgf~problem / comments} {#1}}, comments .default:n = {true}, annotations .bool_set:N = \l__pgfgo_sgfprob_annotations_bool, annotations .default:n = {true}, chat .bool_set:N = \l__pgfgo_sgfprob_chat_bool, chat .default:n = {true}, %UNA PARTIDA, O VARIAS ({1:20, 25}): PRIMERO TODOS LOS ENUNCIADOS Y DESPUES LAS SOLUCIONES. game .code:n = {\__pgfgo_sgfprob_games:n {#1}}, %auto: PL O EL COLOR DE LA PRIMERA JUGADA. none: EL EPIGRAFE NO DICE QUIEN JUEGA. to~play .choices:nn = {auto, black, white, none} {\tl_set_eq:NN \l__pgfgo_sgfprob_to_play_tl \l_keys_choice_tl}, to~play .initial:n = {auto}, %EL EPIGRAFE DE CADA SOLUCION DICE SI ES CORRECTA, SEGUN SUS ANOTACIONES (VER \__pgfgo_sgfprob_verdict:n). verdict .bool_set:N = \l__pgfgo_sgfprob_verdict_bool, verdict .default:n = {true}, verdict .initial:n = {false}, %LA VISTA DEL ARCHIVO (VW). SI NO HAY, CON partial = auto SE MUESTRA SOLO LA PARTE DEL TABLERO QUE USA EL %PROBLEMA. view .bool_set:N = \l__pgfgo_sgfprob_view_bool, view .default:n = {true}, view .initial:n = {true}, partial .code:n = {\__pgfgo_sgf_partial:NNn \l__pgfgo_sgfprob_partial_bool \l__pgfgo_sgfprob_partial_tl {#1}}, partial .initial:n = {auto}, layout .code:n = {\tl_put_right:Nn \l__pgfgo_sgfprob_layout_tl {, #1}}, %CON hyperref: EL EPIGRAFE DEL ENUNCIADO LLEVA A SU PRIMERA SOLUCION, Y EL DE CADA SOLUCION AL ENUNCIADO. links .bool_set:N = \l__pgfgo_sgfprob_links_bool, links .default:n = {true}, links .initial:n = {false}, } %COMO EN \sgfdiagrams (SIN root: EL COMENTARIO DE LA RAIZ VA CON EL ENUNCIADO). \keys_define:nn {pgfgo / sgf~problem / comments} { true .code:n = {\bool_set_true:N \l__pgfgo_sgfprob_comments_bool}, false .code:n = {\bool_set_false:N \l__pgfgo_sgfprob_comments_bool}, font .tl_set:N = \l__pgfgo_sgfprob_comment_font_tl, align .code:n = {\__pgfgo_sgfdiag_comment_align:Nn \l__pgfgo_sgfprob_comment_align_tl {#1}}, align .initial:n = {left}, number .code:n = {\cs_set:Npn \__pgfgo_sgfprob_comment_number:n ##1 {#1}}, number .initial:n = {\textbf{#1}:~}, separator .tl_set:N = \l__pgfgo_sgfprob_comment_separator_tl, separator .initial:n = {\par}, position .choices:nn = {below, right, left, after} {\tl_set_eq:NN \l__pgfgo_sgfprob_comment_position_tl \l_keys_choice_tl}, height .tl_set:N = \l__pgfgo_sgfprob_comment_height_tl, height .initial:n = {none}, position .initial:n = {below}, width .tl_set:N = \l__pgfgo_sgfprob_comment_width_tl, width .initial:n = {auto}, sep .dim_set:N = \l__pgfgo_sgfprob_comment_sep_dim, sep .initial:n = {1em}, } \bool_set_true:N \l__pgfgo_sgfprob_comments_bool \keys_define:nn {pgfgo / sgf~problem / caption} { font .tl_set:N = \l__pgfgo_sgfprob_font_tl, font .initial:n = {\small}, min~width .tl_set:N = \l__pgfgo_sgfprob_caption_min_tl, min~width .initial:n = {8em}, } \keys_define:nn {pgfgo} { sgf~problem .code:n = {\keys_set:nn {pgfgo / sgf~problem} {#1}} } %QUIEN JUEGA: EL PL DEL PRINCIPIO O, SI NO ESTA, EL COLOR DE LA PRIMERA JUGADA. \cs_new_protected:Npn \__pgfgo_sgfprob_player:nnn #1#2#3 { \str_case:nnT {#1} { {player} {\tl_set:Nn \l__pgfgo_sgfprob_player_tl {#2}} {black} {\tl_set:Nn \l__pgfgo_sgfprob_player_tl {black}} {white} {\tl_set:Nn \l__pgfgo_sgfprob_player_tl {white}} }{ \seq_map_break: } } %LA PARTE VISIBLE ES LA MISMA EN TODOS LOS DIAGRAMAS: LA VISTA INICIAL DEL ARCHIVO #1, O LA DE partial = auto. \cs_new_protected:Npn \__pgfgo_sgfprob_window:n #1 { \tl_clear:N \l__pgfgo_sgfdiag_window_tl \int_zero:N \l_pgfgo_goban_sgf_view_from_int \int_zero:N \l_pgfgo_goban_sgf_view_to_int \tl_clear:N \l_pgfgo_goban_sgf_view_variation_tl \tl_if_empty:NTF \l__pgfgo_sgfprob_partial_tl { \bool_lazy_and:nnTF {\l__pgfgo_sgfprob_view_bool} {! \tl_if_empty_p:N \l_pgfgo_kernel_sgf_view_tl} {\tl_set:Nn \l__pgfgo_sgfdiag_window_tl {sgf~view = {#1}}} {\bool_if:NT \l__pgfgo_sgfprob_partial_bool {\tl_set:Nn \l__pgfgo_sgfdiag_window_tl {partial = auto}}} }{ \tl_set:Ne \l__pgfgo_sgfdiag_window_tl {partial = {\exp_not:V \l__pgfgo_sgfprob_partial_tl}} } } %LAS PARTIDAS DE game: NUMEROS Y RANGOS (3:7, COMO LOS DE LAS COORDENADAS), SEPARADOS POR COMAS. LOS : DEL %DOCUMENTO NO SON LETRAS: SE SEPARA CON \c_colon_str. \cs_generate_variant:Nn \seq_set_split:Nnn {NV} \cs_new_protected:Npn \__pgfgo_sgfprob_games:n #1 { \seq_clear:N \l__pgfgo_sgfprob_games_seq \clist_map_inline:nn {#1} { \seq_set_split:NVn \l_tmpa_seq \c_colon_str {##1} \int_step_inline:nnn {\seq_item:Nn \l_tmpa_seq {1}} {\seq_item:Nn \l_tmpa_seq {-1}} {\seq_put_right:Nn \l__pgfgo_sgfprob_games_seq {####1}} } \seq_get_left:NNT \l__pgfgo_sgfprob_games_seq \l_tmpa_tl {\int_set:Nn \l_pgfgo_kernel_sgf_game_int {\l_tmpa_tl}} } %SACA DE LA LISTA LAS PARTIDAS QUE EL ARCHIVO #1 NO TIENE, CON UN SOLO AVISO. SI NO QUEDA NINGUNA, LA %PRIMERA (COMO CON game EN \sgf). SIN EL ARCHIVO NO SE TOCA (EL AVISO ES EL DE LA LECTURA). \seq_new:N \l__pgfgo_sgfprob_existing_seq \int_new:N \l__pgfgo_sgfprob_missing_int \msg_new:nnn {pgfgo} {sgf-games} {'#1'~has~#2~game(s);~the~#3~game(s)~after~#2~are~left~out.} \cs_new_protected:Npn \__pgfgo_sgfprob_existing_games:n #1 { \pgfgo_kernel_sgf_games:n {#1} \int_compare:nNnT {\l_pgfgo_kernel_sgf_games_int} > {0} { \seq_clear:N \l__pgfgo_sgfprob_existing_seq \int_zero:N \l__pgfgo_sgfprob_missing_int \seq_map_inline:Nn \l__pgfgo_sgfprob_games_seq { \int_compare:nNnTF {##1} > {\l_pgfgo_kernel_sgf_games_int} {\int_incr:N \l__pgfgo_sgfprob_missing_int} {\seq_put_right:Nn \l__pgfgo_sgfprob_existing_seq {##1}} } \int_compare:nNnT {\l__pgfgo_sgfprob_missing_int} > {0} { \use:e { \msg_warning:nnnnn {pgfgo} {sgf-games} {\exp_not:n {#1}} {\int_use:N \l_pgfgo_kernel_sgf_games_int} {\int_use:N \l__pgfgo_sgfprob_missing_int} } \seq_if_empty:NT \l__pgfgo_sgfprob_existing_seq {\seq_put_right:Nn \l__pgfgo_sgfprob_existing_seq {1}} \seq_set_eq:NN \l__pgfgo_sgfprob_games_seq \l__pgfgo_sgfprob_existing_seq } } } \cs_generate_variant:Nn \str_case:nnF {V} %LEE EL PROBLEMA DEL ARCHIVO #1 (LA PARTIDA \l_pgfgo_kernel_sgf_game_int): SUS LINEAS, SU TAMANO, QUIEN JUEGA Y %LA PARTE VISIBLE. \cs_new_protected:Npn \__pgfgo_sgfprob_prepare:n #1 { \__pgfgo_sgf_extent:n {#1} \seq_set_eq:NN \l__pgfgo_sgfprob_paths_seq \l_pgfgo_kernel_sgf_paths_seq \pgfgo_kernel_sgf_read:n {#1} \__pgfgo_sgf_board:N \l__pgfgo_sgfdiag_board_tl \tl_clear:N \l__pgfgo_sgfprob_player_tl \str_case:VnF \l__pgfgo_sgfprob_to_play_tl { {auto} {\seq_map_inline:Nn \l_pgfgo_kernel_sgf_moves_seq {\__pgfgo_sgfprob_player:nnn ##1}} {none} {} }{ \tl_set_eq:NN \l__pgfgo_sgfprob_player_tl \l__pgfgo_sgfprob_to_play_tl } \__pgfgo_sgfprob_window:n {#1} } %EL COMIENZO DEL EPIGRAFE DEL PROBLEMA #1: title; CON VARIAS PARTIDAS, title (O "Problem") Y EL NUMERO. %CON VARIAS PARTIDAS, \l__pgfgo_sgfprob_game_tl ES #1 (PARA LOS NOMBRES DE name). \tl_new:N \l__pgfgo_sgfprob_game_tl \cs_new_protected:Npn \__pgfgo_sgfprob_head:n #1 { \tl_set:Ne \l__pgfgo_sgfprob_game_tl {\int_compare:nNnT {\seq_count:N \l__pgfgo_sgfprob_games_seq} > {1} {#1}} \int_compare:nNnTF {\seq_count:N \l__pgfgo_sgfprob_games_seq} > {1} { \tl_set:Ne \l__pgfgo_sgfprob_head_tl { \tl_if_empty:NTF \l__pgfgo_sgfprob_title_tl {\exp_not:n {\pgfgo_text:n {problem}}} {\exp_not:V \l__pgfgo_sgfprob_title_tl} \exp_not:N \nobreakspace #1 } } {\tl_set_eq:NN \l__pgfgo_sgfprob_head_tl \l__pgfgo_sgfprob_title_tl} } %LOS ENLACES (links). EL DESTINO DEL ENUNCIADO Y EL DE LA PRIMERA SOLUCION DE CADA PROBLEMA SE LLAMAN %pgfgo. (DEL ARCHIVO, LA PARTIDA Y statement O solution), Y SE ANOTAN EN EL .aux COMO ETIQUETAS %(pgfgo@): UN ENLACE SOLO SE PONE SI SU DESTINO ESTABA EN LA COMPILACION ANTERIOR, Y SI ALGUNO ES NUEVO %LaTeX AVISA QUE LAS ETIQUETAS CAMBIARON. CADA DESTINO SE PONE UNA SOLA VEZ. \msg_new:nnn {pgfgo} {sgf-links} {sgf~problem/links~needs~hyperref.} \bool_new:N \g__pgfgo_sgfprob_links_warned_bool \prop_new:N \g__pgfgo_sgfprob_targets_prop \tl_new:N \l__pgfgo_sgfprob_target_tl \tl_new:N \l__pgfgo_sgfprob_link_tl \cs_generate_variant:Nn \str_mdfive_hash:n {e} \cs_new:Npn \__pgfgo_sgfprob_id:n #1 { \str_mdfive_hash:e {\tl_to_str:N \l__pgfgo_sgfdiag_file_tl / \int_use:N \l_pgfgo_kernel_sgf_game_int / #1} } \prg_new_protected_conditional:Npnn \__pgfgo_sgfprob_if_links: {T, TF} { \bool_if:NTF \l__pgfgo_sgfprob_links_bool { \cs_if_exist:NTF \hyperlink {\prg_return_true:} { \bool_if:NF \g__pgfgo_sgfprob_links_warned_bool { \bool_gset_true:N \g__pgfgo_sgfprob_links_warned_bool \msg_warning:nn {pgfgo} {sgf-links} } \prg_return_false: } } {\prg_return_false:} } %EL EPIGRAFE #1, CON UN ENLACE AL DESTINO \l__pgfgo_sgfprob_link_tl SI ESTABA EN LA COMPILACION ANTERIOR. \cs_new_protected:Npn \__pgfgo_sgfprob_link:n #1 { \__pgfgo_sgfprob_if_links:TF {\cs_if_exist:cTF {r@pgfgo@\l__pgfgo_sgfprob_link_tl} {\hyperlink{pgfgo.\l__pgfgo_sgfprob_link_tl}{#1}} {#1}} {#1} } %EL DESTINO #1 (statement O solution) ARRIBA DEL DIAGRAMA, SI TODAVIA NO ESTA. \cs_new_protected:Npn \__pgfgo_sgfprob_target:n #1 { \__pgfgo_sgfprob_if_links:T { \tl_set:Ne \l__pgfgo_sgfprob_target_tl {\__pgfgo_sgfprob_id:n {#1}} \prop_if_in:NVF \g__pgfgo_sgfprob_targets_prop \l__pgfgo_sgfprob_target_tl { \prop_gput:NVn \g__pgfgo_sgfprob_targets_prop \l__pgfgo_sgfprob_target_tl {} \hbox_set:Nn \l__pgfgo_sgfdiag_cell_box { \hbox_overlap_right:n { \box_move_up:nn {\box_ht:N \l__pgfgo_sgfdiag_cell_box} {\hbox:n {\hypertarget{pgfgo.\l__pgfgo_sgfprob_target_tl}{}}} } \box_use:N \l__pgfgo_sgfdiag_cell_box } \legacy_if:nT {@filesw} {\iow_now:Ne \@auxout {\token_to_str:N \newlabel {pgfgo@\l__pgfgo_sgfprob_target_tl} {{}{}}}} } } } %EL ENUNCIADO: LA POSICION INICIAL, QUIEN JUEGA Y EL COMENTARIO DE LA RAIZ. \cs_new_protected:Npn \__pgfgo_sgfprob_statement: { \tl_clear:N \l__pgfgo_sgfdiag_variation_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_suffix_tl \l__pgfgo_sgfprob_game_tl \tl_set:Ne \l__pgfgo_sgfprob_link_tl {\__pgfgo_sgfprob_id:n {solution}} \__pgfgo_sgfdiag_draw:nnnn {1} {0} { \__pgfgo_sgfprob_link:n { %LOS DOS PUNTOS, SOLO SI DESPUES SE DICE QUIEN JUEGA. \tl_use:N \l__pgfgo_sgfprob_head_tl \tl_if_empty:NF \l__pgfgo_sgfprob_player_tl { \tl_if_empty:NF \l__pgfgo_sgfprob_head_tl {:~} \str_case:Vn \l__pgfgo_sgfprob_player_tl { {black} {\l__pgfgo_sgfprob_black_tl} {white} {\l__pgfgo_sgfprob_white_tl} } } } } { \bool_if:NT \l__pgfgo_sgfdiag_comments_bool { \__pgfgo_sgf_if_comment:nT {0} {\__pgfgo_sgfdiag_comments_below:n {\__pgfgo_sgf_comment_use:}} } } \__pgfgo_sgfprob_target:n {statement} \bool_if:NTF \l__pgfgo_sgfprob_alone_bool {\__pgfgo_sgfdiag_join: \pgfgo_layout_add_alone:N \l__pgfgo_sgfdiag_cell_box} {\pgfgo_layout_add:NN \l__pgfgo_sgfdiag_cell_box \l__pgfgo_sgfdiag_below_box} } %SI LA LINEA LEIDA (JUGADAS 0 A #1) ES CORRECTA PARA QUIEN JUEGA: EL ULTIMO GB O GW (POSICION BUENA PARA %NEGRO O BLANCO); SI NO HAY, LA PRIMERA JUGADA CON TE O BM (LAS IMPARES SON DE QUIEN JUEGA: SU BM ES UN %ERROR, EL DEL RIVAL NO); SI NO, "RIGHT" EN UN COMENTARIO (COMO EN goproblems.com). SI NO, NADA. \cs_generate_variant:Nn \str_if_in:nnT {ee} \cs_new_protected:Npn \__pgfgo_sgfprob_verdict:n #1 { \tl_clear:N \l__pgfgo_sgfprob_position_tl \tl_clear:N \l__pgfgo_sgfprob_moves_tl \bool_set_false:N \l__pgfgo_sgfprob_right_bool \int_step_inline:nnn {0} {#1} { \pgfgo_kernel_sgf_annotations:n {##1} \seq_map_inline:Nn \l_pgfgo_kernel_sgf_annotations_seq {\__pgfgo_sgfprob_judge:nnn {##1} ####1} \str_if_in:eeT {\pgfgo_kernel_sgf_comment:nn {##1} {true}} {RIGHT} {\bool_set_true:N \l__pgfgo_sgfprob_right_bool} } \tl_set:Ne \l__pgfgo_sgfprob_verdict_tl { \tl_if_empty:NTF \l__pgfgo_sgfprob_position_tl { \tl_if_empty:NTF \l__pgfgo_sgfprob_moves_tl {\bool_if:NT \l__pgfgo_sgfprob_right_bool {correct}} {\tl_use:N \l__pgfgo_sgfprob_moves_tl} } {\tl_use:N \l__pgfgo_sgfprob_position_tl} } } %LA ANOTACION #2 (CON VALOR #3) DE LA JUGADA #1. \cs_new_protected:Npn \__pgfgo_sgfprob_judge:nnn #1#2#3 { \str_case:nn {#2} { {GB} {\__pgfgo_sgfprob_position:n {black}} {GW} {\__pgfgo_sgfprob_position:n {white}} {TE} {\__pgfgo_sgfprob_move:nnn {#1} {correct} {wrong}} {BM} {\__pgfgo_sgfprob_move:nnn {#1} {wrong} {correct}} } } \cs_new_protected:Npn \__pgfgo_sgfprob_position:n #1 { \tl_if_empty:NF \l__pgfgo_sgfprob_player_tl { \tl_set:Ne \l__pgfgo_sgfprob_position_tl {\str_if_eq:VnTF \l__pgfgo_sgfprob_player_tl {#1} {correct} {wrong}} } } %LA JUGADA #1: #2 SI ES DE QUIEN JUEGA (IMPAR), #3 SI ES DEL RIVAL. SOLO CUENTA LA PRIMERA. \cs_new_protected:Npn \__pgfgo_sgfprob_move:nnn #1#2#3 { \bool_lazy_and:nnT {\tl_if_empty_p:N \l__pgfgo_sgfprob_moves_tl} {\int_compare_p:nNn {#1} > {0}} { \tl_set:Ne \l__pgfgo_sgfprob_moves_tl {\int_if_odd:nTF {#1} {#2} {#3}} } } %EL DIAGRAMA DE LA LINEA #2 (#1 ES SU NUMERO). \cs_new_protected:Npn \__pgfgo_sgfprob_solution:nn #1#2 { \tl_set:Nn \l__pgfgo_sgfdiag_variation_tl {#2} \pgfgo_kernel_sgf_read:nn {\l__pgfgo_sgfdiag_file_tl} {#2} \__pgfgo_sgf_count_moves:Nn \l__pgfgo_sgfprob_last_int {\c_max_int} \tl_clear:N \l__pgfgo_sgfprob_verdict_tl \bool_if:NT \l__pgfgo_sgfprob_verdict_bool {\__pgfgo_sgfprob_verdict:n {\l__pgfgo_sgfprob_last_int}} \int_compare:nNnT {\l__pgfgo_sgfprob_last_int} > {0} { \tl_set:Ne \l__pgfgo_sgfdiag_suffix_tl {\tl_if_empty:NF \l__pgfgo_sgfprob_game_tl {\l__pgfgo_sgfprob_game_tl -} #1} \tl_set:Ne \l__pgfgo_sgfprob_link_tl {\__pgfgo_sgfprob_id:n {statement}} \__pgfgo_sgfdiag_draw:nnnn {1} {\l__pgfgo_sgfprob_last_int} { \__pgfgo_sgfprob_link:n { \int_compare:nNnT {\seq_count:N \l__pgfgo_sgfprob_games_seq} > {1} {\l__pgfgo_sgfprob_head_tl :~} \l__pgfgo_sgfprob_variation_title_tl \nobreakspace #1 \tl_if_empty:NF \l__pgfgo_sgfprob_verdict_tl {\nobreakspace (\exp_args:Ne \pgfgo_text:n {\l__pgfgo_sgfprob_verdict_tl})} } } {\__pgfgo_sgfdiag_notes:nn {1} {\l__pgfgo_sgfprob_last_int}} \__pgfgo_sgfprob_target:n {solution} \pgfgo_layout_add:NN \l__pgfgo_sgfdiag_cell_box \l__pgfgo_sgfdiag_below_box } } \cs_new_protected:Npn \pgfgo_sgfproblem:nn #1#2 { \group_begin: \pgfgo_sgf_use_name:n {#2} \keys_set:nn {pgfgo / sgf~problem} {#1} \bool_set_eq:NN \l__pgfgo_sgf_annotations_bool \l__pgfgo_sgfprob_annotations_bool \bool_set_eq:NN \l__pgfgo_sgf_chat_bool \l__pgfgo_sgfprob_chat_bool \__pgfgo_sgfdiag_begin:Nn \l__pgfgo_sgfprob_layout_tl {#2} \tl_set:Nn \l__pgfgo_sgfdiag_sgf_restart_tl {false} %LOS DIAGRAMAS DE UN PROBLEMA SIEMPRE VAN NUMERADOS, SIN MARCA DE LA ULTIMA JUGADA. \bool_set_true:N \l__pgfgo_sgfdiag_numbers_bool \tl_clear:N \l__pgfgo_sgfdiag_last_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_goban_tl \l__pgfgo_sgfprob_goban_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_name_tl \l__pgfgo_sgfprob_name_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_font_tl \l__pgfgo_sgfprob_font_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_caption_min_tl \l__pgfgo_sgfprob_caption_min_tl \bool_set_eq:NN \l__pgfgo_sgfdiag_notes_bool \l__pgfgo_sgfprob_notes_bool \bool_set_eq:NN \l__pgfgo_sgfdiag_comments_bool \l__pgfgo_sgfprob_comments_bool \tl_set_eq:NN \l__pgfgo_sgfdiag_comment_font_tl \l__pgfgo_sgfprob_comment_font_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_comment_align_tl \l__pgfgo_sgfprob_comment_align_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_comment_separator_tl \l__pgfgo_sgfprob_comment_separator_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_comment_position_tl \l__pgfgo_sgfprob_comment_position_tl \tl_set_eq:NN \l__pgfgo_sgfdiag_comment_width_tl \l__pgfgo_sgfprob_comment_width_tl \dim_set_eq:NN \l__pgfgo_sgfdiag_comment_sep_dim \l__pgfgo_sgfprob_comment_sep_dim \tl_set_eq:NN \l__pgfgo_sgfdiag_comment_height_tl \l__pgfgo_sgfprob_comment_height_tl \cs_set_eq:NN \__pgfgo_sgfdiag_comment_number:n \__pgfgo_sgfprob_comment_number:n \bool_set_false:N \l__pgfgo_sgfdiag_root_bool \seq_if_empty:NT \l__pgfgo_sgfprob_games_seq {\seq_put_right:Ne \l__pgfgo_sgfprob_games_seq {\int_use:N \l_pgfgo_kernel_sgf_game_int}} \__pgfgo_sgfprob_existing_games:n {#2} %PRIMERO LOS ENUNCIADOS DE TODAS LAS PARTIDAS, DESPUES LAS SOLUCIONES. \bool_if:NT \l__pgfgo_sgfprob_statement_bool { \seq_map_inline:Nn \l__pgfgo_sgfprob_games_seq { \int_set:Nn \l_pgfgo_kernel_sgf_game_int {##1} \__pgfgo_sgfprob_prepare:n {#2} \__pgfgo_sgfprob_head:n {##1} \__pgfgo_sgfprob_statement: } } \bool_if:NT \l__pgfgo_sgfprob_solutions_bool { \seq_map_inline:Nn \l__pgfgo_sgfprob_games_seq { \int_set:Nn \l_pgfgo_kernel_sgf_game_int {##1} \__pgfgo_sgfprob_prepare:n {#2} \__pgfgo_sgfprob_head:n {##1} \seq_map_indexed_inline:Nn \l__pgfgo_sgfprob_paths_seq {\__pgfgo_sgfprob_solution:nn {####1} {####2}} } } \pgfgo_layout_end: \__pgfgo_sgfdiag_after_flush: \group_end: } \NewDocumentCommand{\sgfproblem}{O{}m}{ \__pgfgo_sgf_if_kernel:n {\pgfgo_sgfproblem:nn {#1} {#2}} } \ExplSyntaxOff