0

I'm drawing stones on a Go (game) board with SGF coordinates (which I only managed to do from the the help people gave me on this question) like this \drawStoneFromSgfCoords{ab}.

However, there might be many stones per diagram, so it would be practical to also have another macro like this: \drawStonesFromSgfCoords{{black, ab}, {white, cd}} (the colors typically alternate, but sometimes it's more practical to have a list of black coordinates and then white's).

Here's what I'm trying right now, though it doesn't work (I mean, it does work, just not with the new macro):

\documentclass{article}

\usepackage{tikz}

% From this answer by @DavidCarlisle. \newcommand\notwhite{black} \newcommand\notblack{white}

% From this answer by @DavidCarlisle. \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}

What's the proper way of accessing or passing arrays (within a loop)?

(I'm using PGF's \foreach because that's what I know.)

psygo
  • 438

1 Answers1

1

I think, it is a better idea to process the nested clist (a comma-separated list) via expl tools here since tools already exist there to handle such lists:

\documentclass{article}
\usepackage{tikz}

% From this answer by @DavidCarlisle. \newcommand\notwhite{black} \newcommand\notblack{white}

% From this answer by @DavidCarlisle. \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}

enter image description here


Some notes on the used commands (a nice overview and an exhaustive documentation can be found in the L3 Interfaces PDF):

  • \clist_set:Nn \l_tmpa_clist { #1 } stores a clist (a comma-separated list) in a token variable to make it accessible. In the example case, {{black, ab}, {white, cd}} is stored as clist in the token variable \l_tmpa_clist.
  • \clist_map_inline:Nn \l_tmpa_clist { ... } loops over every item in the clist (stored in the token variable) and executes the code between the curly braces. The current item is accessed via #1 (##1 in the code example, because it is nested one level deeper).
  • \clist_pop:NN \l_tmpb_clist \l_tmpa_tl grabs the first item of the clist and stores it in a token variable (l_tmpa_tl). It then removes this item from the clist.
  • \exp_args:Noo \drawStoneFromSgfCoords { \l_tmpa_tl } { \l_tmpb_tl } first expands the two token variables and inserts the result as arguments to \drawStoneFromSgfCoords.

So, lets look what happens step by step if we say \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

}

}

  • Do you mind me asking about tips on how to understand this expl3 syntax? Could you maybe write some bullet points on what exactly those macros do? I feel like if the problem changes slightly I wouldn't be able to adapt this by myself at all. – psygo Feb 07 '24 at 15:22
  • 1
    @PhilippeFanaro I added some explanations for the code I added to the existing code. – Jasper Habicht Feb 07 '24 at 15:33
  • Amazing. You went above and beyond. Thank you so much for the helpful explanations! – psygo Feb 07 '24 at 16:32