diff options
author | Karl Berry <karl@freefriends.org> | 2024-01-28 21:25:18 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-01-28 21:25:18 +0000 |
commit | e18df888e4bc09406879efa3de9ad2adbac6ad45 (patch) | |
tree | 5313b1361f459513762630be1ff732be7623a528 /Master | |
parent | 9b52f6425cd55f5efe960c01c2b6dc9526957918 (diff) |
randexam (28jan24)
git-svn-id: svn://tug.org/texlive/trunk@69622 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf | bin | 49561 -> 49496 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex | 18 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf | bin | 41354 -> 41288 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf | bin | 49564 -> 49469 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf | bin | 41312 -> 41229 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam.pdf | bin | 45202 -> 50412 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/randexam/randexam.tex | 213 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/randexam/randexam.cls | 449 |
8 files changed, 532 insertions, 148 deletions
diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf Binary files differindex 732b941999f..d7d570e9b24 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf +++ b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.pdf diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex index d431b45732e..fdfec30618d 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex +++ b/Master/texmf-dist/doc/latex/randexam/randexam-a-answer.tex @@ -12,11 +12,12 @@ \examtitle{name=Math 1906 Final Exam,date=2018-06-28,version=A} % make exam title -\gradetable +\gradetable[total=4] -\examgroup{Fill in the blanks.}{6 questions; 3 points for each; 18 points in total.} +\exampart{Fill in the blanks.}{6 questions; 3 points for each; 18 points in total.} -\answertable[3em]{6}{3} % make answer table: height 3em, six in total, three for each row +% make answer table: six in total, three for each row, strut height 3em +\answertable[total=6,column=3,strut=3em] \begin{question} The first question $k>0$, text $f(x)=\ln x-\frac{x}{\e}+k$ text $(0,+\infty)$ @@ -70,9 +71,10 @@ text text text text text text text text text text $\xi-2\eta\sim$ \fillout{$N(-3 \newpage -\examgroup{Select one answer from four choices.}{6 questions; 3 points for each; 18 points in total.} +\exampart{Select one answer from four choices.}{6 questions; 3 points for each; 18 points in total.} -\answertable{6}{6} % 生成答题栏:默认行高,总共8题,每行8题 +% make answer table: six in total, six for each row, default strut height +\answertable[total=6,column=6] \begin{question} The first question text, text text text text text text text text text text @@ -168,7 +170,7 @@ text text text text text text text text text text text text text text \pickout{D \newpage -\examgroup{Work out math questions.}{6 questions; 8 points for each; 48 points in total.} +\exampart{Work out math questions.}{6 questions; 8 points for each; 48 points in total.} \begin{question} The first question $\int\e^{2x}\,(\tan x+1)^2\dx$. @@ -305,9 +307,9 @@ Text text $H_0:\mu=3140$ text text ($\alpha = 0.01$). \newpage -\examgroup{Work out math proofs.}{2 questions; 16 points in total.} +\exampart{Work out math proofs.}{2 questions; 16 points in total.} -\renewcommand{\solutionname}{Proof} % 将“解”字改为“证”字 +\DeclareExamTranslation{current}{solution-Solution=Proof} % rename "Solution" as "Proof" \begin{question}[points=9] The first question $\{x_n\}$ text $x_1=\sqrt2$, $x_{n+1}=\sqrt{2+x_n}$. diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf Binary files differindex 2da2d3748fe..1a85a26f4cd 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf +++ b/Master/texmf-dist/doc/latex/randexam/randexam-a-blank.pdf diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf Binary files differindex 699a82d0551..349d3a80d95 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf +++ b/Master/texmf-dist/doc/latex/randexam/randexam-b-answer.pdf diff --git a/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf b/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf Binary files differindex e9dd01eab33..5ee6962d09c 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf +++ b/Master/texmf-dist/doc/latex/randexam/randexam-b-blank.pdf diff --git a/Master/texmf-dist/doc/latex/randexam/randexam.pdf b/Master/texmf-dist/doc/latex/randexam/randexam.pdf Binary files differindex 0c7f83abdf6..2faabec1c8d 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam.pdf +++ b/Master/texmf-dist/doc/latex/randexam/randexam.pdf diff --git a/Master/texmf-dist/doc/latex/randexam/randexam.tex b/Master/texmf-dist/doc/latex/randexam/randexam.tex index 9e38395b94e..feb1af2e145 100644 --- a/Master/texmf-dist/doc/latex/randexam/randexam.tex +++ b/Master/texmf-dist/doc/latex/randexam/randexam.tex @@ -3,7 +3,7 @@ \documentclass[12pt,plain,most]{randexam} \geometry{b5paper,margin=2cm} -\newcommand*{\myversion}{2024B} +\newcommand*{\myversion}{2024C} \newcommand*{\mydate}{\the\year-\mylpad\month-\mylpad\day} \newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi} @@ -46,6 +46,7 @@ \NewDocumentCommand\myfile{m}{\textcolor{purple3}{\mbox{#1}}} \NewDocumentCommand\mykey{m}{\textcolor{brown3}{\mbox{\fakeverb{#1}}}} \NewDocumentCommand\myval{m}{\textcolor{azure3}{\mbox{\fakeverb{#1}}}} +\NewDocumentCommand\myelem{m}{\textcolor{violet3}{\mbox{#1}}} \begin{document} @@ -57,6 +58,7 @@ Title: \fillbox{\color{blue3}The randexam class for LaTeX}\\ Author: \fillbox{Jianrui Lyu (tolvjr@163.com)}\\ Version: \fillbox{\myversion{} (\mydate)}\\ + Code: \fillbox{\url{https://github.com/lvjr/randexam}}\\ \hline \end{tabularx}% } @@ -102,16 +104,16 @@ you add class option \myopt{random} (see Subsection \ref{opt:random}): \subsection{Document body} In document body you normally write an \mycmd{\examtitle}, -multiple \mycmd{\examgroup}, and an optional \mycmd{\examdata} commands: +multiple \mycmd{\exampart}, and an optional \mycmd{\examdata} commands: \begin{code} \examtitle{name=Math Final Exam,date=2018-06-28,version=A} ...... -\examgroup{Fill in the blanks.}{3 points for each.} +\exampart{Fill in the blanks.}{3 points for each.} ...... -\examgroup{Select one answer.}{3 points for each.} +\exampart{Select one answer.}{3 points for each.} ...... -\examgroup{Work out math calculations.}{8 points for each.} +\exampart{Work out math calculations.}{8 points for each.} ...... \examdata{Some data may be used in the exam} ...... @@ -130,16 +132,16 @@ If the \mykey{date} key is missing, it has the default value \myval{\today}. When class option \myopt{random} is passed, the value of \mykey{version} key will be modified from \myval{A} to \myval{B}. -\subsection{Exam groups} +\subsection{Exam parts} -The questions in an exam could be separated into several groups: +The questions in an exam could be separated into several parts: \begin{code} -\examgroup{Fill in the blanks.}{3 points for each.} +\exampart{Fill in the blanks.}{3 points for each.} ...... -\examgroup{Select one answer.}{3 points for each.} +\exampart{Select one answer.}{3 points for each.} ...... -\examgroup{Work out math calculations.}{8 points for each.} +\exampart{Work out math calculations.}{8 points for each.} ...... \end{code} @@ -160,7 +162,7 @@ or the exam variants will be incorrect. \subsection{True-or-false questions} \begin{code} -\examgroup{True-or-false questions}{3 points for each.} +\exampart{True-or-false questions}{3 points for each.} \begin{question} The first true-or-false question. \tickout{T} @@ -189,7 +191,7 @@ so as to make \mypkg{randexam} hide them in generating blank exam papers. \subsection{Fill-in-the-blank questions} \begin{code} -\examgroup{Fill in the blanks.}{3 points for each.} +\exampart{Fill in the blanks.}{3 points for each.} \begin{question} The first fill-in-the-blank question \fillout{answer}. @@ -217,7 +219,7 @@ so as to make \mypkg{randexam} hide them in generating blank exam papers. \subsection{Multiple-choice questions} \begin{code} -\examgroup{Select one answer.}{3 points for each.} +\exampart{Select one answer.}{3 points for each.} \begin{question} The first multiple-choice questions \pickout{A}. @@ -275,7 +277,7 @@ according to the lengths of the choices. For subjective questions, you could put answers inside \myenv{solution} environment. \begin{code} -\examgroup{Work out math calculations.}{8 points for each.} +\exampart{Work out math calculations.}{8 points for each.} \begin{question} The first math calculation question. @@ -315,7 +317,7 @@ Answer to the second question. You can write other types of questions. For example: \begin{code} -\examgroup{Some question type}{4 points for each.} +\exampart{Some question type}{4 points for each.} \begin{question} First question text. \answer{Answer text.} @@ -345,10 +347,16 @@ Normally you need a grade table after exam title. You can get it by using \mycmd{\gradetable} command. \begin{code} -\gradetable +\gradetable[total=6,strut=2em] \end{code} -\gradetable +\vspace{-1.5em}\gradetable[total=6,strut=2em] + +The meanings of keys in the \verb!\gradetable! command are: +\begin{description} + \item[total] total number of parts in this exam. + \item[strut] strut height of the score row; its default value is \verb!2.5em!. +\end{description} \subsection{Answer tables} @@ -356,17 +364,18 @@ Before true-or-false, fill-in-the-blank, or multiple-choice questions, you may use \mycmd{\answertable} to generate an blank answer table: \begin{code} -\answertable[3em]{6}{3} +\answertable[total=6,column=3,strut=3em] \end{code} -\answertable[3em]{6}{3} +\answertable[total=6,column=3,strut=3em] -The meanings of the three arguments of \verb!\answertable! commands are as follows: -\begin{itemize} - \item The first one means the strut height of the answer rows; its default value is \verb!1em!. - \item The second one means the total number of questions in this exam group. - \item The third one means the number of questions in each row. -\end{itemize} +The meanings of keys in the \verb!\answertable! command are: +\begin{description} + \item[total] total number of questions in this exam part. + \item[column] number of questions in each row. + \item[strut] strut height of the answer rows; its default value is \verb!1em!. + \item[notice] notice text before the answer table. +\end{description} \subsection{Vertical space} @@ -412,12 +421,13 @@ This is a question. \subsection{Solution name} -If you want to change the name of \myenv{solution} environment, -you could redefine \mycmd{\solutionname} command. +If you would like to change the name of \myenv{solution} environment, +you could modify the translation of \mykey{solution-Solution} keyword +(see Subsection \ref{subsect:translation}). The following example changes it from "Solution" to "Proof": \begin{code} -\renewcommand{\solutionname}{Proof} +\DeclareExamTranslation{current}{solution-Solution=Proof} \end{code} \subsection{Points command} @@ -498,7 +508,7 @@ The answers will be hidden in the compiled exam paper. \subsection{Randomized variants}\label{opt:random} Assume \myfile{exam-a-answer.tex} is an exam paper. -You can get an randomized variant with all questions in the same group shuffled, +You can get an randomized variant with all questions in the same part shuffled, by creating an \myfile{exam-b-answer.tex} file with the following lines: \begin{code} @@ -507,7 +517,7 @@ by creating an \myfile{exam-b-answer.tex} file with the following lines: \end{code} That is to say, when adding \myopt{random} option to \mypkg{randexam} class, -The questions in the same group will be shuffled in the compiled exam paper. +The questions in the same part will be shuffled in the compiled exam paper. Furthermore, four choices in an \myenv{abcd} environment will be shuffled too. \subsection{Two column exam papers} @@ -538,4 +548,147 @@ by creating a new TeX file with the following lines: That is to say, you can make an exam of A3 size from an exam of A4 size, even if you have only the PDF file. +\section{Customizations} + +\subsection{Translations of keywords}\label{subsect:translation} + +With \mycmd{\DeclareExamTranslation} you can define the translaitons of the keywords +in an \mypkg{randexam} paper. At this time only English keywords are defined: + +\begin{code} +\DeclareExamTranslation{english}{ + answertable-Answer = Answer + ,answertable-Number = Number + ,examdata-Appendix = Appendix + ,exampart-Part = Part + ,examtitle-Name = Name + ,examtitle-Solutions = Solutions + ,gradetable-Evaluator = Evaluator + ,gradetable-Part = Part + ,gradetable-Score = Score + ,gradetable-Total = Total + ,headfoot-Name = Name + ,headfoot-of = of + ,headfoot-Page = Page + ,headfoot-Solutions = Solutions + ,headfoot-Version = Version + ,points-point = point + ,points-points = points + ,question-Question = Question + ,solution-Solution = Solution +} +\end{code} + +You could translate them for another language and enable them with \mycmd{\SelectExamTranslation} command: + +\begin{code} +\DeclareExamTranslation{somelang}{ + question-Question = Questioooooon + ,solution-Solution = Soooooolution +} +\SelectExamTranslation{somelang} +\end{code} +\DeclareExamTranslation{somelang}{ + question-Question = Questioooooon + ,solution-Solution = Soooooolution +} +\SelectExamTranslation{somelang} + +After this, you could load current translation of some keywords with \mycmd{\UseExamTranslation} command: + +\begin{code} +\UseExamTranslation{question-Question} +\UseExamTranslation{solution-Solution} +\end{code} +\hrule +\UseExamTranslation{question-Question} +\UseExamTranslation{solution-Solution} +\vspace{0.5em} +\hrule +\vspace{0.5em} + +\SelectExamTranslation{english} + +This command is useful in defining new templates for the exam (see Subsection \ref{subsect:template}). + +\subsection{Saving and reading key values} + +With \mycmd{\DeclareExamValue} and \mycmd{\UseExamValue} you could save and read +the value of a key, respectively. + +\begin{code} +\DeclareExamValue{somemodule}{somekey}{SomeValue} +\UseExamValue{somemodule}{somekey} +\end{code} +\hrule +\DeclareExamValue{somemodule}{somekey}{SomeValue} +\UseExamValue{somemodule}{somekey} +\vspace{0.5em} +\hrule +\vspace{0.5em} + +These two commands are useful in defining new templates +for the exam (see Subsection \ref{subsect:template}). + +\subsection{Templates of elements}\label{subsect:template} + +With \mycmd{\DeclareExamTemplate} you could define a new template for some exam element, +which could be set as default template with \mycmd{\SelectExamTemplate}. +And with \mycmd{\UseExamTemplate} you could use the default template of the element. + +To customize \myelem{examtitle} element for your school, +you can write the following code in document preamble: +\begin{code} +\DeclareExamTemplate{examtitle}{myschool}{% + \fbox{% + \UseExamValue{examtitle}{name}\quad% + \UseExamValue{examtitle}{date}% + }% +}% +\SelectExamTemplate{examtitle}{myschool} +\end{code} +\DeclareExamTemplate{examtitle}{myschool}{% + \fbox{% + \UseExamValue{examtitle}{name}\quad% + \UseExamValue{examtitle}{date}% + }% +}% +\SelectExamTemplate{examtitle}{myschool} + +Then the \mycmd{\examtitle} command in document body will produce different result: +\begin{code} +\examtitle{name=Final Exam in My School,date=2024-01-01} +\end{code} +\vspace{-1em} +\examtitle{name=Final Exam in My School,date=2024-01-01} + +Normally \mycmd{\examtitle} will call \mycmd{\UseExamTemplate{examtitle}{default}}. + +All elements that could be customized with templates in an exam paper +are listed in the following table: + +\begingroup\renewcommand\arraystretch{1.5}\noindent +\begin{tabularx}{\linewidth}{ll} +\hline + \myelem{examtitle} & for customizing \mycmd{\examtitle} command \\ +\hline + \myelem{exampart} & for customizing \mycmd{\exampart} command \\ +\hline + \myelem{examdata} & for customizing \mycmd{\examdata} command \\ +\hline + \myelem{gradetable} & for customizing \mycmd{\gradetable} command \\ +\hline + \myelem{answertable} & for customizing \mycmd{\answertable} command \\ +\hline + \myelem{questionbegin} & for customizing \myenv{question} environment \\ +\hline + \myelem{questionend} & for customizing \myenv{question} environment \\ +\hline + \myelem{solutionbegin} & for customizing \myenv{solution} environment \\ +\hline + \myelem{solutionend} & for customizing \myenv{solution} environment \\ +\hline +\end{tabularx}\par +\endgroup + \end{document} diff --git a/Master/texmf-dist/tex/latex/randexam/randexam.cls b/Master/texmf-dist/tex/latex/randexam/randexam.cls index 8f5ae8bde9b..d103dfe5584 100644 --- a/Master/texmf-dist/tex/latex/randexam/randexam.cls +++ b/Master/texmf-dist/tex/latex/randexam/randexam.cls @@ -5,9 +5,9 @@ % ---------------------------------------------------------------------------- \NeedsTeXFormat{LaTeX2e} -\ProvidesClass{randexam}[2024-01-20 v2024B Make an exam paper and its randomized variants] +\ProvidesClass{randexam}[2024-01-28 v2024C Make an exam paper and its randomized variants] -%% Old LaTeX release could not recongnize date format like 2022-11-01 +%% Old LaTeX release could not recognize date format like 2022-11-01 %\@ifl@t@r\fmtversion{2022-11-01}{}{ \@ifl@t@r\fmtversion{2022/11/01}{}{ \ClassError{randexam}{% @@ -16,6 +16,9 @@ }{Please update your TeX distribution first.} } +\RequirePackage{functional} +\IgnoreSpacesOn + \RequirePackage{etoolbox} \newbool{plain} \boolfalse{plain} % use plain page style @@ -27,7 +30,7 @@ \newbool{amsfonts} \boolfalse{amsfonts} % use ams fonts \newbool{freealign} \boolfalse{freealign} % load freealign package \newbool{medmath} \boolfalse{medmath} % use medium-size formulas -\newbool{grader} \boolfalse{grader} % add grader line in the grade table +\newbool{evaluator} \boolfalse{evaluator} % add evaluator line in the grade table \DeclareKeys{ plain .if = plain, @@ -39,7 +42,7 @@ amsfonts .if = amsfonts, freealign .if = freealign, medmath .if = medmath, - grader .if = grader, + evaluator .if = evaluator, many .code = \booltrue{freealign}, most .code = \booltrue{freealign}\booltrue{medmath} } @@ -66,7 +69,6 @@ \RequirePackage{zref-user,zref-lastpage} \RequirePackage{tabularx} \RequirePackage{xcolor} -\RequirePackage{xkeyval} \ifplain \allowdisplaybreaks[4] @@ -91,6 +93,103 @@ \NewDocumentCommand\SetExamOption{+m}{\SetKeys[randexam]{#1}} %% --------------------------------------------------------------------------- +%% Template commands for exam elements +%% --------------------------------------------------------------------------- + +%% #1: exam element; #2: template name; #3: template code +%% If the template name = default, we enable the template at once +%% Otherwise, we may enable the template by using \SelectExamTemplate command +\NewDocumentCommand\DeclareExamTemplate{mm+m}{ + \tlSet{\expName{l@rdxm@template@#1@#2@tl}}{#3} + \ignorespaces +} + +%% #1: exam element; #2: template name +\NewDocumentCommand\SelectExamTemplate{mm}{ + \tlSetEq{\expName{l@rdxm@template@#1@default@tl}}{\expName{l@rdxm@template@#1@#2@tl}} + \ignorespaces +} + +%% #1: exam element; #2: template name. +%% In an expandable command, we should use \UseName but not \expName. +\NewExpandableDocumentCommand\UseExamTemplate{mm}{ + \UseName{l@rdxm@template@#1@#2@tl} +} + +%% --------------------------------------------------------------------------- +%% Translation commands for exam keywords +%% --------------------------------------------------------------------------- + +\tlSet\l@rdxm@current@language@tl{english} + +\DeclareUnknownKeyHandler[randexam-translation]{ + \tlSet{\expName{l@rdxm@translate@\l@rdxm@declare@language@tl @#1@tl}}{#2} +} + +%% #1: language name; #2: a keyval list with keyword = transaltion format +\NewDocumentCommand\DeclareExamTranslation{mm}{ + \tlIfEqTF{#1}{current}{ + \tlSetEq\l@rdxm@declare@language@tl\l@rdxm@current@language@tl + }{ + \tlSet\l@rdxm@declare@language@tl{#1} + } + \SetKeys[randexam-translation]{#2} + \ignorespaces +} + +%% #1: language name +\NewDocumentCommand\SelectExamTranslation{m}{ + \tlSet\l@rdxm@current@language@tl{#1} + \ignorespaces +} + +%% #1: keyword name. +%% In an expandable command, we should use \UseName but not \expName. +\NewExpandableDocumentCommand\UseExamTranslation{m}{ + \UseName{l@rdxm@translate@\l@rdxm@current@language@tl @#1@tl} +} + +\DeclareExamTranslation{english}{ + answertable-Answer = Answer + ,answertable-Number = Number + ,examdata-Appendix = Appendix + ,exampart-Part = Part + ,examtitle-Name = Name + ,examtitle-Solutions = Solutions + ,gradetable-Evaluator = Evaluator + ,gradetable-Part = Part + ,gradetable-Score = Score + ,gradetable-Total = Total + ,headfoot-Name = Name + ,headfoot-of = of + ,headfoot-Page = Page + ,headfoot-Solutions = Solutions + ,headfoot-Version = Version + ,points-point = point + ,points-points = points + ,question-Question = Question + ,solution-Solution = Solution +} + +\SelectExamTranslation{english} + +%% --------------------------------------------------------------------------- +%% Keyvalue commands for exam options +%% --------------------------------------------------------------------------- + +%% #1 module name; #2: key name; #3: its value +\NewDocumentCommand\DeclareExamValue{mm+m}{ + \tlSet{\expName{l@rdxm@value@#1@#2@tl}}{#3} + \ignorespaces +} + +%% #1: module name; #2: key name. +%% In an expandable command, we should use \UseName but not \expName. +\NewExpandableDocumentCommand\UseExamValue{mm}{ + \UseName{l@rdxm@value@#1@#2@tl} +} + +%% --------------------------------------------------------------------------- %% Command for exam title: \examtitle %% --------------------------------------------------------------------------- @@ -101,88 +200,143 @@ \newcommand{\ischeck}[1]{\ifnum#1>0\,$\checkmark$\,\else\quad\fi} \newcommand{\isquad}[1]{\ifnum#1=0\,$\checkmark$\,\else\quad\fi} -\def\rdxm@temp@a{A} -\def\rdxm@temp@c{C} -\def\rdxm@empty{} - \DeclareKeys[randexam-title]{ - name .store = \@rdxm@title@name, - date .store = \@rdxm@title@date, - version .store = \@rdxm@title@version + name .code = \DeclareExamValue{examtitle}{name}{#1} + ,date .code = \DeclareExamValue{examtitle}{date}{#1} + ,version .code = \DeclareExamValue{examtitle}{version}{#1} } \NewDocumentCommand\SetExamTitle{+m}{\SetKeys[randexam-title]{#1}} -\SetExamTitle{name=Math 1906,date=\today,version=A} +\SetExamTitle{name=Math~1906,date=\today,version=A} -\newcommand\examtitle[1]{% - \SetExamTitle{#1}% - \thispagestyle{plain} - \ifbool{random}{% - \ifx\@rdxm@title@version\rdxm@temp@a\def\@rdxm@title@version{B}\fi - \ifx\@rdxm@title@version\rdxm@temp@c\def\@rdxm@title@version{D}\fi - }{}% +\DeclareExamTemplate{examtitle}{normal}{ \begingroup \Large\noindent - \ifbool{answer}{% - \textcolor{red!80!black}{\@rdxm@title@name\hfill Solutions}% - }{% - \@rdxm@title@name\hfill Name:\underspace{6em}% + \ifbool{answer}{ + \textcolor{red!80!black}{ + \UseExamValue{examtitle}{name}\hfill\UseExamTranslation{examtitle-Solutions} + } + }{ + \UseExamValue{examtitle}{name}\hfill\UseExamTranslation{examtitle-Name}:\underspace{6em} }\par \endgroup } +\SelectExamTemplate{examtitle}{normal} + +\NewDocumentCommand\examtitle{+m}{ + \SetExamTitle{#1} + \thispagestyle{plain} + \ifbool{random}{ + \tlIfEqT{\expWhole{\UseExamValue{examtitle}{version}}}{A}{ + \DeclareExamValue{examtitle}{version}{B} + } + \tlIfEqT{\expWhole{\UseExamValue{examtitle}{version}}}{C}{ + \DeclareExamValue{examtitle}{version}{D} + } + }{} + \UseExamTemplate{examtitle}{default} +} %% --------------------------------------------------------------------------- %% Command for grade table: \gradetable %% --------------------------------------------------------------------------- -%% You need to put .code:n before .initial:n -\DeclareKeys[randexam]{% - groupnumber .code:n = \let\exam@group@number#1, - groupnumber .initial:n = \Roman, +%% total: total number of parts in current exam; +%% strut: strut height in the score row. +\DeclareKeys[randexam-gradetable]{ + total .code = \DeclareExamValue{gradetable}{total}{#1} + ,total .initial:n = 6 + ,strut .code = \DeclareExamValue{gradetable}{strut}{#1} + ,strut .initial:n = 2.5em } \newcounter{@exam@grade@cnt} -\newcommand\rdxm@group@number[1]{% - \stepcounter{@exam@grade@cnt}% - \exam@group@number{@exam@grade@cnt}% +\newrobustcmd\rdxm@part@number[1]{ + \setcounter{@exam@grade@cnt}{#1} + \exam@part@number{@exam@grade@cnt} } -\newcommand\insertgroupname{Part} -\newcommand\insertscorename{Score} -\newcommand\insertgradername{Grader} -\newcommand\inserttotalname{Total} +%% #1: the tl variable; #2: the first cell; #3: the last cell +%% #4: the number of middle cells; #5: the map command for middle cells. +\newrobustcmd\rdxm@table@make@row[5]{ + \tlSet#1{#2 & } + \intStepOneInline{1}{#4}{ + \tlPutRight#1{#5{##1} &} + } + \tlPutRight#1{ #3} +} -\newcommand\gradetable{% - \par\vspace{1em}% - \setcounter{@exam@grade@cnt}{0}% - \noindent\begin{tabularx}{\linewidth}{|*{8}{Y|}} - \hline - \textbf{\insertgroupname} - & \rdxm@group@number{1} & \rdxm@group@number{2} & \rdxm@group@number{3} - & \rdxm@group@number{4} & \rdxm@group@number{5} & \rdxm@group@number{6} - & \inserttotalname\\ - \hline - \textbf{\insertscorename}\rule[-0.75em]{0pt}{2.5em} & & & & & & & \\ +\newrobustcmd\rdxm@gobble@one[1]{} + +%% \dimeval or \dimexpr doesn't accept decimal numbers such as 0.3 +\NewDocumentCommand\MakeExamStruct{m}{ + \rule[-\dimeval{(#1)*3/10}]{0pt}{#1} +} + +\DeclareExamTemplate{gradetable}{normal}{ + \rdxm@table@make@row + \l@rdxm@gradetable@part@tl + {\textbf{\UseExamTranslation{gradetable-Part}}} + {\UseExamTranslation{gradetable-Total}} + {\UseExamValue{gradetable}{total}} + \rdxm@part@number + \rdxm@table@make@row + \l@rdxm@gradetable@score@tl + {\textbf{\UseExamTranslation{gradetable-Score}} + \MakeExamStruct{\UseExamValue{gradetable}{strut}}} + {} + {\UseExamValue{gradetable}{total}} + \rdxm@gobble@one + \ifbool{evaluator}{ + \rdxm@table@make@row + \l@rdxm@gradetable@evaluator@tl + {\textbf{\UseExamTranslation{gradetable-Evaluator}} + \MakeExamStruct{\UseExamValue{gradetable}{strut}}} + {} + {\UseExamValue{gradetable}{total}} + \rdxm@gobble@one + }{} + \noindent + \begin{tabularx}{\linewidth}{|c|*{\UseExamValue{gradetable}{total}}{Y|}Y|} \hline - \ifbool{grader}{ - \textbf{\insertgradername}\rule[-0.75em]{0pt}{2.5em} & & & & & & & \\ - \hline - }{} + \l@rdxm@gradetable@part@tl \\ \hline + \l@rdxm@gradetable@score@tl \\ \hline + \ifbool{evaluator}{\l@rdxm@gradetable@evaluator@tl \\ \hline}{} \end{tabularx} } +\SelectExamTemplate{gradetable}{normal} + +\NewDocumentCommand\gradetable{O{}}{ + \par\vspace{1em} + \begingroup + \SetKeys[randexam-gradetable]{#1} + \UseExamTemplate{gradetable}{default} + \endgroup +} %% --------------------------------------------------------------------------- %% Setting header and footer %% --------------------------------------------------------------------------- \newcommand{\rdxm@columnbox}[1]{\makebox[\columnwidth]{#1}} -\newcommand{\rdxm@headleft}{\@rdxm@title@name} -\newcommand{\rdxm@headright}{\ifbool{answer}{Solutions}{Name:\hspace{12em}}} +\newcommand{\rdxm@headleft}{\UseExamValue{examtitle}{name}} +\newcommand{\rdxm@headright}{ + \ifbool{answer}{ + \UseExamTranslation{headfoot-Solutions} + }{ + \UseExamTranslation{headfoot-Name}:\hspace{12em} + } +} \newcommand{\rdxm@headtext}{\rdxm@headleft\hfill\rdxm@headright} -\newcommand{\rdxm@footleft}{\@rdxm@title@date} -\newcommand{\rdxm@footcenter}{Page~\thepage~of~\zpageref{LastPage}} -\newcommand{\rdxm@footright}{Version \@rdxm@title@version} +\newcommand{\rdxm@footleft}{\UseExamValue{examtitle}{date}} +\newcommand{\rdxm@footcenter}{ + \UseExamTranslation{headfoot-Page}~\thepage\space + \UseExamTranslation{headfoot-of}~\zpageref{LastPage} +} +\newcommand{\rdxm@footright}{ + \UseExamTranslation{headfoot-Version}~\UseExamValue{examtitle}{version} +} \newcommand{\rdxm@foottext}{\rdxm@footleft\hfill\rdxm@footcenter\hfill\rdxm@footright} % fancy page style @@ -235,7 +389,7 @@ \RequirePackage{pgffor} \newcommand*\exam@set@seed{% %% 当\pgfmathrandom的参数为3的倍数时,对相邻种子生成的多个随机数分布不均匀 - %\pgfmathsetseed{\numexpr\rdxm@random@seed+\value{rdxm@group}-1\relax}% + %\pgfmathsetseed{\numexpr\rdxm@random@seed+\value{rdxm@part}-1\relax}% %% 因此我们改用下面的方法,用随机数种子生成下一个随机数种子 \pgfmathsetseed{\rdxm@random@seed}% \pgfmathrandominteger\rdxm@random@seed{1}{2147483647}% @@ -243,25 +397,31 @@ \fi %% --------------------------------------------------------------------------- -%% Command for exam groups: \examgroup +%% Command for exam groups: \exampart %% Command for appendix data: \examdata %% Environment for questions: question %% Environment for solutions: solution %% --------------------------------------------------------------------------- +%% You need to put .code before .initial:n +\DeclareKeys[randexam-exampart]{% + partnumber .code = \let\exam@part@number#1, + partnumber .initial:n = \Roman, +} + \newif\ifonlyonequestion \onlyonequestionfalse % 此部分仅有一道题时不显示题目编号 \xdef\allquestions{} \xdef\lastquestion{} \newcounter{question} % 当前题型的小题编号 \newcounter{questionreal} % 实际显示的小题编号,在各题型小题统一编号时使用 \newcounter{totalquestions} % 之前各题型小题总数,在各题型小题统一编号时使用 -\newcommand{\solutionname}{Solution} + \newcounter{choice} % 后面选择题的 abcd 环境要用到 \newcommand{\hangtext}{} \newlength{\hanglength} -\colorlet{group number}{black} -\colorlet{question number}{blue!80!black} -\colorlet{solution name}{blue!80!black} +\colorlet{part~number}{black} +\colorlet{question~number}{blue!80!black} +\colorlet{solution~name}{blue!80!black} \newcounter{rdxm@shuffle@temp@cnt} \newcounter{rdxm@list@temp@cnt} @@ -337,19 +497,29 @@ \xdef\lastquestion{}% } -\newcounter{rdxm@group} +\newcounter{rdxm@part} -\newcommand\insertgroup[2]{% - \noindent\textbf{\textcolor{group number}{Part~\Roman{rdxm@group}}: #1} (#2)% +\DeclareExamTemplate{exampart}{normal}{ + \noindent + \textbf{ + \textcolor{part~number}{\UseExamTranslation{exampart-Part}~\Roman{rdxm@part}} + :~\UseExamValue{exampart}{type} + } + \space(\UseExamValue{exampart}{points}) } +\SelectExamTemplate{exampart}{normal} -\newcommand{\examgroup}[2]{% +\newcommand{\exampart}[2]{ \printquestions - \setcounter{totalquestions}{\value{totalquestions}+\value{question}}% - \setcounter{question}{0}% - \stepcounter{rdxm@group}% - \vspace{1em}% - \insertgroup{#1}{#2}% + \setcounter{totalquestions}{\value{totalquestions}+\value{question}} + \setcounter{question}{0} + \stepcounter{rdxm@part} + \vspace{1em} + \begingroup + \DeclareExamValue{exampart}{type}{#1} + \DeclareExamValue{exampart}{points}{#2} + \UseExamTemplate{exampart}{default} + \endgroup \par\nopagebreak \if\relax\detokenize{#1}\relax % #1 is empty \onlyonequestiontrue @@ -361,57 +531,96 @@ \@afterheading } -\renewcommand\appendixname{Appendix} -\newcommand{\examdata}[1]{% +\DeclareExamTemplate{examdata}{normal}{ + \centerline{ + \textbf{\UseExamTranslation{examdata-Appendix}} + \quad\UseExamValue{examdata}{caption} + } + \smallskip +} +\SelectExamTemplate{examdata}{normal} + +\NewDocumentCommand\examdata{+m}{ \printquestions\rdxm@stop@random - \centerline{\textbf{\appendixname}\quad #1}\smallskip + \DeclareExamValue{examdata}{caption}{#1} + \UseExamTemplate{examdata}{default} } \preto{\@enddocumenthook}{\printquestions\rdxm@stop@random} \newcommand\ignorepars{\@ifnextchar\par{\expandafter\ignorepars\@gobble}{}} -% 局部定义,仅在当前题目内有效 -\define@key{exam@question}{points}[-1]{\def\rdxm@question@points{#1}} -\define@key{exam@question}{level}[]{\def\rdxm@question@level{#1}} -\define@key{exam@question}{year}[]{\def\rdxm@question@year{#1}} +% local definition, valid only in current question +\DeclareKeys[randexam-question]{ + points .store = \l@rdxm@question@points + ,level .store = \l@rdxm@question@level + ,year .store = \l@rdxm@question@year +} -\newcommand\pointname{point} -\newcommand\pointsname{points} -\newcommand\pointorpoints[1]{\ifnumgreater{#1}{1}{\pointsname}{\pointname}} +\newcommand\pointorpoints[1]{ + \ifnumgreater{#1}{1}{ + \UseExamTranslation{points-points} + }{ + \UseExamTranslation{points-point} + } +} \newcommand{\questionpointstext}[1]{ (#1 \pointorpoints{#1}) } \newcommand\rdxm@hook@exec@other@keys{} -\newcommand{\execute@question@keys}[1]{% - \setkeys{exam@question}{#1}% +\newrobustcmd\execute@question@keys{ \rdxm@hook@exec@other@keys - \ifdefvoid{\rdxm@question@points}{}{\questionpointstext{\rdxm@question@points}}% + \ifdefvoid{\l@rdxm@question@points}{}{\questionpointstext{\l@rdxm@question@points}} } -\newenvironment{questionreal}[1][]{% - \stepcounter{question}\setcounter{choice}{0}% +\DeclareExamTemplate{questionbegin}{normal}{ \ifresetnumber \ifonlyonequestion \renewcommand{\hangtext}{\qquad}% \else - \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question number}{\arabic{question}}.}}\;\,}% + \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question~number}{\arabic{question}}.}}\;\,} \fi \else \setcounter{questionreal}{\value{totalquestions}+\value{question}}% - \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question number}{\arabic{questionreal}}.}}\;\,}% + \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{question~number}{\arabic{questionreal}}.}}\;\,} \fi - \settowidth{\hanglength}{\hangtext}% + \settowidth{\hanglength}{\hangtext} \description[leftmargin=\hanglength,labelwidth=0pt,labelsep=0pt,topsep=0pt,parsep=0pt] - \item[\hangtext]\execute@question@keys{#1}% -}{\enddescription} -\newenvironment{solutionreal}{% - \renewcommand{\hangtext}{\textbf{\textsf{\textcolor{solution name}{\solutionname}.}}\;\,}% - \settowidth{\hanglength}{\hangtext}% + \item[\hangtext]\execute@question@keys +} +\SelectExamTemplate{questionbegin}{normal} + +\DeclareExamTemplate{questionend}{normal}{\enddescription} +\SelectExamTemplate{questionend}{normal} + +\NewDocumentEnvironment{questionreal}{O{}}{ + \stepcounter{question} + \setcounter{choice}{0} + \SetKeys[randexam-question]{#1} + \UseExamTemplate{questionbegin}{default} +}{ + \UseExamTemplate{questionend}{default} +} + +\DeclareExamTemplate{solutionbegin}{normal}{ + \renewcommand{\hangtext}{ + \textbf{\textsf{\textcolor{solution~name}{\UseExamTranslation{solution-Solution}}.}}\;\, + } + \settowidth{\hanglength}{\hangtext} \description[leftmargin=\hanglength,labelwidth=0pt,labelsep=0pt,topsep=0pt,parsep=0pt] \item[\hangtext] -}{\enddescription} +} +\SelectExamTemplate{solutionbegin}{normal} + +\DeclareExamTemplate{solutionend}{normal}{\enddescription} +\SelectExamTemplate{solutionend}{normal} + +\NewDocumentEnvironment{solutionreal}{}{ + \UseExamTemplate{solutionbegin}{default} +}{ + \UseExamTemplate{solutionend}{default} +} \let \oldnewpage = \newpage \let \oldvfill = \vfill @@ -480,28 +689,37 @@ %% Command for answer tables: \answertable %% --------------------------------------------------------------------------- +%% property .store is the same as .tl_set:N in ltkeys. +%% you need to put .code before .initial:n. +%% total: total number of questions in current exam part; +%% column: number of questions in each answer row; +%% strut: strut height in each answer rows; +%% notice: notice text before the answer table. +\DeclareKeys[randexam-answertable]{ + total .code = \DeclareExamValue{answertable}{total}{#1} + ,column .code = \DeclareExamValue{answertable}{column}{#1} + ,strut .code = \DeclareExamValue{answertable}{strut}{#1} + ,strut .initial:n = 1em + ,notice .code = \DeclareExamValue{answertable}{notice}{#1} + ,notice .initial:n = {Notice:~you~MUST~write~the~answers~in~the~following~tables.} +} + \gdef\answer@lines@temp{}% \newcommand{\answer@lines@add}[1]{% \xdef\answer@lines@temp{\answer@lines@temp#1}% } -\newcommand\insertnumbertext{Number} -\newcommand\insertanswertext{Answer} -\newcommand\insertanswertabletext{% - Notice: you MUST write the answers in the following tables.% +\newrobustcmd\answer@number@hided[1]{\UseExamTranslation{answertable-Number}} +\newrobustcmd\answer@cell@strut[1]{ + \parbox[c][#1][c]{2em}{\hbox{\UseExamTranslation{answertable-Answer}}} } -\newrobustcmd{\answer@number@hided}[1]{\insertnumbertext} % 在 PDFLaTeX 中需要保护中文 -\newrobustcmd{\answer@cell@strut}[1]{\parbox[c][#1][c]{2em}{\hbox{\insertanswertext}}} - \newcounter{answer@col} \newcounter{answer@row} \newcounter{answer@total} +%% #1: strut; #2: total; #3: column. \newcommand{\answer@lines}[3]{% - % #1 答题栏各栏指定高度 - % #2 答题栏总共答案个数 - % #3 答题栏每行答案个数 \setcounter{answer@row}{(#2-1)/#3+1}% 除法向下取整,改为向上取整 \begingroup \let\hline=\relax \let\\=\relax % 禁止展开 @@ -537,13 +755,22 @@ \answer@lines@temp } -\newcommand{\answertable}[3][1em]{% - \insertanswertabletext\par - \begin{tabularx}{\linewidth}{|c|*{#3}{Y|}} +\DeclareExamTemplate{answertable}{normal}{ + \UseExamValue{answertable}{notice}\par + \begin{tabularx}{\linewidth}{|c|*{\UseExamValue{answertable}{column}}{Y|}} \hline - \answer@lines{#1}{#2}{#3} - \end{tabularx}% - \par\vspace{0.8em}% + \answer@lines{\UseExamValue{answertable}{strut}} + {\UseExamValue{answertable}{total}}{\UseExamValue{answertable}{column}} + \end{tabularx} +} +\SelectExamTemplate{answertable}{normal} + +\NewDocumentCommand\answertable{O{}}{ + \begingroup + \SetKeys[randexam-answertable]{#1} + \UseExamTemplate{answertable}{default} + \endgroup + \par\vspace{0.8em} } %% --------------------------------------------------------------------------- @@ -940,3 +1167,5 @@ \let \downwhitearrow = \Downarrow }} +\IgnoreSpacesOff + |