暗号では、証明には一連のゲームが含まれます。各ゲームには行のリストが含まれます。隣接するゲームは、少数の行 (通常は 1 行) を除いてほぼ同じです。以前は、古いゲームを次のゲームにコピーして、新しいゲームに変更を加えていました。しかし、これは非常に不便で、維持するのが困難です。結果として得られるソース ファイルも不必要に大きくなります。20 のゲームがあり、各ゲームに 10 行ある証明を考えてみてください。
そこで、私はこれ用の環境を作成することにしました。これは、各項目が「列挙」環境でもある「列挙」環境のように見えます。外側の列挙子に新しい項目 (ゲーム) を作成するたびに、最後のゲームのどの行を変更するかを可変長パラメータとして指定します。パラメータで指定されていない最後のゲームのすべての行を環境自体が自動的にコピーするようにします。
これを実現するにはどうしたらよいか、何かアイデアはありますか?
答え1
少し格闘した後 (初めて使用prop
)、これはうまく機能すると思いますが、少し物事が混在しており、より優れた「ユーザー インターフェイス」を考えた方が良いかもしれません。
まず、引数を持つexceptcryptolist
のような環境があります。オプションの引数はenumerate
\item{…}
cryptolist
リストの名前(デフォルトではdefault
) これにより、同時に複数の異なるリストを管理するオプションが提供されます。
\replacecryptoitems
次に、2 つのコマンド(オプションの引数の名前と、置換する項目の通常のキー値リスト) と(オプションの引数の名前)があります\printcryptolist
。たとえば、\replacecryptoitems{2=Modified second item, 3=modified third item}
と を実行して\printcryptolist
印刷することができます。
新しい暗号リストを初期化するには、 が必要です\newcryptolist{name}
。
\documentclass{scrartcl}
\usepackage{xparse,enumitem}
\ExplSyntaxOn
\NewDocumentCommand \newcryptolist { m }
{
\prop_new:c { g_cryptolist_#1_prop }
\int_new:c { g_cryptolist_#1_int }
}
\NewDocumentEnvironment { cryptolist } { O{default} }
{
\tl_set:Nn \l_cryptolist_name_tl { #1 }
\int_gzero:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int }
\prop_gclear:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
\enumerate
\cs_set_eq:NN \normalitem \item
\cs_set_eq:NN \item \cryptoitem
}
{ \endenumerate }
\NewDocumentCommand \cryptoitem { o m }
{
\int_gincr:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int }
\tl_set:Nx \l_cryptolist_item_tl
{ \int_use:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int } }
\prop_gput:con { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
{ \l_cryptolist_item_tl }
{ #2 }
\IfValueTF { #1 } { \normalitem [ #1 ] } { \normalitem }
#2
}
\NewDocumentCommand \printcryptolist { O{default} }
{ \cc_printitems:n { #1 } }
\NewDocumentCommand \replacecryptoitems { O{default} m }
{ \cc_replaceitems:nn { #1 } { #2 } }
\tl_new:N \l_cryptolist_name_tl
\tl_new:N \l_cryptolist_item_tl
\prop_new:N \g_cryptolist_default_prop
\int_new:N \g_cryptolist_default_int
\keys_define:nn { cryptolist }
{
unknown .code:n =
\prop_gput:cVn { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
\l_keys_key_tl { #1 }
}
\cs_new_protected:Npn \cc_printitems:n #1
{
\begin{enumerate}
\tl_set:Nn \l_cryptolist_name_tl { #1 }
\int_step_inline:nnnn { 1 } { 1 }
{ \int_use:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int } }
{
\item
\prop_item:cn { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
{ ##1 }
}
\end{enumerate}
}
\cs_new_protected:Npn \cc_replaceitems:nn #1 #2
{
\tl_set:Nn \l_cryptolist_name_tl { #1 }
\keys_set:nn { cryptolist } { #2 }
}
\ExplSyntaxOff
\newcryptolist{anotherlist}
\begin{document}
\begin{cryptolist}[anotherlist]
\item{First item to be used later;}
\item{second item.}
\end{cryptolist}
\begin{cryptolist}
\item{First item}
\item{Second item}
\item{Third item}
\item{Last item}
\end{cryptolist}
\replacecryptoitems{2 = Second (modified) item, 4 = Last modified item.}
\printcryptolist
\replacecryptoitems[anotherlist]{1=Changing the first one to be used now;}
\printcryptolist[anotherlist]
\end{document}
新しいリクエストを支援するための拡張コード。この場合、使用するたびに\replacecryptoitems
置き換えられたエントリが記録されます。そして次回に\printcryptoitems
与えられます(のみ次回、1 回の使用後にリセットされると、変更されたエントリが\gamediff{…}
編集されます。
\documentclass{scrartcl}
\usepackage{xparse,enumitem}
\usepackage[x11names]{xcolor}
\ExplSyntaxOn
\NewDocumentCommand \gamediff { m }
{ \textcolor { Tomato3 } { #1 } }
\NewDocumentCommand \newcryptolist { m }
{
\prop_new:c { g_cryptolist_#1_prop }
\int_new:c { g_cryptolist_#1_int }
\seq_new:c { g_cryptolist_modifieditems_#1_seq }
}
\NewDocumentEnvironment { cryptolist } { O{default} }
{
\tl_set:Nn \l_cryptolist_name_tl { #1 }
\int_gzero:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int }
\prop_gclear:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
\enumerate[noitemsep]
\cs_set_eq:NN \normalitem \item
\cs_set_eq:NN \item \cryptoitem
}
{ \endenumerate }
\NewDocumentCommand \cryptoitem { o m }
{
\int_gincr:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int }
\tl_set:Nx \l_cryptolist_item_tl
{ \int_use:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int } }
\prop_gput:con { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
{ \l_cryptolist_item_tl }
{ #2 }
\IfValueTF { #1 } { \normalitem [ #1 ] } { \normalitem }
#2
}
\NewDocumentCommand \printcryptolist { O{default} }
{ \cc_printitems:n { #1 } }
\NewDocumentCommand \replacecryptoitems { O{default} m }
{ \cc_replaceitems:nn { #1 } { #2 } }
\tl_new:N \l_cryptolist_name_tl
\tl_new:N \l_cryptolist_item_tl
\prop_new:N \g_cryptolist_default_prop
\seq_new:N \g_cryptolist_modifieditems_default_seq
\int_new:N \g_cryptolist_default_int
\keys_define:nn { cryptolist }
{
unknown .code:n =
\seq_gput_right:cV
{ g_cryptolist_modifieditems_ \tl_use:N \l_cryptolist_name_tl _seq }
\l_keys_key_tl
\prop_gput:cVn { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
\l_keys_key_tl { #1 }
}
\cs_new_protected:Npn \cc_printitems:n #1
{
\begin{enumerate}[noitemsep]
\tl_set:Nn \l_cryptolist_name_tl { #1 }
\int_step_inline:nnnn { 1 } { 1 }
{ \int_use:c { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _int } }
{
\item
\group_begin:
\seq_if_in:cnF
{ g_cryptolist_modifieditems_ \tl_use:N \l_cryptolist_name_tl _seq }
{ ##1 }
{ \cs_set_eq:NN \gamediff \prg_do_nothing: }
{
\prop_item:cn { g_cryptolist_ \tl_use:N \l_cryptolist_name_tl _prop }
{ ##1 }
}
\group_end:
}
\end{enumerate}
\seq_gclear:c
{ g_cryptolist_modifieditems_ \tl_use:N \l_cryptolist_name_tl _seq }
}
\cs_new_protected:Npn \cc_replaceitems:nn #1 #2
{
\tl_set:Nn \l_cryptolist_name_tl { #1 }
\keys_set:nn { cryptolist } { #2 }
}
\ExplSyntaxOff
\newcryptolist{anotherlist}
\begin{document}
\begin{cryptolist}
\item{First item}
\item{Second item}
\item{Third item}
\item{Last item}
\end{cryptolist}
\replacecryptoitems{2 = Second \gamediff{(modified)} item, 4 = Last modified \gamediff{item}.}
\printcryptolist
And this next time they are not highlighted.
\printcryptolist
\end{document}
答え2
\documentclass{article}
\usepackage{color}
\usepackage{expl3}
\newcommand\gamediff[2][red]{\color{#1}{\underline{\color{black}{#2}}}\color{black}{}}
\newsavebox\MBox
\newcommand\gamediffeq[2][red]{{\sbox\MBox{$#2$}\rlap{\usebox\MBox}\color{#1}\rule[-1.2\dp\MBox]{\wd\MBox}{0.5pt}}}
\ExplSyntaxOn
\seq_new:N \g_crypto__gameseq_seq
\tl_new:N \g_crypto__gameseq_tl
\int_new:N \g_crypto__gameseq_i
\cs_new:Npn \crypto__gameseq_move:ccn #1#2#3
{
\int_step_inline:nnnn { 1 } { 1 } { #3 }
{
\seq_gpop_left:cN { #1 } \g_crypto__gameseq_tl
\seq_gput_left:cV { #2 } \g_crypto__gameseq_tl
}
}
\cs_new:Npn \crypto__gameseq_store:cn #1#2
{
\crypto__gameseq_move:ccn { #1 } { g_crypto__gameseq_seq } { #2 }
}
\cs_new:Npn \crypto__gameseq_load:cn #1#2
{
\crypto__gameseq_move:ccn { g_crypto__gameseq_seq } { #1 } { #2 }
}
\cs_new:Npn \crypto__gameseq_out:N #1
{
\item \tl_use:N #1
}
\cs_new:Npn \crypto_gameseq_new:c #1
{
\seq_gclear_new:c { g_crypto_gameseq_#1 }
\int_gzero_new:c { g_crypto_gameseq_#1_num }
}
\cs_new:Npn \crypto_gameseq_add:cnn #1#2#3
{
\crypto__gameseq_store:cn { g_crypto_gameseq_#1 } { \int_eval:n { #2 - 1 } }
\seq_gput_left:cn { g_crypto_gameseq_#1 } { #3 }
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { \int_eval:n { #2 - 1 } }
}
\cs_new:Npn \crypto_gameseq_del:cnn #1#2#3
{
\crypto__gameseq_store:cn { g_crypto_gameseq_#1 } { \int_eval:n { #2 - 1 } }
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { \int_eval:n { #2 - 1 } }
}
\cs_new:Npn \crypto_gameseq_mod:cnn #1#2#3
{
\crypto__gameseq_store:cn { g_crypto_gameseq_#1 } { \int_eval:n { #2 - 1 } }
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\seq_gput_left:cn { g_crypto_gameseq_#1 } { #3 }
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { \int_eval:n { #2 - 1 } }
}
\cs_new:Npn \crypto_gameseq_get:c #1
{
\int_gincr:c { g_crypto_gameseq_#1_num }
\item[Game~\int_use:c { g_crypto_gameseq_#1_num }.]
\begin{enumerate}
\seq_map_function:cN { g_crypto_gameseq_#1 } \crypto__gameseq_out:N
\end{enumerate}
}
\cs_new_eq:NN \seqnew \crypto_gameseq_new:c
\cs_new_eq:NN \seqout \crypto_gameseq_get:c
\cs_new_eq:NN \seqadd \crypto_gameseq_add:cnn
\cs_new_eq:NN \seqdel \crypto_gameseq_del:cnn
\cs_new_eq:NN \seqmod \crypto_gameseq_mod:cnn
\ExplSyntaxOff
\begin{document}
\begin{itemize}
\seqnew{cc}
\seqadd{cc}{1}{first item}
\seqadd{cc}{2}{third item}
\seqadd{cc}{2}{fourth item}
\seqout{cc}
\seqmod{cc}{2}{\gamediff{second} item}
\seqout{cc}
\seqout{cc}
\end{itemize}
\end{document}
最初の問題を解決するために、seq
の代わりにを使用するように変更しましたprop
。結果は次のようになります。
しかし、2 番目の問題をどうやって解決すればよいかわかりませんでした。2 つのアイデアがあります。
ゲームが印刷されるたびに、すべての項目を調べて への呼び出しをすべて削除します
gamediff
。障害はgamediff
最上位レベルではない可能性があります。{{gamediff}}
または である可能性があります$gamediff$
。リストにアイテムを格納するとき、ユーザーは直接呼び出すのではなく、現在のゲームがどこにあるか
gamediff
を生成する関数を呼び出します。ゲームが出力されると、が評価され、最初のパラメータが現在のゲームに等しいものだけがその内容を強調表示します。gamediff[i]
i
gamediff
マヌエルのアイデアにより、問題 2 も解決されます。
\documentclass{article}
\usepackage{color}
\usepackage{expl3}
\newcommand\highlight[2][red]{\color{#1}{\underline{\color{black}{#2}}}\color{black}{}}
\newsavebox\MBox
\newcommand\highlighteq[2][red]{{\sbox\MBox{$#2$}\rlap{\usebox\MBox}\color{#1}\rule[-1.2\dp\MBox]{\wd\MBox}{0.5pt}}}
\ExplSyntaxOn
\seq_new:N \g_crypto__gameseq_seq
\tl_new:N \g_crypto__gameseq_tl
\int_new:N \g_crypto__gameseq_i
\cs_new:Npn \crypto__gameseq_move:ccn #1#2#3
{
\int_step_inline:nnnn { 1 } { 1 } { \int_eval:n { \int_eval:n { #3 } * 2 } }
{
\seq_gpop_left:cN { #1 } \g_crypto__gameseq_tl
\seq_gput_left:cV { #2 } \g_crypto__gameseq_tl
}
}
\cs_new:Npn \crypto__gameseq_store:cn #1#2
{
\crypto__gameseq_move:ccn { #1 } { g_crypto__gameseq_seq } { #2 }
}
\cs_new:Npn \crypto__gameseq_load:cn #1#2
{
\crypto__gameseq_move:ccn { g_crypto__gameseq_seq } { #1 } { #2 }
}
\cs_new:Npn \crypto_gameseq_new:c #1
{
\seq_gclear_new:c { g_crypto_gameseq_#1 }
\int_gzero_new:c { g_crypto_gameseq_#1_num }
}
\cs_new:Npn \crypto_gameseq_add:cnn #1#2#3
{
\crypto__gameseq_store:cn { g_crypto_gameseq_#1 } { #2 - 1 }
\seq_gput_left:cn { g_crypto_gameseq_#1 } { #3 }
\seq_gput_left:cn { g_crypto_gameseq_#1 } { 1 }
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { #2 - 1 }
}
\cs_new:Npn \crypto_gameseq_del:cnn #1#2
{
\crypto__gameseq_store:cn { g_crypto_gameseq_#1 } { #2 - 1 }
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { #2 - 1 }
}
\cs_new:Npn \crypto_gameseq_mod:cnn #1#2#3
{
\crypto__gameseq_store:cn { g_crypto_gameseq_#1 } { #2 - 1 }
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\seq_gput_left:cn { g_crypto_gameseq_#1 } { #3 }
\seq_gput_left:cn { g_crypto_gameseq_#1 } { 1 }
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { #2 - 1 }
}
\cs_new:Npn \crypto_gameseq_get:c #1
{
\int_gincr:c { g_crypto_gameseq_#1_num }
\item[Game~\int_use:c { g_crypto_gameseq_#1_num }.]
\begin{enumerate}
\int_step_variable:nnnNn { 1 } { 1 } { \seq_count:c { g_crypto_gameseq_#1 } } \g_crypto__gameseq_i
{
\seq_gpop_left:cN { g_crypto_gameseq_#1 } \g_crypto__gameseq_tl
\int_if_odd:nTF \g_crypto__gameseq_i
{
\tl_if_empty:NTF { \g_crypto__gameseq_tl }
{
\cs_set_eq:NN \gamediff \prg_do_nothing:
\cs_set_eq:NN \gamediffeq \prg_do_nothing:
}
{
\cs_set_eq:NN \gamediff \highlight
\cs_set_eq:NN \gamediffeq \highlighteq
}
\seq_gput_left:Nn \g_crypto__gameseq_seq {}
}
{
\item \tl_use:N \g_crypto__gameseq_tl
\seq_gput_left:cV { g_crypto__gameseq_seq } \g_crypto__gameseq_tl
}
}
\crypto__gameseq_load:cn { g_crypto_gameseq_#1 } { \int_eval:n { \seq_count:c { g_crypto__gameseq_seq } / 2 } }
\end{enumerate}
}
\cs_new_eq:NN \seqnew \crypto_gameseq_new:c
\cs_new_eq:NN \seqout \crypto_gameseq_get:c
\cs_new_eq:NN \seqadd \crypto_gameseq_add:cnn
\cs_new_eq:NN \seqdel \crypto_gameseq_del:cnn
\cs_new_eq:NN \seqmod \crypto_gameseq_mod:cnn
\cs_new_eq:NN \gamediff \highlight
\cs_new_eq:NN \gamediffeq \highlighteq
\ExplSyntaxOff
\begin{document}
\begin{itemize}
\seqnew{cc}
\seqadd{cc}{1}{first item}
\seqout{cc}
\seqadd{cc}{2}{\gamediff{third} item}
\seqout{cc}
\seqadd{cc}{2}{fourth item}
\seqout{cc}
\seqmod{cc}{2}{\gamediff{second} item}
\seqout{cc}
\seqout{cc}
\seqdel{cc}{2}
\seqout{cc}
\end{itemize}
\end{document}
結果は