Problemas al expandir una variable dentro de un `\foreachitem` usando el paquete `listofitems` y una macro

Problemas al expandir una variable dentro de un `\foreachitem` usando el paquete `listofitems` y una macro

Siguienteesta respuesta de @ StevenB.Segletes, quien también es uno de los creadores del paquete.listofitems, ahora estoy intentando usar lo que ese paquete pudo analizar desde una sola ramaSGFcadena dentro de una macro.

Esto es lo que me gustaría poder lograr, pero creo que tengo problemas de expansión porque recibo un Missing \endcsname insertederror:

\long\def\Firstof#1#2\endFirstof{#1}
\ignoreemptyitems
\newcommand{\parseSgf}[1]{
  \setsepchar{;/[||]}
  \readlist*\Z{#1}

  % This loop basically splits on `;`, which is a node/move delimiter in SGF
  \foreachitem \i \in \Z[]{
    \itemtomacro\Z[\icnt, 1]\stoneColor
    \itemtomacro\Z[\icnt, 2]\sgfCoords

    % These if's test the `key[value]` SGF format for the keys `B` and `W`, which denote Black and White moves, respecitvely
    % Other keys typically refer to metadata, or other secondary info.
    \if\stoneColor B
      \drawStoneFromSgfCoords{black}{\sgfCoords} % if I hardcode the arguments, it works.
      % \drawStoneFromSgfCoords{black}{Z[\icnt, 2]} % I've also tried stuff like this directly...
    \fi
    \if\stoneColor AB
      \drawStoneFromSgfCoords{black}{\sgfCoords}
    \fi
    \if\stoneColor W
      \drawStoneFromSgfCoords{white}{\sgfCoords}
    \fi
    \if\stoneColor AW
      \drawStoneFromSgfCoords{white}{\sgfCoords}
    \fi
  }
}

Idealmente, si alguien puede encontrar una solución a esto, me gustaría que encontrara movimientos blancos o negros ( By W) y piedras editadas (agregadas) ( ABy AW), por lo que los if se verían así:

\if\stoneColor { B \OR AB }
...
\if\stoneColor { W \OR AW }

Pero, por supuesto, puedo guardar esto para otra pregunta, si llega a ser demasiado.


Aquí tienes un ejemplo completo:

\documentclass{article}

\usepackage{tikz}

% From [this answer by @DavidCarlisle](https://tex.stackexchange.com/a/708876/64441).
\newcommand\notwhite{black}
\newcommand\notblack{white}

% From [this answer by @DavidCarlisle](https://tex.stackexchange.com/a/708893/64441).
\ExplSyntaxOn
  \cs_generate_variant:Nn \int_from_alph:n {e}

  \NewExpandableDocumentCommand{\stringToCoordX}{ m }{
    \int_from_alph:e { \use_i:nn #1 }
  }
  \NewExpandableDocumentCommand{\stringToCoordY}{ m }{
    \int_from_alph:e { \use_ii:nn #1 }
  }
\ExplSyntaxOff

\newcommand{\drawStoneFromSgfCoords}[2]{
  \pgfmathsetmacro{\x}{\stringToCoordX{#2} - 1}
  \pgfmathsetmacro{\y}{\stringToCoordY{#2} - 1}

  \draw[draw = \UseName{not#1}, fill = #1, line width = 0.1mm]
    (\x * 10cm / 18, \y * 10cm / 18)
    circle [radius = 0.2575cm];
}

\usepackage{listofitems}

% From [this answer by @StevenB.Segletes](https://tex.stackexchange.com/a/709014/64441).
\long\def\Firstof#1#2\endFirstof{#1}
\ignoreemptyitems
\newcommand{\parseSgf}[1]{
  \setsepchar{;/[||]}
  \readlist*\Z{#1}

  \foreachitem \i \in \Z[]{
    \itemtomacro\Z[\icnt, 1]\color
    \itemtomacro\Z[\icnt, 2]\sgfCoords

    \expandafter\if\expandafter\Firstof\stoneColor\endFirstof B
      \drawStoneFromSgfCoords{black}{ab}
    \else\expandafter\if\expandafter\Firstof\stoneColor\endFirstof W
      \drawStoneFromSgfCoords{white}{cd}
    \fi\fi
  }
}

\def\sgfA{;B[ab];W[cd]} % not truly valid SGF, just one simple example
\def\sgfB{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs])}
\def\sgfC{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs];PL[W]AB[dq]AW[eq])}

\begin{document}
  \begin{tikzpicture}
    \pgfmathsetmacro{\step}{10 / 18}

    \draw[step=\step] (0, 0) grid (10, 10);

    % \drawStoneFromSgfCoords{black}{ab}
    % \drawStoneFromSgfCoords{white}{cd}
    
    \parseSgf{\sgfA}
  \end{tikzpicture}
\end{document}

Respuesta1

Varios asuntos:

  1. No lo use \color, ya que sobrescribe una macro existente... La cambié a \Color.

  2. El valor de \Colorserá Bo W, que no es un color real. Por eso, introduzco \newcommand\thecolorofB{black}y \newcommand\thecolorofW{white}convierto \Coloren un color real.

  3. Los paréntesis en las definiciones del SGF también están causando un problema. No estaban siendo analizados, sino interpretados como comandos SGF (pero faltando el []dato asociado). Por lo tanto, programé el análisis para digerirlos. Este enfoque resuelve el problema inmediato, pero puede no ser adecuado dependiendo de dónde quiera llevar este problema en el futuro.

  4. Los valores de \Colory \sgfCoordsdebían ampliarse antes de enviarlos a su macro \drawStoneFromSgfCoords. Logré esto expandiéndolos \tmpy luego expandiéndolos \tmpa la macro invocación.

El MWE:

\documentclass{article}

\usepackage{tikz}

% From [this answer by @DavidCarlisle](https://tex.stackexchange.com/a/708876/64441).
\newcommand\notwhite{black}
\newcommand\notblack{white}

% From [this answer by @DavidCarlisle](https://tex.stackexchange.com/a/708893/64441).
\ExplSyntaxOn
  \cs_generate_variant:Nn \int_from_alph:n {e}

  \NewExpandableDocumentCommand{\stringToCoordX}{ m }{
    \int_from_alph:e { \use_i:nn #1 }
  }
  \NewExpandableDocumentCommand{\stringToCoordY}{ m }{
    \int_from_alph:e { \use_ii:nn #1 }
  }
\ExplSyntaxOff

\newcommand{\drawStoneFromSgfCoords}[2]{%
  \pgfmathsetmacro{\x}{\stringToCoordX{#2} - 1}
  \pgfmathsetmacro{\y}{\stringToCoordY{#2} - 1}
%
  \draw[draw = \UseName{not#1}, fill = #1, line width = 0.1mm]
    (\x * 10cm / 18, \y * 10cm / 18)
    circle [radius = 0.2575cm];
}

\usepackage{listofitems}

% From [this answer by @StevenB.Segletes](https://tex.stackexchange.com/a/709014/64441).
\long\def\Firstof#1#2\endFirstof{#1}
\newcommand\thecolorofB{black}
\newcommand\thecolorofW{white}
\ignoreemptyitems
\newcommand{\parseSgf}[1]{%
  \setsepchar{;||(||)/[||]}%
  \readlist*\Z{#1}%
%
  \foreachitem \i \in \Z[]{%
    \itemtomacro\Z[\icnt, 1]\Color
    \itemtomacro\Z[\icnt, 2]\sgfCoords
    \edef\tmp{{\csname thecolorof\Color\endcsname}{\sgfCoords}}%
%
    \expandafter\if\expandafter\Firstof\Color\endFirstof B
      \expandafter\drawStoneFromSgfCoords\tmp
    \else\expandafter\if\expandafter\Firstof\Color\endFirstof W
      \expandafter\drawStoneFromSgfCoords\tmp
    \fi\fi
  }%
}

\def\sgfA{;B[ab];W[cd]}
\def\sgfB{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs])}
\def\sgfC{(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[6.5]SZ[19]DT[2024-02-05];B[as];W[bs];B[cs];PL[W]AB[dq]AW[eq])}

\begin{document}
  \begin{tikzpicture}
    \pgfmathsetmacro{\step}{10 / 18}
    \draw[step=\step] (0, 0) grid (10, 10);
    \parseSgf{\sgfC}
  \end{tikzpicture}
\end{document}

ingrese la descripción de la imagen aquí

información relacionada