Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A couple of ideas for the future of xsim (or xsim-exam) #49

Open
pablgonz opened this issue Oct 9, 2019 · 2 comments
Open

A couple of ideas for the future of xsim (or xsim-exam) #49

pablgonz opened this issue Oct 9, 2019 · 2 comments
Assignees
Labels
suggestion suggestions and feature requests

Comments

@pablgonz
Copy link

pablgonz commented Oct 9, 2019

Just out of curiosity I've been going through the xsim.ideas file and I've realized that maybe in the future there is xsim-exam (which would be great). Let me explain a little, the xsim package is powerful when it comes to writing well a text related to problems and solutions, it covers all requirements, but sometimes you need something a little simpler (simpler is relative).

In my usual work (and that of many teachers in my country) I occupy lists of exercises very similar to the ones that straggled me in the practices in my years of university, of the type:

Instruction: Solve ALL ...and only a large list of problems and exercises numbered from 1 to 30.

In my country this is the literal translation of "eXercise Sheets", yes, without further instructions and hopefully the answers to the odd exercises, nothing much explained as a solution, just a short answer x=1 and ready.
The second and quite common are the multiple selection tests (they are actually single selection, but that's how they're known). Where the alternatives are of the type

A.   A)  (A)  a.  a)  (a)

and other variants, where the official one is A) in the national tests.
In both cases the design is almost always delegated to the good enumitem package, the difficulty is in being able to keep the keys of the alternatives and the answers.
An image to be better understood:
test-keyans-crop-1
This is where my proposal comes into play, for xsim-exam probably, I read in one of your comments that you want to keep xsim as simple as possible. With the following code:

\documentclass{article}
\usepackage{xparse,letltxmacro,enumitem,multicol} % need
\usepackage[margin=1in,noheadfoot,papersize={8.5in,13in}]{geometry} % for mwe
\ExplSyntaxOn
\LetLtxMacro{\oldenum}{\enumerate}
\LetLtxMacro{\oldendenum}{\endenumerate}
\tl_new:N \l_keyans_columns_tl
\tl_new:N \l_keyans_enumitem_tl
\tl_new:N \l_keyans_name_seq_tl
\bool_new:N \l_keyans_save_ans_bool
\bool_new:N \l_keyans_save_key_bool

\RenewDocumentEnvironment{enumerate}{ O{} }
  {
    \tl_clear:N \l_keyans_enumitem_tl
    \keys_set:nn { keyans } { columns = 1, #1 }
    \_keyans_beginenum:V \l_keyans_enumitem_tl
    \int_compare:nT { \l_keyans_columns_tl > 1 }
     {
       \setlength{ \columnsep }{ \l_keyans_colsep_dim }
       \raggedcolumns\begin{multicols}{ \l_keyans_columns_tl }
     }
  }
  {
    \int_compare:nT { \l_keyans_columns_tl > 1 }
     { \end{multicols} }
    \oldendenum
    \bool_if:NT \l_keyans_save_ans_bool
      { \end{saveanswer} }
    \bool_if:NT \l_keyans_save_key_bool
      { \end{savekeyans} }
  }

\cs_new_protected:Npn \_keyans_beginenum:n #1
  {
    \bool_if:NT \l_keyans_save_ans_bool
      {
        \__keyans_store_current_id:n{ \l_keyans_name_seq_tl }
        \begin{saveanswer}{ \l_keyans_name_seq_tl }
      }
    \bool_if:NT \l_keyans_save_key_bool
      {
        \__keyans_store_current_id:n{ \l_keyans_name_seq_tl }
        \begin{savekeyans}{ \l_keyans_name_seq_tl }
      }
    \oldenum[#1]
  }

\cs_generate_variant:Nn \_keyans_beginenum:n {V}

\keys_define:nn { keyans }
  {
    col-sep  .dim_set:N = \l_keyans_colsep_dim,
    col-sep  .initial:n = 15pt,
    columns  .tl_set:N  = \l_keyans_columns_tl,
    columns  .initial:n = 1,
    save-ans .code:n    = {
                           \bool_set_true:N \l_keyans_save_ans_bool
                           \tl_set:Nn \l_keyans_name_seq_tl { #1 }
                          },
    save-key .code:n    = {
                           \bool_set_true:N \l_keyans_save_key_bool
                           \tl_set:Nn \l_keyans_name_seq_tl { #1 }
                          },
    unknown  .code:n    = \tl_put_right:Nx \l_keyans_enumitem_tl
                          { \l_keys_key_tl \tl_if_empty:nF { #1 } { = \exp_not:n { #1 } } , }
  }

\prop_new:N \g_keyans_admin_prop

\cs_new_protected:Npn \__keyans_store_current_id:n #1
  { \prop_gput:Nnn \g_keyans_admin_prop {current-id} {#1} }

\cs_new_protected:Npn \__keyans_retrieve_current_id:n
  { \prop_item:Nn \g_keyans_admin_prop {current-id} }

\NewDocumentEnvironment{saveanswer}{ m }
  {
    \setlist[enumerate,1]{left=0pt, labelsep=5pt, noitemsep, nosep, label=\small\arabic*.}
    \setlist[enumerate,2]{before={\__keyans_step_down_level:},after={\__keyans_step_up_level:},%
                          leftmargin=16pt,nosep,itemsep=0pt,label=(\alph*)}
    \setlist[enumerate,3]{before={\__keyans_step_down_level:},after={\__keyans_step_up_level:},%
                          leftmargin=20pt,nosep,itemsep=0pt,label=\Roman*.}
    \seq_if_exist:cF { g_keyans_saved_#1_seq }{ \seq_new:c { g_keyans_saved_#1_seq }}%
  }{}

\NewDocumentCommand{\answer}{ +m }
  {
    \seq_gput_right:cn { g_keyans_saved_ \__keyans_retrieve_current_id:n _seq } { \item  #1 }
    \par
  }

\NewDocumentEnvironment{savekeyans}{ m }
  {
    \setlist[enumerate,1]{left=0pt,labelsep=5pt,itemsep=1pt,label=\arabic*.}
    \setlist[enumerate,2]{leftmargin=16pt,nosep,label=\Alph*)}
    \seq_if_exist:cF { g_keyans_saved_#1_seq }{ \seq_new:c { g_keyans_saved_#1_seq }}
  }{}

\NewDocumentCommand{\keyans}{ !o }
  {
   \IfNoValueTF{ #1 }
      {
        \tl_set:Nn \l_tmpa_tl { \protect\item }
        \tl_put_right:Nx \l_tmpa_tl { \protect\space \Alph{enumii} }
        \seq_gput_right:cV { g_keyans_saved_ \__keyans_retrieve_current_id:n _seq }{ \l_tmpa_tl }
        \par
      }
      {
        \seq_gput_right:cn { g_keyans_saved_ \__keyans_retrieve_current_id:n _seq }{ \item #1 }
        \par
      }
  }

% \__keyans_step_down_level: and \__keyans_step_up_level: for save in nested enumerate
\cs_new_protected:Nn \__keyans_step_down_level:
  {
    \seq_gput_right:cn { g_keyans_saved_ \__keyans_retrieve_current_id:n _seq }
      { \item \begin{enumerate} }
  }
\cs_new_protected:Nn \__keyans_step_up_level:
  {
    \seq_gput_right:cn { g_keyans_saved_ \__keyans_retrieve_current_id:n _seq }
      { \end{enumerate} }
  }

% Display \answer{...} and \keyans[...] saved in list by id
\cs_new_protected:Npn \__keyans_print_anskey:nn #1#2
  {
    \seq_if_empty:cF { g_keyans_saved_#1_seq }
      {
        \begin{enumerate}[#2]
        \seq_map_inline:cn { g_keyans_saved_#1_seq } { ##1 }
        \end{enumerate}
      }
  }

\NewDocumentCommand{ \printkeyans }{ O{columns=2} +m }
  {
    \setlist[enumerate,1]{left=0pt, labelsep=5pt, noitemsep, nosep, label=\small\arabic*.}
    \setlist[enumerate,2]{leftmargin=16pt,nosep,itemsep=0pt,label=(\alph*)}
    \setlist[enumerate,3]{leftmargin=20pt,nosep,itemsep=0pt,label=\Roman*.}
    \small
    \__keyans_print_anskey:nn {#2}{#1}
  }
\ExplSyntaxOff
\pagestyle{empty}
\begin{document}
\section{List of exercises}
Solve and answer the following exercises.

\begin{enumerate}[save-ans=Worksheet,left=0pt,labelsep=5pt,nosep,label=\arabic*.,columns=2]
\item Factor $x^{2}-2x+1$  \answer{$\left(x-1\right)^{2}$}
\item Factor $3x+3y+3z$    \answer{$3(x+y+z)$}
\item True False
  \begin{enumerate}
  \item $\alpha > \delta$ \answer{False}
  \item \LaTeX2e\ is cool? \answer{Very True!}
  \end{enumerate}
\item Related to Linux
  \begin{enumerate}
  \item You use linux? \answer{Yes}
  \item Usually uses the package manager? \answer{Yes}
  \item Rate the following package and class
        \begin{enumerate}
        \item xsim-exam \answer{doesn't exist for now :(}
        \item xsim \answer{very good}
        \item exsheets  \answer{obsolete}
        \end{enumerate}
  \end{enumerate}
\end{enumerate}
\subsection{Response to exercises}
\printkeyans{Worksheet}

\section{Single alternative selection test}
Mark only one of the alternatives in each question.

\begin{enumerate}[save-key=choices,left=0pt,columns=2]
\item First type of questions
    \begin{enumerate}
        \item value
        \item value
        \item value
        \item correct \keyans
        \item value
    \end{enumerate}
\item Second type of questions
        \begin{enumerate}[leftmargin=2pc,label=\Roman*.]
            \item $2\alpha+2\delta=90^{\circ}$
            \item $\alpha=\delta$
            \item $\angle EDF=45^{\circ}$
        \end{enumerate}
\begin{enumerate}[columns=2,col-sep=10pt]%
        \item I only
        \item II only \keyans
        \item I and II only
        \item I and III only
        \item I, II, and III
\end{enumerate}
\item Third type of questions
        \begin{enumerate}[leftmargin=2pc,label=(\arabic*)]
            \item $2\alpha+2\delta=90^{\circ}$
            \item $\angle EDF=45^{\circ}$
        \end{enumerate}
    \begin{enumerate}
        \item Alternativa A
        \item Alternativa B
        \item Alternativa C \keyans
        \item Alternativa D
        \item Alternativa E
    \end{enumerate}
\item Fourth type of question, a problem with numerical response \keyans[$\sqrt{2}$]
\end{enumerate}

\subsection{Keys and Answers for test}
\printkeyans[columns=4]{choices}
\end{document}

I can save the answers and keys of the tests in a sequence (expl3), it is not a silver bullet and it is not written at the level of xsim :(. To have a functionality of this style (I think) that would be an addition to this great project.
Greetings and thanks for the great contribution.
Pablo

@cgnieder cgnieder added the suggestion suggestions and feature requests label Nov 2, 2019
@cgnieder cgnieder self-assigned this Feb 17, 2020
@cgnieder
Copy link
Owner

cgnieder commented Mar 8, 2020

The input will never match your code but you can have most of it already:

\documentclass{article}
\usepackage[enable-debug]{expl3}
\usepackage[no-files]{xsim}

\xsimsetup{
  load-style = layouts ,
  exercise/template = runin ,
  solution/template = runin
}

\usepackage{tasks,fontawesome,fmtcount,multicol}
\NewTasksEnvironment[label=\Alph*),label-width=12pt]{choices}[\choice]
\newcommand*\correct{\thetask\expanded{\SetExerciseProperty{choice}{\thetask}}}

\NewTasksEnvironment[label=\Roman*,label-width=12pt]{options}[\option]

\DeclareExerciseProperty{choice}

\newcommand*\pkg[1]{\texttt{#1}}
\newcommand*\cls[1]{\texttt{#1}}

\newcommand\EA[2]{\IfInsideSolutionTF{#2}{#1}}
\newcommand\answer[1]{\IfInsideSolutionT{#1}}

\begin{document}

\section{List of exercises}
Solve and answer the following exercises.

\begin{exercise}
  Factor $x^{2}-2x+1$
\end{exercise}
\begin{solution}
  $\left(x-1\right)^{2}$
\end{solution}
\begin{exercise}
  Factor $3x+3y+3z$
\end{exercise}
\begin{solution}
  $3(x+y+z)$
\end{solution}

\begin{exercise}[solution]
  \EA{True or false?}{}
  \begin{tasks}(2)
    \task \EA{$\alpha > \delta$}{False}
    \task \EA{\LaTeX2e\ is cool?}{Very True!}
  \end{tasks}
\end{exercise}

\begin{exercise}[subtitle=Talking Linux,solution]
  \begin{tasks}(2)
    \task \EA{You use linux?}{Yes}
    \task \EA{Usually uses the package manager?}{Yes}
  \end{tasks}
\end{exercise}

\begin{exercise}[solution]
  \EA{Rate the following \LaTeX\ packages and classes.}{}
  \begin{tasks}(\EA{3}{1})
    \task \EA{\cls{xsim-exam}}{doesn't exist for now}
    \task \EA{\pkg{xsim}}{very good}
    \task \EA{\pkg{exsheets}}{obsolete}
  \end{tasks}
\end{exercise}

\begin{exercise}
  \begin{choices}(5)
    \choice value
    \choice value
    \choice value
    \choice[\correct] correct
    \choice value
  \end{choices}
\end{exercise}
\begin{solution}
  \GetExerciseProperty{choice}
\end{solution}

\begin{exercise}
  \begin{options}(3)
    \option $2\alpha+2\delta=90^{\circ}$
    \option $\alpha=\delta$
    \option $\angle EDF=45^{\circ}$
  \end{options}
  \begin{choices}(4)
    \choice I only
    \choice[\correct] II only
    \choice I and II only
    \choice I and III only
    \choice I, II, and III
  \end{choices}
\end{exercise}
\begin{solution}
  \GetExerciseProperty{choice}
\end{solution}

\begin{exercise}
  \begin{tasks}[label=(\arabic*),label-width=13pt](2)
    \task $2\alpha+2\delta=90^{\circ}$
    \task $\angle EDF=45^{\circ}$
  \end{tasks}
  \begin{choices}(3)
    \choice Alternative A
    \choice Alternative B
    \choice[\correct] Alternative C
    \choice Alternative D
    \choice Alternative E
  \end{choices}
\end{exercise}
\begin{solution}
  \GetExerciseProperty{choice}
\end{solution}

\clearpage

\section{Solutions}
\raggedcolumns
\begin{multicols}{2}
  \printsolutions[headings=false]
\end{multicols}

\end{document}

image

@pablgonz
Copy link
Author

pablgonz commented Mar 9, 2020

@cgnieder Great, it's a nice approximation, unfortunately I don't use task for this, because of psychometric norms in the creation of selection tests, the alternatives go in vertical order (as in enumitem) and not in horizontal order (as in task).

There is some way to "adapt" your code to make it more like mine, just the "List of exercise" section (without taking into account multiple choice)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
suggestion suggestions and feature requests
Projects
None yet
Development

No branches or pull requests

2 participants