1

I'm having a really hard time understanding this error in a massive document. I took the time to work out a "minimal example", so I could post the error with precision. Please, when trying to answer, do not change the structure, assuming this "toy example" could be rearranged easily. Thanks a lot. Here the example. Bellow it I would explain more about the attempts.

% By Dr. Beco - 60 games
\documentclass[a4paper,12pt]{article}

\usepackage[utf8]{inputenc} % accented chars
\usepackage[english]{babel} % translations
\usepackage{graphicx} % includegraphics
\usepackage[ps]{skak} % chess
\usepackage{float} % figure[H]
\usepackage{xstring} % get tokens

%%%%%%%%%%%%%%%%%%%%% define \variable = value
\newcommand{\setvalue}[2]
{
    \ifdefined #1
        \renewcommand{#1}{#2}
    \else
        \newcommand{#1}{#2}
    \fi
}

%%%%%%%%%%%%%%%%%%%%% fill all needed variables for a section
\newcommand{\setsec}[6]
{
  \setvalue{\gnumber}{#1}
  \setvalue{\gcolor}{#2}
  \setvalue{\gdate}{#3}
  \setvalue{\gresult}{#4}
  \setvalue{\gopening}{#5}
  \setvalue{\gfirstmoves}{#6}
  \mysec{\gnumber}{\gcolor}{\gdate}{\gresult}{\gopening}{#6}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%% inicia seção
% parâmetros:
% #1 num. jogo
% #2 minha cor (W ou B)
% #3 Data
% #4 resultado (1:brancas, 0:pretas, 2:empate)
% #5 ECO code seguido do nome da abertura
% #6 Linha principal para mostrar a abertura
\newcommand{\mysec}[6]
{
  \section*{Code #1#2, date: #3 result: #4 opening: #5}
  \mygamesi{#1}{#2}{#5}{#6}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \mygamesi{Game Number}{Color}{Opening}{Moves}
\newcommand{\mygamesi}[4]
{
  \newgame
  \mainline{#4}
  \begin{figure}[H]
  \centering
  \showboard
  \caption{#1#2, #3}
  \label{g1}
  \end{figure}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% show some variation on board
% #1 game number \gnumber
% #2 my color \gcolor
% #3 #2 label key for \ref{}
% #4 #3 variation to show (board and caption)
% optional #1 : s=show full var in caption, h=hide, only last move in caption
\newcommand{\myvar}[3][h]
{
  \storegame{mainline}
  \hidemoves{#3}
  \begin{figure}[H]
  \centering
  \showboard

  \ifthenelse{\equal{#1}{s}}{\caption{opt S:position after variation \protect\movecomment{#3}}}{}
  \ifthenelse{\equal{#1}{h}}{\caption{opt H:position after variation \protect\movecomment{\protect\StrBefore[2]{#3}{ }} ... \lastmove{}}}{} %<<<<<<<<<<<<<<<<<

  \label{gv}
  \end{figure}
  \restoregame{mainline}
}

%%%%%%%%%%%%%%%%%%%%%%%%%% fim de seção
% #1 num. jogo \gnumber
% #2 minha cor (W ou B) \gcolor
\newcommand{\myend}
{
  \begin{figure}[H]
%   \includegraphics{\gnumber-graph.png}
[altern. text: evaluation graph]
  \caption{\gnumber\gcolor, evaluation graph}
  \label{ge}
  \end{figure}
}

\tinyboard

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}

\setsec{1}{B}{2017.17.17}{0}{B00 Strange Defense}{1. e3 e5 2. d3 d4 3. Nc3 Bb4}

It was a serious game.

\mainline{4. a3 Bxc3+ 5. bxc3 dxe4 6. Qg4 Nf6 7. Qxg7
Rg8 8. Qh6 c5 9. Bg5 Ng4 }

after \variationcurrent{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7} you can see:

my var show:

\myvar[s]{v1}{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7}

my var hide:

\myvar[h]{v1}{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7}

White resigns

\myend

\end{document}
  • Note: We are using PDFLatex
  • The line with error is marked with %<<<<<<<<<<<<<<<<<

What I expect it to do

  • \myvar[s] would show all chess moves inside the caption. That is working fine.
  • \myvar[h] would show just the first move of the string, 3 dots, and the last move. That is unachievable.

The problem is that I can't give the skak command \movecomment{} a variable inside caption.

I've tried all combinations of \def and \edef, but I don't really understand those, so I prefer a LaTeX approach. I've tried \newcommand and DeclareRobustCommand also, and adding and removing \protect in many places on the way.

The idea is very simple: given a string with moves, say "1. e4 e5 2. d4 d5", I want the "first move", that is "1. e4". The skak package gives a lastmove that works inside captions, I even read its code. But I can't understand it to adapt.

My simple solution would be:

For example:

  • \StrBefore[2]{#1}{ }[\firstmove]

and then

  • \movecomment{\firstmove}

But who says this works? I've being trying and reading about this expansions and macros for sometime now, but I can't work it out.

Thanks any help.


Edited:

Also something that isn't working:

\newcommand{\setsec}[6]
{
  \setvalue{\gnumber}{#1}
  \setvalue{\gcolor}{#2}
  \setvalue{\gdate}{#3}
  \setvalue{\gresult}{#4}
  \setvalue{\gopening}{#5}
  \setvalue{\gfirstmoves}{#6}
  \mysec{\gnumber}{\gcolor}{\gdate}{\gresult}{\gopening}{#6}
}

The last line should really be:

  \mysec{\gnumber}{\gcolor}{\gdate}{\gresult}{\gopening}{\gfirstmoves}

but alas...


Current solution (workaround)

  • Inside command \myvar:

       \ifthenelse{\equal{#1}{s}}{\caption{THEN: position after variation \protect\movecomment{#3}}}{\caption{ELSE: position after variation \protect\movecomment{#1} \ldots\ \lastmove{}}}
    
  • If the whole line is to be in caption:

        \myvar[s]{v1}{10. Qc4+ Kb8 11. Qd3 Qf6 12. Rd1 Qxf2}
         % or
         \myvar{v1}{10. Qc4+ Kb8 11. Qd3 Qf6 12. Rd1 Qxf2}
    
  • If only first and last move is to be in caption:

        \myvar[22. Qc4+]{v1}{10. Qc4+ Kb8 11. Qd3 Qf6 12. Rd1 Qxf2}
    

Edited: removed package multicolumn - not a minimum example after all. ;)

  • You use commands \mysec and \myend to enclose \begin{} and \end{} calls. I cannot help but believe that somewhere this approach will cause a crash. My understanding is that a better approach will be obtained by generating environments where the beginning and ending are not separated (and not themselves called within \newcommand). Have you tried using the built-in \newenvironment command or using commands in \usepackage{environ}? – Jeffrey J Weimer Sep 29 '18 at 14:35
  • I see your point and I'm working towards this, probably I'll even need another question here somewhere in the future, but I'm optimist I can deal with that later. But this point is not related to this question itself. Please, if you can ofc, a little light in the passing parameters. – Dr Beco Sep 29 '18 at 14:40
  • I've removed the package "multicolumn" from the "Minimal" example now. Thanks for poiting that out. – Dr Beco Sep 29 '18 at 14:44
  • The problem I face is, the approach is complex. I cannot honestly follow it as one who writes code (e.g. python), let alone as one who is at an intermediate level of working with LaTeX. And then we must not change the code. Gosh! I believe that you will do better with what is called a "nuke and repave". As a coder, I say to avoid \newcommand functions that require so many parameters all at once and then pass them to other \newcommand functions that themselves perhaps need yet other parameters. For LaTeX, avoid using approaches that are known to break LaTeX in even basic cases. – Jeffrey J Weimer Sep 29 '18 at 14:54
  • Thanks Jeffrey. If it helps you to just give it a try, focus on \StrBefore[2]{#1}{ }[\firstmove] where #1 is the string 1. e4 e5 2. d4 d5 and \movecomment{\firstmove} inside a caption. Any help is appreciated. Try to compile the code and, of course, you can change the code. Change any function. Any ideas I can get may help me to adapt it. – Dr Beco Sep 29 '18 at 15:37
1

This is a better MWE of the problem.

\documentclass[a4paper,12pt]{article}

\usepackage[ps]{skak} % chess
\usepackage{xstring} % get tokens

\begin{document}

Extracted String: \StrBefore[2]{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7}{ }

Move Comment: \movecomment{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7}

Reduced Move Comment: \movecomment{\StrBefore[2]{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7}{ }}

\end{document}

I believe this may show a fundamental issue within \movecomment. It may need a clever use of \expandafter. My attempts to solve it as such have failed.

Once the above works, you want to put this in yet another macro and use positional parameters. And then that gets put in yet another macro call that passes those parameters. I honestly fail to see that what you are doing is truly a best approach. I instead see an over-engineered approach that does not work directly at a minimum level, requires as-yet-unknown TeX-level primitive commands to force it to work even at a minimum level, and may then give even more problems once it is encapsulated in yet another layer of macros (upon macros upon macros) with positional parameters.

Ugh!

Here is a starting point to a cleaner approach. First, I avoid calling macros from within macros as well as passing parameters from one macro to another and then to yet another. Rather than struggle with searching the string to remove a part after a space, I just specify what is always wanted and what may be chosen to be hidden. Granted, you state this latter approach is a "work-around". I would however honestly take this "work-around" solution over what you are trying to do any day, even when what you have would work. Today the value of the position for the space you want to skip is [2]. Tomorrow, you may decide for your third example that skip value should be to [3]. Then, you have to re-hard code the LaTeX document to handle the case only at that point. In the approach below, you just have to change what is passed to the second and third parameters of the macro \myvar.

\documentclass[a4paper,12pt]{article}

\usepackage{graphicx} % includegraphics
\usepackage[ps]{skak} % chess
\usepackage{float} % figure[H]

\setlength{\parindent}{0em}

\newcommand{\setvalue}[2]
{
    \ifdefined #1
        \renewcommand{#1}{#2}
    \else
        \newcommand{#1}{#2}
    \fi
}

\newcommand{\setsec}[5]
{
  \setvalue{\gnumber}{#1}
  \setvalue{\gcolor}{#2}
  \setvalue{\gdate}{#3}
  \setvalue{\gresult}{#4}
  \setvalue{\gopening}{#5}
  \section*{Code \gnumber\gcolor, date: \gdate result: \gresult opening: \gopening}
}

\newcommand{\mygamesi}[1]
{
  \setvalue{\gfirstmoves}{#1}
  \newgame
  \mainline{#1}
  \begin{figure}[H]
  \centering
  \showboard
  \caption{\gnumber{}\gcolor{}\gdate{}}
  \label{g1}
  \end{figure}
}

\newcommand{\myvar}[3][h]
{
  \storegame{mainline}
  \hidemoves{#2 #3}
  \begin{figure}[H]
  \centering
  \showboard
  \ifthenelse{\equal{#1}{s}}
  {\caption{opt S:position after variation \protect\movecomment{#2\ #3}}}
  {\caption{opt H:position after variation \protect\movecomment{#3}} ... \lastmove{}}
  \label{gv}
  \end{figure}
  \restoregame{mainline}
}

\newcommand{\myend}
{
  \begin{figure}[H]
%   \includegraphics{\gnumber-graph.png}[altern. text: evaluation graph]
  \caption{\gnumber\gcolor, evaluation graph}
  \label{ge}
  \end{figure}
}

\tinyboard

\begin{document}

\setsec{1}{B}{2017.17.17}{0}{B00 Strange Defense}

\mygamesi{1. e3 e5 2. d3 d4 3. Nc3 Bb4}

It was a serious game.

\mainline{4. a3 Bxc3+ 5. bxc3 dxe4 6. Qg4 Nf6 7. Qxg7
Rg8 8. Qh6 c5 9. Bg5 Ng4 }

after \variationcurrent{10. Qxh7 Qxg5 11. Qxe4 Nf6 12. Bb5+ Nbd7} you can see:

my var show:

\myvar[s]{10. Qxh7 Qxg5}{11. Qxe4 Nf6 12. Bb5+ Nbd7}

my var hide:

\myvar[h]{10. Qxh7 Qxg5}{11. Qxe4 Nf6 12. Bb5+ Nbd7}

White resigns
%
%\myend

\end{document}

I remain curious that someone will post a solution to the MWE that I have posted. But I'm not holding my breath.

  • This seems to provide a document that compiles, but doesn't answer the question. – Werner Sep 30 '18 at 18:01
  • Thanks, but this solution is already mentioned inside the question itself: Current solution (workaround). – Dr Beco Oct 1 '18 at 17:59
  • As a workaround, it is fine, but I use latex for a long time now and I'm really wondering the intrinsic problem bellow this example. Why I can't figure out how to extract a part of a string and use it as parameter to call as many macros as I want, transparently. Somewhere in the cold there should be a trick to protect everything and work this out. – Dr Beco Oct 1 '18 at 18:00
  • I leave my example posted, if nothing else because you were open to cleaner implementations of the approach that you took. – Jeffrey J Weimer Oct 2 '18 at 1:27
  • Thanks a lot Jeffrey I +1 your answer and I'll wait also for some good soul to tackle the kernel of the problem (without holding my breath). If we can't find a solution, yours will be accepted in the (hopefully no so long) future. – Dr Beco Oct 3 '18 at 20:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.