TeX - LaTeX Asked on April 12, 2021
I wanted to distinguish the control variables of different agents in a separate color so that my students can read examples more easily. To do so, I wanted to write a macro definevar{x,y;z}
that I could call at the beginning of each example to define var
before the semicolon as {color{player1} var}
and after the semicolon as {color{player2} var}
. I found in this answer how to do it for a single variable, but was surprised that this method did not extend to lists processed by the listofitems
package in a straightforward manner.
In below code, defvar
works well for a single variable, but somehow definevar
does not define the variables. If I replace foreach
with pgfplot
‘s pgfplotsforeachungrouped
, it defines the variables but initializes them all to the last input variable.
documentclass{article}
usepackage{xcolor, pgffor, listofitems}
colorlet{player1}{blue}
colorlet{player2}{red}
newcommand{defvar}[2]{
expandafterdefcsname #2endcsname{{color{player#1} #2}}
}
newcommand{definevar}[1]{
setsepchar{;/,}%
greadlist*varlist{#1}%
foreach pl in {1, ..., varlistlen} {%
foreachitem i in varlist[pl] {%
defvar{pl}{i}%
}%
}%
}
begin{document}
defvar{1}{x}
defvar{2}{y}
$x + y = 1$.
definevar{x, y; z}
$x + y = z$.
end{document}
Several issues:
defvar
needs to employ global gdef
rather than def
, since it is invoked inside of the loop groups of definevar
.
pl
and i
need to be once expanded before being used to call defvar
. Without this, the defvar
retains the literal pl
and i
rather than using their replacement texts that you desire.
The MWE repaired:
documentclass{article}
usepackage{xcolor, pgffor, listofitems}
colorlet{player1}{blue}
colorlet{player2}{red}
newcommand{defvar}[2]{
expandaftergdefcsname #2endcsname{{color{player#1} #2}}
}
newcommand{definevar}[1]{
setsepchar{;/,}%
greadlist*varlist{#1}%
foreach pl in {1, ..., varlistlen} {%
foreachitem i in varlist[pl] {%
deftmp{expandafterdefvarexpandafter{pl}}%
expandaftertmpexpandafter{i}%
}%
}%
}
begin{document}
defvar{1}{x}
defvar{2}{y}
$x + y = 1$.
definevar{x, y; z}
$x + y = z$.
end{document}
An alternate way to achieve those same goals is to use xdef
inside of defvar
instead of gdef
(as long as you noexpand
the color
). That way, inside of definevar
, you can revert to the simpler syntax, without worrying about expansions.
documentclass{article}
usepackage{xcolor, pgffor, listofitems}
colorlet{player1}{blue}
colorlet{player2}{red}
newcommand{defvar}[2]{
expandafterxdefcsname #2endcsname{{noexpandcolor{player#1} #2}}
}
newcommand{definevar}[1]{
setsepchar{;/,}%
greadlist*varlist{#1}%
foreach pl in {1, ..., varlistlen} {%
foreachitem i in varlist[pl] {%
defvar{pl}{i}%
}%
}%
}
begin{document}
defvar{1}{x}
defvar{2}{y}
$x + y = 1$.
definevar{x, y; z}
$x + y = z$.
end{document}
Correct answer by Steven B. Segletes on April 12, 2021
You can use expl3
so you don't need scratch macros.
The argument to definevar
is first split into pieces at semicolons, then each piece is examined to produce variables colored according to the piece number, you just need to define as many colors player
n as you need.
documentclass{article}
usepackage{xcolor}
colorlet{player1}{blue}
colorlet{player2}{red}
colorlet{player3}{green!60!blue}
ExplSyntaxOn
NewDocumentCommand{definevar}{m}
{
seq_set_split:Nnn l_tmpa_seq { ; } { #1 }
seq_map_indexed_inline:Nn l_tmpa_seq
{
clist_map_inline:nn { ##2 }
{
cs_set_protected:cpn { ####1 } { textcolor{player##1}{####1} }
}
}
}
ExplSyntaxOff
begin{document}
$definevar{x;y}x + y = 1$.
$definevar{x,y;z;t}x+y=z-t$.
end{document}
You might also consider the following:
documentclass{article}
usepackage{xcolor}
colorlet{player1}{blue}
colorlet{player2}{red}
colorlet{player3}{green!60!blue}
ExplSyntaxOn
NewDocumentCommand{definevar}{m}
{
seq_set_split:Nnn l_tmpa_seq { ; } { #1 }
seq_map_indexed_inline:Nn l_tmpa_seq
{
clist_map_inline:nn { ##2 }
{
cs_set_protected:cx { __olafsson_var_####1: }
{
exp_not:N textcolor{player##1}{mathcharthemathcode`####1}
}
char_set_active_eq:Nc ####1 { __olafsson_var_####1: }
mathcode `####1 = "8000 scan_stop:
}
}
}
ExplSyntaxOff
begin{document}
$definevar{x;y} x + y = 1$.
$definevar{x,y;z;t} x + y = z - t$.
end{document}
that yields the same output.
Answered by egreg on April 12, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP