![生成图表时出现 foreach 循环错误](https://linux22.com/image/397769/%E7%94%9F%E6%88%90%E5%9B%BE%E8%A1%A8%E6%97%B6%E5%87%BA%E7%8E%B0%20foreach%20%E5%BE%AA%E7%8E%AF%E9%94%99%E8%AF%AF.png)
在我之前的问题中,如何使用 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 页
(第 2 页具有与第 1 页相同的图表,因为输入数据相同)
第 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
参数说明符的作用以及为什么它们不能在这样或那样的情况下使用。
脚注:
非常短;你可以跳过文档风格此时。
具体来说,字符和类别代码、标记、如何将输入中的字符转换为标记以及如何处理生成的标记流(其中一部分是扩展的概念)
\edef
、、\csname
和\string
。