使用包“listofitems”和宏扩展“\foreachitem”内的变量时出现问题

使用包“listofitems”和宏扩展“\foreachitem”内的变量时出现问题

下列的这个答案来自@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
  }
}

理想情况下,如果有人能够找到解决这个问题的方法,我希望它能够找到黑棋或白棋移动(BW)以及编辑(添加)的石头(ABAW),因此 if 看起来会像这样:

\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将是BW,这不是实际颜色。因此,我引入\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}

在此处输入图片描述

相关内容