Проблемы с расширением переменной внутри `\foreachitem` с использованием пакета `listofitems` и макроса

Проблемы с расширением переменной внутри `\foreachitem` с использованием пакета `listofitems` и макроса

Следующийэтот ответ от @StevenB.Segletes, который также является одним из создателей пакетаlistofitems, теперь я пытаюсь использовать то, что этот пакет смог проанализировать из одной веткиСГФстрока внутри макроса.

Вот чего я хотел бы добиться, но, думаю, у меня возникли проблемы с расширением, потому что я получаю сообщение об Missing \endcsname insertedошибке:

\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
  }
}

В идеале, если кто-то сможет найти решение этой проблемы, я бы хотел, чтобы оно находило как ходы черных, так и ходы белых ( Bи W), а также измененные (добавленные) камни ( ABи AW), поэтому «если» будут выглядеть следующим образом:

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

Но, конечно, я могу приберечь это для другого вопроса, если он станет слишком назойливым.


Вот полный пример:

\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}

решение1

Несколько вопросов:

  1. Не используйте \color, так как он перезаписывает существующий макрос... Я изменил его на \Color.

  2. Значение \Colorбудет Bили W, что не является фактическим цветом. Поэтому я ввожу \newcommand\thecolorofB{black}и \newcommand\thecolorofW{white}для преобразования \Colorв фактический цвет.

  3. Скобки в определениях SGF также вызывают проблему. Они не анализировались, а интерпретировались как команды SGF (но без связанных []данных). Поэтому я жестко запрограммировал анализ, чтобы переварить их. Этот подход решает непосредственную проблему, но может оказаться неподходящим в зависимости от того, куда вы хотите направить эту проблему в будущем.

  4. Значения \Colorи \sgfCoordsнеобходимо было расширить, прежде чем передавать их в ваш макрос \drawStoneFromSgfCoords. Я добился этого, расширив их в \tmp, а затем расширив \tmpв вызов макроса.

МВЭ:

\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}

введите описание изображения здесь

Связанный контент