Цикл по массиву строк (на самом деле массив массивов строк, например `{{black, ab}, {white, cd}}`)

Цикл по массиву строк (на самом деле массив массивов строк, например `{{black, ab}, {white, cd}}`)

Я рисую камни на доске для игры в Го.СГФкоординаты (что мне удалось сделать только благодаря помощи, которую мне дали люди наэтот вопрос) так \drawStoneFromSgfCoords{ab}.

Однако на одной диаграмме может быть много камней, поэтому было бы практично иметь еще один макрос, например такой: \drawStonesFromSgfCoords{{black, ab}, {white, cd}}(цвета обычно чередуются, но иногда практичнее иметь список черных координат, а затем белых).

Вот что я сейчас пробую, хотя это не работает (я имею в виду, это работает, просто не с новым макросом):

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

  \newcommand\stringToCoordX[1]{
    \int_from_alph:e{\use_i:nn#1}
  }
  \newcommand\stringToCoordY[1]{
    ~\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];
    node[color = white] {1};
}

% Example usage: `drawStonesFromSgfCoords{{black, ab}, {white, cd}}`
\newcommand{\drawStonesFromSgfCoords}[1]{
  \foreach \coords in {#1}{
    \drawStoneFromSgfCoords{{\coords}[0]}{{\coords}[1]}
  }
}

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

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

    \drawStoneFromSgfCoords{black}{ab}
    \drawStoneFromSgfCoords{white}{cd}
    
    % \drawStonesFromSgfCoords{{black, ab}, {white, cd}}
  \end{tikzpicture}
\end{document}

Каков правильный способ доступа к массивам или их передачи (внутри цикла)?

(Я использую PGF, \foreachпотому что я это знаю.)

решение1

Я думаю, что было бы лучше обрабатывать вложенный clistсписок (разделенный запятыми) с помощью инструментов expl, поскольку там уже существуют инструменты для обработки таких списков:

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

\ExplSyntaxOn
  % Example usage: `drawStonesFromSgfCoords{{black, ab}, {white, cd}}`
  \NewExpandableDocumentCommand{\drawStonesFromSgfCoords}{ m }{
    \clist_set:Nn \l_tmpa_clist { #1 }
    \clist_map_inline:Nn \l_tmpa_clist {
      \clist_set:Nn \l_tmpb_clist { ##1 }
      \clist_pop:NN \l_tmpb_clist \l_tmpa_tl 
      \clist_pop:NN \l_tmpb_clist \l_tmpb_tl 
      \exp_args:Noo \drawStoneFromSgfCoords { \l_tmpa_tl } { \l_tmpb_tl }
      
    }
  }
\ExplSyntaxOff

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

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

    %\drawStoneFromSgfCoords{black}{ab}
    %\drawStoneFromSgfCoords{white}{cd}
    \drawStonesFromSgfCoords{{black, ab}, {white, cd}}
    
  \end{tikzpicture}
\end{document}

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


Некоторые заметки об используемых командах (хороший обзор и исчерпывающую документацию можно найти вИнтерфейсы L3 PDF):

  • \clist_set:Nn \l_tmpa_clist { #1 }сохраняет clist(список, разделенный запятыми) в переменной токена, чтобы сделать его доступным. В примере {{black, ab}, {white, cd}}хранится как clistв переменной токена \l_tmpa_clist.
  • \clist_map_inline:Nn \l_tmpa_clist { ... }цикл по каждому элементу в clist(хранится в переменной token) и выполняет код между фигурными скобками. Текущий элемент доступен через #1( ##1в примере кода, потому что он вложен на один уровень глубже).
  • \clist_pop:NN \l_tmpb_clist \l_tmpa_tlберет первый элемент из clistи сохраняет его в переменной токена ( l_tmpa_tl). Затем он удаляет этот элемент из clist.
  • \exp_args:Noo \drawStoneFromSgfCoords { \l_tmpa_tl } { \l_tmpb_tl }сначала расширяет две переменные токена и вставляет результат в качестве аргументов в \drawStoneFromSgfCoords.

Итак, давайте посмотрим, что произойдет шаг за шагом, если мы скажем \drawStonesFromSgfCoords{{black, ab}, {white, cd}}:

\NewExpandableDocumentCommand{\drawStonesFromSgfCoords}{ m }{

    % store {{black, ab}, {white, cd}} in \l_tmpa_clist 
    \clist_set:Nn \l_tmpa_clist { #1 }

    % loop over items in \l_tmpa_clist 
    \clist_map_inline:Nn \l_tmpa_clist {

      % store {black, ab} in \l_tmpb_clist
      \clist_set:Nn \l_tmpb_clist { ##1 }

      % store black in \l_tmpa_tl and remove item from clist
      \clist_pop:NN \l_tmpb_clist \l_tmpa_tl 

      % store ab in \l_tmpb_tl and remove item from clist
      \clist_pop:NN \l_tmpb_clist \l_tmpb_tl 

      % expand \l_tmpa_tl and \l_tmpb_tl so that we get
      % \drawStoneFromSgfCoords{black}{ab}
      \exp_args:Noo \drawStoneFromSgfCoords { \l_tmpa_tl } { \l_tmpb_tl }

      % repeat this loop for the next item in the clist in \l_tmpa_clist

    }
}

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