生成图表时出现 foreach 循环错误

生成图表时出现 foreach 循环错误

在我之前的问题中,如何使用 minipage 设置循环宏?,有人建议我使用 foreach 循环来解决问题。经过测试,循环工作正常,如第 1 页 pdf 中所示。但是,当添加更多 FEN 时,循环会给出错误的格式,如 pdf 2 和 3 中所示。任何关于如何修复 foreach 循环的建议都值得赞赏。

\documentclass{article}
\usepackage{xskak,chessboard}
\usepackage[margin=3cm]{geometry}
\begin{document}

%**** WORKSHEET 1 IS CORRECT; WORKSHEET 2 AND 3 IS WRONG ******
%********************************************************
%******CORRECT WORKSHEET USING FOREACH LOOP *******

\foreach \X/\Y in 
{basic/{3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
%******* PAWN LEVEL *****************
pawn/{8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
%************ 2 PAWN LEVEL *******************
2 pawns/{8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
%************ MINOR + PAWN LEVEL ********************
Minor + Pawns/{4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
 8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1}}
{\noindent\tikz{\node[rotate=90,font=\bfseries,align=center,text width=4cm]{\X};}
\foreach \Z in \Y
{\begin{minipage}[b]{0.35\linewidth}
\chessboard[smallboard,setfen=\Z]
\end{minipage}}

}
%****** WHEN NEW FENS ARE ADDED, FOREACH LOOP GETS WRONG. WORKSHEET IS NOT SAME AS **
%**** PREVIOUS WORKSHEET *****
\foreach \X/\Y in 
{basic/{3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
basic/{3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
%******* PAWN LEVEL *****************
pawn/{8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
pawn/{8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
%************ 2 PAWN LEVEL *******************
2 pawns/{8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
2 pawns/{8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
%************ MINOR + PAWN LEVEL ********************
Minor + Pawns/{4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1},
Minor + Pawns/{4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1}}
{\noindent\tikz{\node[rotate=90,font=\bfseries,align=center,text width=4cm]{\X};}
\foreach \Z in \Y
{\begin{minipage}[b]{0.35\linewidth}
\chessboard[smallboard,setfen=\Z]
\end{minipage}}
\par
}
\end{document}

答案1

这是一个解决方案expl3

\documentclass{article}
\usepackage{chessboard}
\usepackage{xskak}
\usepackage[margin=2cm]{geometry}
\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn

\msg_new:nnn { mychess } { groups-have-different-number-of-series }
  { all~groups~must~have~the~same~number~of~series~ (found~\exp_not:n {#1}~
    and~\exp_not:n {#2}). }

\seq_new:N \g_mychess_groups_seq

\cs_new_protected:Npn \mychess_define_groups:n #1
  {
    \seq_gset_from_clist:Nn \g_mychess_groups_seq {#1}
  }

% #1: group name (A, B, C, ...)
% #2: diagram data for this group (a comma list)
\cs_new_protected:Npn \mychess_set_group_diagrams:nn #1#2
  {
    \seq_gclear_new:c { g_mychess_group_#1_seq }
    \seq_gset_from_clist:cn { g_mychess_group_#1_seq } {#2}
  }

% Expand to the number of series declared for group #1
\cs_new:Npn \mychess_nb_series_for_group:n #1
  {
    \seq_count:c { g_mychess_group_#1_seq }
  }

\cs_generate_variant:Nn \mychess_nb_series_for_group:n { V }
\cs_generate_variant:Nn \msg_error:nnnn { nnVx }

\tl_new:N \l__mychess_a_group_tl
\int_new:N \l__mychess_nb_series_int

\cs_new_protected:Npn \mychess_print_all_diagrams:
  {
    % Get the name of the first group and the number of series declared for
    % this group (any other group would do, as they must have the same number
    % of series---which we are going to check right now as a safety measure
    % against invalid user input).
    \seq_get_left:NN \g_mychess_groups_seq \l__mychess_a_group_tl
    \int_set:Nn \l__mychess_nb_series_int
      { \mychess_nb_series_for_group:V \l__mychess_a_group_tl }

    % Check that the same number of series was defined for each group, and
    % print an error message if this is not the case.
    \seq_map_inline:Nn \g_mychess_groups_seq
      {
        \int_compare:nNnF
          { \mychess_nb_series_for_group:n {##1} }
          =
          { \l__mychess_nb_series_int }
          {
            \msg_error:nnVx { mychess }
              { groups-have-different-number-of-series }
              \l__mychess_nb_series_int
              { \mychess_nb_series_for_group:n {##1} }
          }
      }

    % Print all diagrams in series order, then in group order inside each
    % series.
    \int_step_function:nN { \l__mychess_nb_series_int }
      \mychess_print_diagrams_for_series:n
  }

\seq_new:N \l__mychess_print_one_diagram_set_tmp_seq

% #1: group name
% #2: data (a comma list: of rounds? Not sure about what the data represents)
\cs_new_protected:Npn \mychess_print_one_diagram_set:nn #1#2
  {
    \par \noindent
    \tikz { \node[rotate=90,font=\bfseries,align=center,text~width=4cm] {#1}; }
    \seq_set_from_clist:Nn \l__mychess_print_one_diagram_set_tmp_seq {#2}
    \seq_map_inline:Nn \l__mychess_print_one_diagram_set_tmp_seq
      {
        \chessboard[smallboard,setfen=##1]
        \skip_horizontal:n { \fill }
      }
    \par
  }

\cs_generate_variant:Nn \mychess_print_one_diagram_set:nn { nx }

% #1: 1 for the first series, 2 for second, etc.
\cs_new_protected:Npn \mychess_print_diagrams_for_series:n #1
  {
    \seq_map_inline:Nn \g_mychess_groups_seq
      {
        \mychess_print_one_diagram_set:nx
          {##1}                 % group name
          { \seq_item:cn { g_mychess_group_##1_seq } {#1} }
      }
  }

% Processing the “big structure”
\seq_new:N \g__mychess_rosfg_discovered_groups_seq

% #1: group name
% #2: data (a comma list: of rounds? Not sure about what the data represents)
\cs_new_protected:Npn \mychess_read_one_series_for_group:nn #1#2
  {
    \seq_if_in:NnF \g__mychess_rosfg_discovered_groups_seq {#1}
      { % First time we see group #1 in the “big structure”
        \seq_gput_right:Nn \g__mychess_rosfg_discovered_groups_seq {#1}
        % Clear all data for this group
        \seq_gclear_new:c { g_mychess_group_#1_seq }
      }

    % Append the data to what we already have for this group
    \seq_gput_right:cn { g_mychess_group_#1_seq } {#2}
  }

\cs_generate_variant:Nn \mychess_read_one_series_for_group:nn { VV }

\cs_new_protected:Npn \mychess_read_big_structure:n #1
  {
    \seq_gclear:N \g__mychess_rosfg_discovered_groups_seq

    \foreach \group / \data in {#1}
      { \mychess_read_one_series_for_group:VV \group \data }

    \seq_gset_eq:NN \g_mychess_groups_seq
                    \g__mychess_rosfg_discovered_groups_seq
  }

% #1: comma list of group names
\NewDocumentCommand \definegroups { m }
  {
    \mychess_define_groups:n {#1}
  }

% #1: group name
% #2: data for this group (a comma list containing one item per series, each
% item being itself a comma list describing the diagrams for the (group,
% series) combination).
\NewDocumentCommand \setgroupdiagrams { m m }
  {
    \mychess_set_group_diagrams:nn {#1} {#2}
  }

\NewDocumentCommand \readbigstructure { m }
  {
    \mychess_read_big_structure:n {#1}
  }

\NewDocumentCommand \printalldiagrams { }
  {
    \mychess_print_all_diagrams:
  }

\ExplSyntaxOff

\begin{document}

% Load the data as provided in the question
\readbigstructure{%
basic/{3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
basic/{3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
%******* PAWN LEVEL *****************
pawn/{8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
pawn/{8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
%************ 2 PAWN LEVEL *******************
2 pawns/{8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
2 pawns/{8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
%************ MINOR + PAWN LEVEL ********************
Minor + Pawns/{4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1},
Minor + Pawns/{4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1}}

% Print it
\printalldiagrams

\newpage
% Alternate input syntax written for the duplicate question:
% <https://tex.stackexchange.com/questions/497019/foreach-looping-error>
\definegroups{A, B, C, D}
\setgroupdiagrams{A}{
  {3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
   8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
   1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
  {3k4/8/2Q5/4K3/8/8/8/8 w - - 0 1,
   8/8/2k5/7R/6R1/8/5K2/8 w - - 0 1,
   1k6/7R/3K4/8/8/8/8/8 w - - 0 1},
}
\setgroupdiagrams{B}{
  {8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
   8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
   8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
  {8/8/8/8/8/1k6/7P/4K3 w - - 0 1,
   8/8/8/8/4k3/4p3/4K3/8 w - - 0 1,
   8/1k6/8/8/1PK5/8/8/8 w - - 0 1},
}
\setgroupdiagrams{C}{
  {8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
   8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
   k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
  {8/8/8/4p1K1/2k1P3/8/8/8 w - - 0 1,
   8/8/8/p7/P7/7k/7P/6K1 w - - 0 1,
   k7/P1K5/6p1/7p/7P/8/8/8 w - - 0 1},
}
\setgroupdiagrams{D}{
  {4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
   8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
   8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1},
  {4BK2/6P1/5k2/8/8/1b6/8/8 w - - 0 1,
   8/8/4k3/2p4n/2P1K3/8/7B/8 w - - 0 1,
   8/p7/P5p1/1P4P1/5P2/3kb3/8/3K4 w - - 0 1},
}
\printalldiagrams

\end{document}

第 1 页

第 1 页

(第 2 页具有与第 1 页相同的图表,因为输入数据相同)

第 3 页

第 3 页

(第 4 页的图表与第 3 页相同,因为输入数据相同)

笔记:

  • 第二次使用的替代输入语法(参见文档末尾)声明组名 A、B、C 和 D,如下所示重复的问题

  • 您可以在 之前或之后使用\readbigstructure\definegroups和,这无关紧要(与 不同,这些命令不会产生任何输出)。\setgroupdiagrams\begin{document}\printalldiagrams

如果你想学习expl3,我知道的最好的起点是expl3.pdf成立这里, 然后l3styleguide.pdf1最后是主要参考,界面3.pdf无论如何,之前阅读 TeXbook 会有很大帮助,因为许多基本的 TeX 概念2在 LaTeX3 语言中无处不在。例如,一旦你理解了\edef,你就会很清楚地知道x参数说明符的作用以及为什么它们不能在这样或那样的情况下使用。


脚注:

  1. 非常短;你可以跳过文档风格此时。

  2. 具体来说,字符和类别代码、标记、如何将输入中的字符转换为标记以及如何处理生成的标记流(其中一部分是扩展的概念)\edef、、\csname\string

相关内容