Автоматически копировать элементы из последнего списка

Автоматически копировать элементы из последнего списка

В криптографии доказательство включает в себя последовательность игр. Каждая игра содержит список строк. Соседние игры почти одинаковы, за исключением небольшого количества строк (обычно 1). Раньше я копировал старую игру в следующую и модифицировал новую. Но это действительно неудобно и сложно поддерживать. Полученный исходный файл также неоправданно большой. Просто представьте себе доказательство с 20 играми, и каждая из них имеет 10 строк.

Итак, я решил создать среду для этого. Она выглядит как среда "перечисления", где каждый из ее элементов также является средой "перечисления". Каждый раз, когда я создаю новый элемент (игру) для внешнего перечислителя, я также указываю в качестве вариативного параметра, какие строки последней игры я хочу изменить. Я хочу, чтобы сама среда автоматически копировала каждую строку из последней игры, которая не указана в параметре.

Есть идеи, как этого можно добиться?

решение1

После небольшой борьбы с этим (при первом использовании prop) я думаю, что это работает, хотя это немного смешанный вариант, и, возможно, было бы лучше придумать лучший «пользовательский интерфейс».

Во-первых, у вас есть среда cryptolist, которая похожа на среду, enumerateза исключением того, что \item{…}у нее есть аргумент. cryptolistимеет необязательный аргумент, который являетсяназвание списка(по умолчанию это default), что дает вам возможность вести много разных списков одновременно.

Затем идут две команды \replacecryptoitems(имя в необязательном аргументе и обычный список ключей-значений заменяемых элементов) и \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дается (тольков следующий раз, после одного использования, он сбрасывается) измененные записи редактируются \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}

Чтобы решить первую проблему, я изменил на use seqвместо prop. И результат такой: введите описание изображения здесь

Но я не понял, как решить вторую проблему. У меня есть две идеи:

  1. Каждый раз, когда игра распечатывается, пройдитесь по всем элементам и удалите все вызовы gamediff. Препятствие gamediffможет быть не на самом верхнем уровне. Это может быть {{gamediff}}или $gamediff$.

  2. при сохранении элемента в списке пользователь не вызывает 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}

Результатом являетсявведите описание изображения здесь

Связанный контент