3

In crypto, proof involves a sequence of games. Each game contains a list of lines. Adjacent games are almost the same except for a small number of lines (usually 1). I used to copy the old game to the next one and modify on the new one. But this is really inconvenient and hard to maintain. The resulting source file is also unnecessarily large. Just think of a proof with 20 games and each of them has 10 lines.

So, I decided to create an environment for this. It looks like an "enumerate" environment where each of its items is also an "enumerate" environment. Every time I create a new item (game) for the outer enumerator, I'll also specify as a variadic parameter which lines of the last game I want to change. I want the environment itself copys every line from the last game that is not specified in the parameter automatically.

Any idea how this can be accomplished?

3
  • 1
    Could you include a(n external) source for what you're trying to achieve?
    – 1010011010
    Sep 27 '14 at 15:48
  • Section 6.1 of eprint.iacr.org/2014/588.pdf, starting from page 17. This example might be too complicated since it has an additional level of enumerate starting from Game 4. But this is not necessary and all games can be written as just a simple list.
    – c c
    Sep 27 '14 at 16:17
  • This seems “easy” with expl3, but, for instance, in order to define the first time the list it would be easier if the item was an argument to the \item command.
    – Manuel
    Sep 27 '14 at 18:09
4

After a small fight with it (first time using prop) I think this works, although it's a bit of a mix of things, and may it would be better to think of a better “user interface”.

First, you have an environment cryptolist which is like an enumerate except that \item{…} does have an argument. cryptolist has an optional argument which is the name of the list (by default it's default) which gives you the option to mantain many different lists at the same time.

Then there are two commands \replacecryptoitems (the name in the optional argument and a usual key-value list of the items to replace) and \printcryptolist (the name in the optional argument). For instance you can \replacecryptoitems{2=Modified second item, 3=modified third item} and then \printcryptolist to print it.

To initialise a new crypto list you need \newcryptolist{name}.

enter image description here

\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}

Extended code to help the new request. In this case, each time you use \replacecryptoitems the replaced entries are recorded. And the next time \printcryptoitems is given (only the next time, after one usage it's reset) the changed entries are \gamediff{…}ed.

enter image description here

\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}
0
1
\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}

To solve the first problem, I changed to use seq instead of prop. And the result is enter image description here

But I didn't figure out how I could solve the second problem. I have two ideas:

  1. Each time a game is printed out, go though all items and remove all calls to gamediff. The obstacle is gamediff might not be at the topmost level. It can be {{gamediff}} or $gamediff$.

  2. when store an item into the list, the user doesn't call gamediff directly, but calls a function which will generate gamediff[i] where i is the current game. And when a game is printed out, gamediff is evaluated and only those with the first parameter equal to the current game will hightlight its content.


With Manuel's idea, problem 2 is also handled.

\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}

The result isenter image description here

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.