% \iffalse meta-comment % ================================================== % exam-ltr.dtx – LaTeX Exam Package (LTR) % Version: 1.0 % Date: 2026/08/20 % % Copyright (C) 2026 by Nadeer Aljaroudi % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either % version 1.3c of this license or (at your option) any later % version. % ================================================== % \fi % % \iffalse %<*driver> \documentclass{ltxdoc} \usepackage{exam-ltr} \usepackage{array} \usepackage{enumitem} \usepackage{underscore} \usepackage[hyperindex=false]{hyperref} \hypersetup{colorlinks=true,linkcolor=blue} \EnableCrossrefs \RecordChanges \begin{document} \DocInput{exam-ltr.dtx} \end{document} % % \fi % % \changes{v1.0}{2026/08/20}{Initial public release} % % \GetFileInfo{exam-ltr.dtx} % % \title{^^A % \textsf{exam-ltr} --- A Comprehensive LaTeX Exam Package\thanks{^^A % This file has version v1.0, dated 2026-08-20.}^^A % } % % \author{Nadeer Aljaroudi} % \date{2026-08-20} % % \maketitle % % \begin{abstract} % The \textsf{exam-ltr} package provides a comprehensive framework for % designing professional exams and academic assessments in \LaTeX. % Developed specifically for educators and exam setters, it supports % a wide variety of question types, including Multiple Choice, % True/False, Fill in the Blank, Ordering, Matching, Essay, Short Answer, % and Reading Passages. % % Key features include automatic answer key generation, controlled % randomization, metadata display, and flexible layout for both % simple quizzes and complex examinations. % \end{abstract} % % \tableofcontents % % \section{Introduction} % % The \textsf{exam-ltr} package provides a clean and robust environment for % building professional exams without manual formatting. Built with educators % in mind, it allows you to focus on creating high-quality question content % while the package handles layout, alignment, and answer key generation % automatically. % % \medskip % \textbf{Key features:} % \begin{itemize} % \item \textbf{8 Dedicated Question Types}: MC, TF, FillBlank, Ordering, % Matching, Essay, ShortAnswer, and Reading Passage (ReadingPassage). % \item \textbf{Automated Answer Keys}: Answers are collected and displayed % directly after each question in teacher mode. % \item \textbf{Smart Randomization}: Shuffles options, matching columns, % and ordering items in a reproducible manner. % \item \textbf{Metadata Display}: Show or hide marks, difficulty levels, % and question type tags. % \item \textbf{Dual-Mode Output}: Switch between student version (answers % hidden) and teacher version (answers shown). % \end{itemize} % % \section{Installation} % % The \texttt{exam-ltr} package is distributed through CTAN and is included % in all major LaTeX distributions (TeX Live, MiKTeX, MacTeX). In most cases, % no manual installation is needed; the system's package manager will handle % it automatically. % % If manual installation is required, use one of the following methods. % % \subsection*{Quick Installation (Single Project)} % % This method is suitable for users who need the package for a single document. % % \begin{enumerate} % \item Copy \texttt{exam-ltr.sty} into the same folder as the main % \texttt{.tex} file. % \item Add \texttt{\textbackslash usepackage\{exam-ltr\}} to the document % preamble. % \end{enumerate} % % \subsection*{Permanent Installation (System-Wide)} % % This method installs the package into the user's local TeX tree, making it % available for all future documents. % % \subsubsection*{Linux / macOS} % % \begin{enumerate} % \item Create the target directory:\\ % \texttt{mkdir -p \~{}/texmf/tex/latex/exam-ltr} % % \item Copy the package file into this directory:\\ % \texttt{cp exam-ltr.sty \~{}/texmf/tex/latex/exam-ltr/} % % \item Update the LaTeX file database:\\ % \texttt{texhash \~{}/texmf} % \end{enumerate} % % \subsubsection*{Windows} % % \begin{itemize} % \item \textbf{MiKTeX:} % \begin{enumerate} % \item Create the folder: % \texttt{C:\textbackslash texmf\textbackslash tex\textbackslash latex\textbackslash exam-ltr} % \item Copy \texttt{exam-ltr.sty} into it. % \item Refresh the database via the MiKTeX Console (``Refresh FNDB''). % \end{enumerate} % % \item \textbf{TeX Live:}: % \begin{enumerate} % \item Create the folder: % \texttt{C:\textbackslash texlive\textbackslash texmf-local\textbackslash tex\textbackslash latex\textbackslash exam-ltr} % \item Copy \texttt{exam-ltr.sty} into it. % \item Refresh the database by running \texttt{texhash}. % \end{enumerate} % \end{itemize} % % \subsection*{Requirements} % % The package requires the following LaTeX packages, which are loaded % automatically: \texttt{xcolor}, \texttt{tcolorbox}, \texttt{expl3}, % and \texttt{xparse}. % % \subsection*{Engine Compatibility} % % The package is compatible with all major LaTeX engines: % pdfLaTeX, LuaLaTeX, and XeLaTeX. % % \section{Quick Start} % % This section outlines the standard workflow for creating an exam with % the \texttt{exam-ltr} package. % % \subsection*{Step 1: Load the Package and Configure Mode} % % Include the package in your document preamble and set the desired output % mode: % % \begin{flushleft}\ttfamily % \cs{documentclass}\{article\}\\ % \cs{usepackage}\{exam-ltr\}\\[1em] % \cs{TeacherMode} \quad \% Show answer keys\\ % \cs{ShowMarks} \quad \% Display marks\\ % \cs{ShowCorrection} \quad \% Show answer boxes\\ % \cs{ExamID}\{123\} \quad \% Fix randomization seed % \end{flushleft} % % \subsection*{Step 2: Structure Your Questions} % % Wrap every question in the \texttt{Question} environment. You must % specify four arguments: \meta{Type}, \meta{Difficulty}, \meta{Marks}, % and \meta{Question text}: % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\marg{Type}\marg{Difficulty}\marg{Marks}\marg{Question text}\\ % \hspace*{2em}\textit{question content}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection*{Step 3: Choose the Environment for Your Question} % % Inside the \texttt{Question} environment, select the environment that % matches your question type: \texttt{MC} (Multiple Choice), \texttt{TF} % (True/False), \texttt{FillBlank}, \texttt{Ordering}, \texttt{Matching}, % \texttt{Essay}, \texttt{ShortAnswer}, or \texttt{ReadingPassage}. % % \subsection*{Step 4: Compile and View Output} % % Compile your document with \texttt{pdflatex} (or \texttt{xelatex}/ % \texttt{lualatex}). The output depends on the mode set in Step 1: % % \begin{itemize} % \item \textbf{Student Mode (default):} Answer keys are hidden. % \item \textbf{Teacher Mode:} Answer keys appear when \cs{ShowCorrection} % is also enabled. % \end{itemize} % % \subsection*{Minimal Working Example} % % \begin{flushleft}\ttfamily % \cs{documentclass}\{article\}\\ % \cs{usepackage}\{exam-ltr\}\\[1em] % \cs{TeacherMode}\\ % \cs{ShowCorrection}\\[1em] % \cs{begin}\{document\}\\[1em] % \cs{begin}\{Question\}\{MC\}\{Easy\}\{2\}\{Multiple Choice Quiz\}\\ % \hspace*{2em}\cs{begin}\{MC\}\\ % \hspace*{4em}\cs{MCQuestion}\{What is 2+2?\}\{2\}\\ % \hspace*{6em}\cs{MCOption}\{3\}\\ % \hspace*{6em}\cs{MCOption}\{4\}\\ % \hspace*{6em}\cs{MCOption}\{5\}\\ % \hspace*{2em}\cs{end}\{MC\}\\ % \cs{end}\{Question\}\\[1em] % \cs{end}\{document\} % \end{flushleft} % % \section{Mode Commands} % % The package provides several switches that control the appearance of % the final exam sheet. These switches allow you to toggle between student % and teacher views, display metadata, and show answer boxes. % % \subsection*{Student and Teacher Modes} % % \DescribeMacro{\StudentMode} % \DescribeMacro{\TeacherMode} % These commands toggle between student and teacher views. % % \begin{flushleft}\ttfamily % \cs{StudentMode} \quad \% Hide answer keys (default)\\ % \cs{TeacherMode} \quad \% Show answer keys % \end{flushleft} % % The default mode is \cs{StudentMode}. When \cs{TeacherMode} is active, % answer keys become visible. % % \subsection*{Metadata Visibility} % % \DescribeMacro{\ShowMarks} % \DescribeMacro{\ShowDifficulty} % \DescribeMacro{\ShowType} % These commands control the visibility of question metadata. % % \begin{flushleft}\ttfamily % \cs{ShowMarks} \quad \% Display marks\\ % \cs{ShowDifficulty} \quad \% Display difficulty levels\\ % \cs{ShowType} \quad \% Display question type % \end{flushleft} % % Each switch is independent; any combination may be enabled. % % \subsection*{Correction Boxes} % % \DescribeMacro{\ShowCorrection} % Enables the display of correction boxes for teacher use. % % \begin{flushleft}\ttfamily % \cs{ShowCorrection} % \end{flushleft} % % Only takes effect when \cs{TeacherMode} is explicitly enabled. % % \subsection*{Randomization Seed} % % \DescribeMacro{\ExamID} % Sets a fixed seed for all randomization operations (shuffling MC options, % ordering items, and matching pairs). % % \begin{flushleft}\ttfamily % \cs{ExamID}\marg{number} % \end{flushleft} % % Using the same seed guarantees identical output across compilations. % % \section{Question Environment} % % \DescribeEnv{Question} % The Question environment is the primary container for all question % types. It handles automatic numbering, manages metadata display % (type, difficulty, marks), and integrates answer key collection % in teacher mode. % % \subsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\marg{Type}\marg{Difficulty}\marg{Marks}\marg{Question Text}\\ % \hspace*{2em}\textit{question content}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection*{Arguments} % % \begin{itemize} % \item \meta{Type}: Question category (MC, TF, FillBlank, Ordering, % Matching, Essay, ShortAnswer, ReadingPassage). % \item \meta{Difficulty}: Descriptive label (e.g., Easy, Medium, Hard). % \item \meta{Marks}: Numeric score assigned to the question. % \item \meta{Question Text}: Main prompt or instruction. % \end{itemize} % % \subsection*{How It Works} % % \begin{itemize} % \item \textbf{Automatic Numbering:} Questions are numbered sequentially. % % \item \textbf{Metadata Display:} When enabled via \cs{ShowType}, % \cs{ShowDifficulty}, and \cs{ShowMarks}, the corresponding % labels are displayed alongside the question. % % \item \textbf{Answer Key Collection:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, all answers are collected % and displayed in a dedicated answer key box. % % \item \textbf{Consistent Formatting:} All question types placed % inside this environment share consistent spacing and layout. % \end{itemize} % % \subsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{Matching\}\{Easy\}\{3\}\{Match the opposite words.\}\\ % \hspace*{2em}\cs{begin}\{Matching\}\\ % \hspace*{4em}\cs{MatchPair}\{Tall\}\{Short\}\\ % \hspace*{4em}\cs{MatchPair}\{Big\}\{Small\}\\ % \hspace*{4em}\cs{MatchPair}\{High\}\{Low\}\\ % \hspace*{2em}\cs{end}\{Matching\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \section{Question Types} % % \subsection{Multiple Choice (MC)} % \DescribeEnv{MC} % \DescribeMacro{\MCQuestion} % \DescribeMacro{\MCOption} % The MC environment creates multiple-choice questions with automatically % shuffled options. Multiple questions can be placed inside a single % MC environment, each with its own set of options. The correct answer % is stored internally and appears in the answer key in teacher mode. % Options are displayed in a grid layout with a customizable number % of columns. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{MC\}\oarg{columns}\\ % \hspace*{2em}\cs{MCQuestion}\marg{question text}\marg{correct\_index}\\ % \hspace*{4em}\cs{MCOption}\marg{option 1}\\ % \hspace*{4em}\cs{MCOption}\marg{option 2}\\ % \hspace*{4em}\cs{MCOption}\marg{option 3}\\ % \hspace*{4em}...\\ % \cs{end}\{MC\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Column Layout (Default: 4):} The optional \oarg{columns} % argument sets the number of columns for displaying options. % Any number can be used as long as it fits the page width. % % \item \textbf{Correct Answer Index:} The \marg{correct\_index} % is a single number indicating which option is correct % (e.g., 2 means the second option is correct). This index % is used internally to track the correct answer after % shuffling. % % \item \textbf{Randomization:} All options inside \cs{MCQuestion} % are shuffled based on the global exam seed set by % \cs{ExamID}. This ensures reproducibility when a fixed % seed is provided. % % \item \textbf{Answer Key Integration:} The correct answer is % collected automatically and displayed in the answer key % when \cs{TeacherMode} and \cs{ShowCorrection} are enabled. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{MC\}\{Easy\}\{1\}\{Basic Arithmetic\}\\ % \hspace*{2em}\cs{begin}\{MC\}[3]\\ % \hspace*{4em}\cs{MCQuestion}\{What is 2+2?\}\{2\}\\ % \hspace*{6em}\cs{MCOption}\{3\}\\ % \hspace*{6em}\cs{MCOption}\{4\}\\ % \hspace*{6em}\cs{MCOption}\{5\}\\ % \hspace*{2em}\cs{end}\{MC\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{True/False (TF)} % \DescribeEnv{TF} % \DescribeMacro{\TFQuestion} % The TF environment creates True/False questions. Multiple statements % can be placed inside a single TF environment, each with its own % correct answer. Two display styles are available: bracket style % (default) and options style, allowing flexibility for different % assessment needs. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{TF\}\oarg{style}\\ % \hspace*{2em}\cs{TFQuestion}\marg{statement}\marg{answer}\\ % \hspace*{2em}\cs{TFQuestion}\marg{statement}\marg{answer}\\ % \hspace*{2em}...\\ % \cs{end}\{TF\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Visual Style:} The optional \oarg{style} argument % selects the display format: % \begin{itemize} % \item \texttt{bracket} (default): Places an empty answer slot % \texttt{( )} after each statement. % \item \texttt{options}: Places ``True'' and ``False'' labels % to the right of each statement. % \end{itemize} % % \item \textbf{Statement Input:} The \marg{statement} argument % receives the text that students must evaluate. % % \item \textbf{Answer Specification:} The \marg{answer} argument % accepts any text, which will be displayed in the answer key % as provided (e.g., ``True'', ``False'', ``T'', ``F''). % % \item \textbf{Answer Key:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, the correct answers are % collected and displayed in the answer key. % % \item \textbf{Multiple Questions:} Multiple \cs{TFQuestion} % commands can be placed sequentially within one TF environment. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{TF\}\{Easy\}\{2\}\{True or False\}\\ % \hspace*{2em}\cs{begin}\{TF\}[bracket]\\ % \hspace*{4em}\cs{TFQuestion}\{The Earth is flat.\}\{False\}\\ % \hspace*{4em}\cs{TFQuestion}\{Water boils at 100°C.\}\{True\}\\ % \hspace*{2em}\cs{end}\{TF\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{Fill in the Blank (FillBlank)} % \DescribeEnv{FillBlank} % \DescribeMacro{\WordBank} % \DescribeMacro{\FillQuestion} % \DescribeMacro{\Blank} % The FillBlank environment creates fill-in-the-blank questions where % students complete sentences with appropriate words. It supports % single or multiple blanks per question, multiple correct answers % per blank (separated by \texttt{\textbar}), and an optional word % bank to assist students during assessment. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{FillBlank\}\oarg{wordbank}\\ % \hspace*{2em}\cs{WordBank}\oarg{separator}\marg{word1, word2, ...}\\ % \hspace*{2em}\cs{FillQuestion}\marg{text with \cs{Blank}}\marg{answer}\\ % \cs{end}\{FillBlank\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Blank Creation:} The \cs{Blank} command creates an % underline field where students write their answers. % Its optional argument \oarg{width} sets the line length % (default: 4.25em). % % \item \textbf{Word Bank Activation:} The optional \oarg{wordbank} % argument controls whether a word bank is displayed. % Set to \texttt{true} to show a framed list of words % above the questions (default is \texttt{false}). % % \item \textbf{Word Bank Configuration:} The \cs{WordBank} command % defines the vocabulary list. Words must be separated by commas. % The optional \oarg{separator} controls spacing between words % (default: \cs{quad}). % % \item \textbf{Multiple Answers:} When a question has multiple blanks, % separate the answers with \texttt{\textbar} in the order % they appear. Example: \texttt{Red\textbar Green\textbar Blue}. % % \item \textbf{Answer Key:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, correct answers are % collected and displayed in a dedicated answer key box. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{FillBlank\}\{Medium\}\{4\}\{Complete the sentences\}\\ % \hspace*{2em}\cs{begin}\{FillBlank\}[true]\\ % \hspace*{4em}\cs{WordBank}\{gravity, light, oxygen\}\\ % \hspace*{4em}\cs{FillQuestion}\{Humans need \cs{Blank}\ to breathe.\}\{oxygen\}\\ % \hspace*{4em}\cs{FillQuestion}\{Plants need \cs{Blank}\ from the sun.\}\{light\}\\ % \hspace*{2em}\cs{end}\{FillBlank\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{Ordering} % \DescribeEnv{Ordering} % \DescribeMacro{\OrderQuestion} % \DescribeMacro{\OrderOption} % \DescribeMacro{\OrderAnswer} % The Ordering environment creates sequencing questions where students % must arrange items in their correct logical order. Items must be % written in their proper sequence inside the environment, but are % presented to students in a shuffled layout. The original order % is preserved for the teacher's answer key. Options are displayed % in a grid layout with a customizable number of columns. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{Ordering\}\oarg{columns}\\ % \hspace*{2em}\cs{OrderQuestion}\marg{instruction}\\ % \hspace*{4em}\cs{OrderOption}\marg{item 1}\\ % \hspace*{4em}\cs{OrderOption}\marg{item 2}\\ % \hspace*{4em}\cs{OrderOption}\marg{item 3}\\ % \hspace*{4em}...\\ % \hspace*{2em}\cs{OrderAnswer}\oarg{width}\\ % \cs{end}\{Ordering\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Correct Sequence:} Items must be written inside % \cs{OrderOption} in their correct logical order. This order % is preserved for the answer key. % % \item \textbf{Randomization:} Items are shuffled for the student % based on the global exam seed (\cs{ExamID}), ensuring % consistent randomization across compilations. % % \item \textbf{Column Layout (Default: 4):} The optional \oarg{columns} argument % sets the number of columns for displaying shuffled items. % Any number can be used as long as it fits the page width. % % \item \textbf{Answer Space:} The \cs{OrderAnswer} command adds % an optional answer space (with customizable width) where % students write their final ordered sequence. % % \item \textbf{Answer Key:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, the correct sequence is % collected and displayed in the answer key. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{Ordering\}\{Medium\}\{3\}\{Arrange in correct order\}\\ % \hspace*{2em}\cs{begin}\{Ordering\}[3]\\ % \hspace*{4em}\cs{OrderQuestion}\{Steps of the water cycle\}\\ % \hspace*{6em}\cs{OrderOption}\{Evaporation\}\\ % \hspace*{6em}\cs{OrderOption}\{Condensation\}\\ % \hspace*{6em}\cs{OrderOption}\{Precipitation\}\\ % \hspace*{4em}\cs{OrderAnswer}\\ % \hspace*{2em}\cs{end}\{Ordering\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{Matching} % \DescribeEnv{Matching} % \DescribeMacro{\MatchPair} % The Matching environment creates two-column association questions. % Items must be written in their correct pairs inside the environment. % The left column remains fixed and numbered, while the right column % is automatically shuffled for students. The original pairings % are preserved for the teacher's answer key. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{Matching\}\oarg{left\_ratio}\\ % \hspace*{2em}\cs{MatchPair}\marg{left item}\marg{right item}\\ % \hspace*{2em}\cs{MatchPair}\marg{left item}\marg{right item}\\ % \hspace*{2em}...\\ % \cs{end}\{Matching\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Pair Definition:} Each pair is defined using \cs{MatchPair}. % The order of definition determines the correct answer key. % The left column is fixed and numbered, while the right column % is automatically shuffled. % % \item \textbf{Column Width Control:} The optional \oarg{left\_ratio} % adjusts the width of the left column as a decimal fraction % between 0 and 1. Default is 0.5 (equal split). This is useful % when the left column contains short terms and the right column % has lengthy descriptions (e.g., 0.3 for 30\% width). % % \item \textbf{Randomization:} The right column is shuffled based on % the global exam seed (\cs{ExamID}), ensuring consistency % across compilations. % % \item \textbf{Answer Key:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, the correct mappings are % displayed as numbered-to-lettered pairs (e.g., (1) $\Rightarrow$ (b)). % % \item \textbf{Capacity:} Supports a maximum of 26 pairs per question % (limited by the alphabet A--Z). % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{Matching\}\{Medium\}\{4\}\{Match countries with capitals\}\\ % \hspace*{2em}\cs{begin}\{Matching\}[0.3]\\ % \hspace*{4em}\cs{MatchPair}\{France\}\{Paris\}\\ % \hspace*{4em}\cs{MatchPair}\{Germany\}\{Berlin\}\\ % \hspace*{4em}\cs{MatchPair}\{Italy\}\{Rome\}\\ % \hspace*{2em}\cs{end}\{Matching\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{Essay} % \DescribeEnv{Essay} % \DescribeMacro{\EssayQuestion} % The Essay environment creates open-ended, long-form written response % questions. It provides a writing area with either ruled lines or % blank space, depending on the selected style. The instructor's % answer summary is stored and displayed in the answer key in teacher % mode. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{Essay\}\oarg{lines}\\ % \hspace*{2em}\cs{EssayQuestion}\oarg{line\_count}\marg{question}\marg{answer summary}\\ % \hspace*{2em}...\\ % \cs{end}\{Essay\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Writing Space Style:} The optional environment argument % \oarg{lines} controls the appearance of the writing area: % \begin{itemize} % \item \texttt{true}: Generates ruled notebook lines (default). % \item \texttt{false}: Provides blank white space for free-form % text or diagrams. % \end{itemize} % % \item \textbf{Writing Space Size (Default: 4):} The optional \oarg{line\_count} % argument specifies the number of lines allocated for the % student's answer. % % \item \textbf{Question Components:} \cs{EssayQuestion} command % takes two mandatory arguments: the question prompt and a % concise answer summary for the instructor's reference. % % \item \textbf{Multiple Questions:} Multiple \cs{EssayQuestion} % commands can be placed sequentially within one Essay environment. % % \item \textbf{Answer Key:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, all answer summaries are % collected and displayed in a dedicated answer key box. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{Essay\}\{Hard\}\{10\}\{Written Response\}\\ % \hspace*{2em}\cs{begin}\{Essay\}[true]\\ % \hspace*{4em}\cs{EssayQuestion}\{What is cloud computing?\}\{Cloud computing\}\\ % \hspace*{4em}\cs{EssayQuestion}[10]\{What is cybersecurity?\}\{Cybersecurity\}\\ % \hspace*{2em}\cs{end}\{Essay\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{Short Answer (ShortAnswer)} % \DescribeEnv{ShortAnswer} % \DescribeMacro{\ShortQuestion} % The ShortAnswer environment creates questions that require brief, % direct responses — such as single words, short phrases, or concise % statements. The answer space can be customized (0, 1, or 2 lines) % to keep the exam layout clear and space-efficient. The instructor's % answer is stored and displayed in the answer key in teacher mode. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{ShortAnswer\}\oarg{lines}\\ % \hspace*{2em}\cs{ShortQuestion}\oarg{size}\marg{question}\marg{answer}\\ % \hspace*{2em}...\\ % \cs{end}\{ShortAnswer\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Writing Space Style:} The optional environment argument % \oarg{lines} controls the appearance of the answer space: % \begin{itemize} % \item \texttt{true}: Generates ruled notebook lines (default). % \item \texttt{false}: Provides blank white space without lines. % \end{itemize} % % \item \textbf{Answer Space Size:} The optional \oarg{size} argument % specifies the number of lines for the student's answer: % \begin{itemize} % \item \texttt{0}: Prints a short underline directly after the % question text — ideal for single-word answers. % (Always prints a line regardless of the environment style.) % \item \texttt{1}: Generates a one-line writing space below the % question. % \item \texttt{2}: Generates a two-line writing space below the % question. % \end{itemize} % % \item \textbf{Question Components:} \cs{ShortQuestion} command % takes two mandatory arguments: the question prompt and the % model answer or keyword solution. % % \item \textbf{Multiple Questions:} Multiple \cs{ShortQuestion} % commands can be placed sequentially within one ShortAnswer % environment. % % \item \textbf{Answer Key:} When \cs{TeacherMode} and % \cs{ShowCorrection} are enabled, all answers are collected % and displayed in a dedicated answer key box. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{ShortAnswer\}\{Easy\}\{3\}\{Answer briefly\}\\ % \hspace*{2em}\cs{begin}\{ShortAnswer\}[true]\\ % \hspace*{4em}\cs{ShortQuestion}[0]\{Diameter of Earth?\}\{12,742 km\}\\ % \hspace*{4em}\cs{ShortQuestion}[1]\{Strongest gravity planet?\}\{Jupiter\}\\ % \hspace*{2em}\cs{end}\{ShortAnswer\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \subsection{Reading Passage} % \DescribeEnv{ReadingPassage} % The ReadingPassage environment provides a container for reading % comprehension texts. The passage is printed exactly as written — % preserving all formatting, paragraph breaks, and inline styling — % without any modification or randomization. The passage is displayed % in a standalone box, and authors can place any question type after % it to assess comprehension. % % \subsubsection*{Syntax} % % \begin{flushleft}\ttfamily % \cs{begin}\{ReadingPassage\}\marg{title}\\ % \hspace*{2em}\textit{passage text}\\ % \cs{end}\{ReadingPassage\} % \end{flushleft} % % \subsubsection*{How It Works} % % \begin{itemize} % \item \textbf{Passage Rendering:} The text is displayed in a framed % box, exactly as entered, preserving all formatting. % % \item \textbf{Title:} The mandatory \marg{title} argument sets the % centered heading above the passage. If left empty \{\}, % the default title ``Reading Passage'' is used. % % \item \textbf{Content Flexibility:} The passage can include multiple % paragraphs, inline text styles (bold, italic, etc.), and % custom lists. % % \item \textbf{Question Integration:} Any question type can follow % a ReadingPassage within the same \texttt{Question} block % to assess comprehension. % \end{itemize} % % \subsubsection*{Example} % % \begin{flushleft}\ttfamily % \cs{begin}\{Question\}\{ReadingPassage\}\{Medium\}\{10\}\{Read and answer\}\\ % \hspace*{2em}\cs{begin}\{ReadingPassage\}\{The Solar System\}\\ % \hspace*{4em}\textit{Our solar system has eight planets that orbit the Sun: }\\ % \hspace*{4em}\textit{Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and}\\ % \hspace*{4em}\textit{Neptune.}\\ % \hspace*{2em}\cs{end}\{ReadingPassage\}\\[2pt] % \hspace*{2em}\cs{begin}\{FillBlank\}\\ % \hspace*{4em}\cs{FillQuestion}\{\cs{Blank}\ is the smallest planet.\}\{Mercury\}\\ % \hspace*{4em}\cs{FillQuestion}\{\cs{Blank}\ is the largest planet.\}\{Jupiter\}\\ % \hspace*{2em}\cs{end}\{FillBlank\}\\ % \cs{end}\{Question\} % \end{flushleft} % % \section{Complete Example} % % A fully functional sample exam file, \texttt{example.tex}, is % included with the package to demonstrate its capabilities in a realistic % academic context. The example file covers all question types supported % by the package: \texttt{MC}, \texttt{TF}, \texttt{Ordering}, % \texttt{FillBlank}, \texttt{Matching}, \texttt{ShortAnswer}, % \texttt{Essay}, and \texttt{ReadingPassage}. % % \medskip % \textbf{Usage Instructions:} % % \begin{enumerate} % \item Ensure you have the file \texttt{example.tex} in your % working directory (usually found in the package documentation % folder). % % \item Open it in your \LaTeX{} editor and compile with \texttt{pdflatex}, % \texttt{xelatex}, or \texttt{lualatex}. % % \item To switch between student and teacher views, uncomment or comment % the \cs{TeacherMode} and \cs{ShowCorrection} commands in the % preamble. This toggles the display of answer keys and correction % boxes. % \end{enumerate} % % \section{Common Mistakes} % % The following list addresses frequent errors encountered during exam % creation. Adhering to these guidelines ensures correct compilation % and output. % % \begin{itemize} % \item \textbf{Enabling \cs{ShowCorrection} without \cs{TeacherMode}:} % \cs{ShowCorrection} alone does not display answers. Both % \cs{TeacherMode} and \cs{ShowCorrection} must be active for % solutions to appear. % % \item \textbf{Omitting the \texttt{Question} Environment:} % All question types must be wrapped inside the \texttt{Question} % environment. Failing to do so prevents metadata and answer keys % from appearing. % % \item \textbf{Using Invalid Type Identifiers:} % The first argument of \texttt{Question} must be a valid % identifier: \texttt{MC}, \texttt{TF}, \texttt{FillBlank}, % \texttt{Ordering}, \texttt{Matching}, \texttt{Essay}, % \texttt{ShortAnswer}, or \texttt{ReadingPassage}. Using % non-standard identifiers (e.g., \texttt{MCQ}) will result in % missing or incorrect metadata labels. % % \item \textbf{Missing Pipe Separator in \texttt{FillBlank}:} % For questions with multiple answers, separate them with a % vertical pipe \texttt{\textbar} (e.g., \texttt{Red\textbar Green\textbar Blue}). % Omitting this causes the package to treat multiple answers as % a single string. % % \item \textbf{Incorrect Column Placement in \texttt{Matching}:} % The \texttt{Matching} environment always shuffles the right % column. Items intended for randomization must be placed in % the second argument. Placing them in the first argument results % in an illogical question. % % \item \textbf{Incorrect Input Sequence in \texttt{Ordering}:} % The order in which you write the \cs{OrderOption} commands % in your document defines the correct answer. Entering them % in the wrong order will result in incorrect grading. % % \item \textbf{Omitting the Title in \texttt{ReadingPassage}:} % The \texttt{ReadingPassage} environment requires a title % argument. If no custom title is needed, use empty braces % \texttt{\{\}}. Omitting the argument causes LaTeX to misinterpret % the first character of the passage text as the title. % \end{itemize} % % \section{Known Limitations} % % The \texttt{exam-ltr} package has the following limitations in its % current version. % % \begin{itemize} % \item \textbf{Directionality:} % The package is optimized for Left-to-Right (LTR) languages % (e.g., English). For Right-to-Left (RTL) languages (e.g., Arabic), % use the companion package \texttt{exam-rtl}. % % \item \textbf{Mandatory Randomization:} % Option shuffling cannot be fully disabled. Even without the % \cs{ExamID} macro, a default randomization is applied. % % \item \textbf{Scope of Randomization:} % Randomization is limited to internal elements: choices in % \texttt{MC}, items in \texttt{Ordering}, and the right-hand % column in \texttt{Matching}. Shuffling the entire sequence % of question blocks is not supported in this version. % % \item \textbf{Item Capacity:} % Each question within \texttt{Ordering} and \texttt{Matching} % is limited to a maximum of 26 items (tracked using Latin % letters A--Z). % % \item \textbf{Answer Key Placement:} % Answer keys are displayed individually beneath each question. % A centralized answer sheet at the end of the document is not % supported in this version. % \end{itemize} % % \section{License} % % This package is distributed under the LaTeX Project Public License (LPPL), % version 1.3c or later. % % The latest version of this license is available at: % \url{http://www.latex-project.org/lppl.txt} % % \StopEventually{^^A % \PrintChanges % \PrintIndex % } % % \section{Implementation} % % This section contains the complete source code of the \texttt{exam-ltr} % package. Each macro, variable, and environment is documented with its % purpose and usage. % % \iffalse %<*package> % \fi % % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{exam-ltr}[2026/08/20 v1.0 LTR Exam Core] \RequirePackage{xcolor} \RequirePackage{tcolorbox} \tcbuselibrary{skins, breakable} \RequirePackage{expl3} \RequirePackage{xparse} % \end{macrocode} % \begin{macrocode} \ExplSyntaxOn \cs_generate_variant:Nn \tl_if_eq:nnT { VVT } \cs_generate_variant:Nn \msg_warning:nnn { nnx } % \end{macrocode} % \begin{macro}{\PrintNumber} % Converts a number to its standard representation. % \begin{macrocode} \newcommand{\PrintNumber}[1]{\number#1} % \end{macrocode} % \end{macro} % \begin{macro}{\g__mode_teacher_bool} % \begin{macro}{\g__mode_marks_bool} % \begin{macro}{\g__mode_difficulty_bool} % \begin{macro}{\g__mode_type_bool} % \begin{macro}{\g__mode_correction_bool} % Core boolean variables for controlling mode and metadata visibility. % \begin{macrocode} \bool_new:N \g__mode_teacher_bool \bool_new:N \g__mode_marks_bool \bool_new:N \g__mode_difficulty_bool \bool_new:N \g__mode_type_bool \bool_new:N \g__mode_correction_bool % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\g__exam_id_int} % \begin{macro}{\g__question_number_int} % \begin{macro}{\g__question_seed_int} % Core integer variables for exam ID, question numbering, and seed. % \begin{macrocode} \int_new:N \g__exam_id_int \int_new:N \g__question_number_int \int_new:N \g__question_seed_int % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\g__question_answer_tl} % \begin{macro}{\g__question_type_tl} % \begin{macro}{\g__question_level_tl} % \begin{macro}{\g__question_marks_tl} % Token lists for storing question data. % \begin{macrocode} \tl_new:N \g__question_answer_tl \tl_new:N \g__question_type_tl \tl_new:N \g__question_level_tl \tl_new:N \g__question_marks_tl % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\g__question_type_prop} % Property list that maps question type identifiers to their display names. % \begin{macrocode} \prop_new:N \g__question_type_prop \prop_put:Nnn \g__question_type_prop {MC} {Multiple~Choice} \prop_put:Nnn \g__question_type_prop {TF} {True/False} \prop_put:Nnn \g__question_type_prop {FillBlank} {Fill~in~the~Blank} \prop_put:Nnn \g__question_type_prop {Ordering} {Ordering} \prop_put:Nnn \g__question_type_prop {Matching} {Matching} \prop_put:Nnn \g__question_type_prop {Essay} {Essay} \prop_put:Nnn \g__question_type_prop {ShortAnswer} {Short~Answer} \prop_put:Nnn \g__question_type_prop {ReadingPassage} {Reading~Passage} % \end{macrocode} % \end{macro} % \begin{macro}{\g__exam_letters_seq} % Sequence of Latin letters (a--z) for labeling options. % \begin{macrocode} \seq_new:N \g__exam_letters_seq \seq_set_from_clist:Nn \g__exam_letters_seq { a , b , c , d , e , f , g , h , i , j , k , l , m , n , o , p , q , r , s , t , u , v , w , x , y , z } % \end{macrocode} % \end{macro} % \begin{macro}{\StudentMode} % \begin{macro}{\TeacherMode} % Set the teacher/student mode booleans. % \begin{macrocode} \NewDocumentCommand{\StudentMode}{} { \bool_gset_false:N \g__mode_teacher_bool } \NewDocumentCommand{\TeacherMode}{} { \bool_gset_true:N \g__mode_teacher_bool } % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\ShowType} % \begin{macro}{\ShowDifficulty} % \begin{macro}{\ShowMarks} % \begin{macro}{\ShowCorrection} % Set metadata visibility booleans. % \begin{macrocode} \NewDocumentCommand{\ShowType}{} { \bool_gset_true:N \g__mode_type_bool } \NewDocumentCommand{\ShowDifficulty}{} { \bool_gset_true:N \g__mode_difficulty_bool } \NewDocumentCommand{\ShowMarks}{} { \bool_gset_true:N \g__mode_marks_bool } \NewDocumentCommand{\ShowCorrection}{} { \bool_gset_true:N \g__mode_correction_bool } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\ExamID} % Sets the randomization seed. Use \texttt{0} for default system seed. % \begin{macrocode} \NewDocumentCommand{\ExamID}{m}{ \int_gset:Nn \g__exam_id_int {#1} \sys_gset_rand_seed:n {#1} } % \end{macrocode} % \end{macro} % \begin{macro}{\__question_build_seed} % Builds a unique seed for each question based on the exam ID and % question number. This ensures consistent randomization across % compilations. % \begin{macrocode} \cs_new_protected:Npn \__question_build_seed: { \int_gset:Nn \g__question_seed_int { \int_eval:n { \g__exam_id_int * 1000 + \g__question_number_int } } \sys_gset_rand_seed:n { \g__question_seed_int } } % \end{macrocode} % \end{macro} % \begin{macro}{\__exam_print_answer_box} % Prints a formatted answer key box in teacher mode. % \begin{macrocode} \cs_new_protected:Npn \__exam_print_answer_box: { \par\smallskip \begin{tcolorbox}[ enhanced, breakable, colback=white, colframe=black, arc=0pt, outer~arc=0pt, boxrule=1pt, top=10pt, bottom=10pt, left=10pt, right=10pt, parbox=true, fontupper=\linespread{1.2}\selectfont, before~upper={\begin{flushleft}}, after~upper={\end{flushleft}}, coltitle=black, fonttitle=\bfseries, title={Answer~Key}, attach~boxed~title~to~top~left={ xshift=5mm, yshift=-3.5mm }, boxed~title~style={ colback=white, colframe=white, left=5pt, right=5pt } ]{ \setlength{\baselineskip}{1.2\normalbaselineskip} \tl_use:N \g__question_answer_tl } \end{tcolorbox} \par\smallskip } % \end{macrocode} % \end{macro} % \begin{environment}{Question} % Main container for all question types. Handles numbering, metadata, % and answer collection. % \begin{macrocode} \dim_new:N \g__question_number_width_dim \dim_new:N \g__question_metadata_width_dim \dim_new:N \g__question_text_width_dim \NewDocumentEnvironment{Question}{ m m m m } { \int_gincr:N \g__question_number_int \tl_gset:Nn \g__question_type_tl {#1} \tl_gset:Nn \g__question_level_tl {#2} \tl_gset:Nn \g__question_marks_tl {#3} \tl_gclear:N \g__question_answer_tl \__question_build_seed: \tl_clear:N \l_tmpa_tl \bool_if:nT { \g__mode_type_bool } { \tl_put_right:Nn \l_tmpa_tl { [\prop_item:Nn \g__question_type_prop {#1}] } } \bool_if:nT { \g__mode_difficulty_bool } { \tl_put_right:Nn \l_tmpa_tl { ~[#2] } } \bool_if:nT { \g__mode_marks_bool } { \tl_put_right:Nn \l_tmpa_tl { ~[#3~marks] } } \settowidth{\g__question_metadata_width_dim} { \footnotesize \l_tmpa_tl } \settowidth{\g__question_number_width_dim} { \bfseries Question~\PrintNumber{ \g__question_number_int }:~ } \dim_set:Nn \g__question_text_width_dim { \linewidth - \g__question_number_width_dim - \g__question_metadata_width_dim - 1em } \dim_compare:nNnT { \g__question_text_width_dim } < { 0pt } { \dim_set:Nn \g__question_text_width_dim { 0pt } } \par\medskip \noindent \makebox[\linewidth][l] { \makebox[\g__question_number_width_dim][l] {\bfseries Question~\PrintNumber{\g__question_number_int}:~} \parbox[t]{\g__question_text_width_dim} { \bfseries #4 } \hfill { \footnotesize \bool_if:nT { \g__mode_type_bool } { [\prop_item:Nn \g__question_type_prop {#1}] } \bool_if:nT { \g__mode_difficulty_bool } { ~[#2] } \bool_if:nT { \g__mode_marks_bool } { ~[#3~marks] } } } \par\smallskip } { \bool_if:nT { \g__mode_teacher_bool && \g__mode_correction_bool } { \tl_if_empty:NF \g__question_answer_tl { \__exam_print_answer_box: } } \par\smallskip } % \end{macrocode} % \end{environment} % \begin{environment}{MC} % Creates multiple-choice questions with shuffled options. % \begin{macrocode} \dim_new:N \l__mc_label_width_dim \dim_new:N \l__mc_label_sep_dim \dim_new:N \l__mc_col_sep_dim \dim_new:N \l__mc_text_width_dim \dim_set:Nn \l__mc_label_width_dim { 1.25em } \dim_set:Nn \l__mc_label_sep_dim { 0.5em } \dim_set:Nn \l__mc_col_sep_dim { 1.5em } \dim_new:N \l__mc_before_first_question_dim \dim_new:N \l__mc_after_question_text_dim \dim_new:N \l__mc_between_questions_dim \dim_new:N \l__mc_after_options_dim \dim_new:N \l__mc_between_option_lines_dim \dim_set:Nn \l__mc_before_first_question_dim { 0.2em } \dim_set:Nn \l__mc_after_question_text_dim { 0.4em } \dim_set:Nn \l__mc_between_questions_dim { 0.3em } \dim_set:Nn \l__mc_after_options_dim { 0.3em } \dim_set:Nn \l__mc_between_option_lines_dim { 0.7em } \int_new:N \l__mc_question_counter_int \int_new:N \l__mc_option_counter_int \int_new:N \l__mc_columns_int \int_new:N \l__mc_correct_index_int \seq_new:N \l__mc_options_seq \tl_new:N \l__mc_question_text_tl \NewDocumentEnvironment{MC}{ O{4} } { \int_set:Nn \l__mc_columns_int {#1} \int_zero:N \l__mc_question_counter_int \int_zero:N \l__mc_option_counter_int \par } { \int_compare:nNnT { \l__mc_option_counter_int } > { 0 } { \__mc_display_options: } \par } % \end{macrocode} % \end{environment} % \begin{macro}{\MCQuestion} % Defines a multiple-choice question within the MC environment. % \begin{macrocode} \NewDocumentCommand{\MCQuestion}{ m m } { \int_compare:nNnT { \l__mc_option_counter_int } > { 0 } { \__mc_display_options: \par\vspace{\l__mc_after_options_dim} } \int_incr:N \l__mc_question_counter_int \int_compare:nNnTF { \l__mc_question_counter_int } = { 1 } { \par\vspace{\l__mc_before_first_question_dim} } { \par\vspace{\l__mc_between_questions_dim} } \par\noindent \textbf{\PrintNumber{\l__mc_question_counter_int}.~#1} \par\vspace{\l__mc_after_question_text_dim} \int_set:Nn \l__mc_correct_index_int {#2} \int_zero:N \l__mc_option_counter_int \seq_clear:N \l__mc_options_seq } % \end{macrocode} % \end{macro} % \begin{macro}{\MCOption} % Defines an option for a multiple-choice question. % \begin{macrocode} \NewDocumentCommand{\MCOption}{ m } { \int_incr:N \l__mc_option_counter_int \seq_put_right:Nn \l__mc_options_seq {#1} } % \end{macrocode} % \end{macro} % \begin{macro}{\__mc_display_options} % Displays the shuffled options in a grid layout. % \begin{macrocode} \cs_new_protected:Npn \__mc_display_options: { \int_compare:nNnT { \l__mc_option_counter_int } = { 0 } { \msg_warning:nn { mc } { no-options } \par \scan_stop: } \tl_set:Nx \l_tmpa_tl { \seq_item:Nn \l__mc_options_seq { \l__mc_correct_index_int } } \seq_shuffle:N \l__mc_options_seq \int_set:Nn \l_tmpa_int {\int_mod:nn { \l__mc_option_counter_int} {\l__mc_columns_int }} \int_compare:nNnT { \l_tmpa_int } > { 0 } { \int_set:Nn \l_tmpb_int { \l__mc_columns_int - \l_tmpa_int } \prg_replicate:nn { \l_tmpb_int } { \seq_put_right:Nn \l__mc_options_seq { \hspace{0pt} } } } \dim_set:Nn \l_tmpb_dim { \int_eval:n { \l__mc_columns_int - 1 } \l__mc_col_sep_dim } \dim_set:Nn \l_tmpa_dim { ( \linewidth - \l_tmpb_dim ) / \l__mc_columns_int } \dim_set:Nn \l__mc_text_width_dim { \dim_eval:n { \l_tmpa_dim - \l__mc_label_width_dim - \l__mc_label_sep_dim } } \dim_compare:nNnT { \l__mc_text_width_dim } < { 0pt } { \dim_set:Nn \l__mc_text_width_dim { 0pt } } \noindent \int_step_inline:nn { \seq_count:N \l__mc_options_seq } { \tl_set:Nx \l_tmpb_tl {\seq_item:Nn \l__mc_options_seq {##1}} \makebox[\l_tmpa_dim][l] { \makebox[\l__mc_label_width_dim][r] { \int_compare:nNnTF {##1} > {\l__mc_option_counter_int} { \hspace{0pt} } { \seq_item:Nn \g__exam_letters_seq {##1}) } }% \hspace{\l__mc_label_sep_dim}% \parbox[t]{\l__mc_text_width_dim} { \setlength{\baselineskip}{1.2\normalbaselineskip} \raggedright \l_tmpb_tl \par }% } \int_compare:nNnT { ##1 } < { \l__mc_option_counter_int + 1 } { \tl_if_eq:VVT \l_tmpb_tl \l_tmpa_tl { \tl_gput_right:Nx \g__question_answer_tl { \exp_not:N \makebox[5.25em][l] { (\PrintNumber{\l__mc_question_counter_int})~ $\Rightarrow$~ (\seq_item:Nn \g__exam_letters_seq {##1}) }% \qquad } } } \int_compare:nNnF { \int_mod:nn {##1} { \l__mc_columns_int } } = { 0 } { \hspace{\l__mc_col_sep_dim} } \int_compare:nNnT { \int_mod:nn {##1} { \l__mc_columns_int } } = { 0 } { \par\prevdepth=\dp\strutbox% \vspace{\l__mc_between_option_lines_dim} \noindent } } \par } % \end{macrocode} % \end{macro} % \begin{macro}{\msg_new:nnn{mc}{no-options}} % Warning message for MC questions without options. % \begin{macrocode} \msg_new:nnn { mc } { no-options } { Warning: No options for question \int_use:N \l__mc_question_counter_int. } % \end{macrocode} % \end{macro} % \begin{environment}{TF} % Creates True/False questions with two display styles. % \begin{macrocode} \int_new:N \l__tf_question_counter_int \tl_new:N \l__tf_question_text_tl \tl_new:N \l__tf_correct_answer_tl \bool_new:N \l__tf_style_bool \dim_const:Nn \l__tf_number_width_dim { 5.3mm } \dim_const:Nn \l__tf_bracket_width_dim { 3em } \dim_const:Nn \l__tf_option_width_dim { 8em } \dim_new:N \l__tf_before_first_question_dim \dim_new:N \l__tf_between_questions_dim \dim_set:Nn \l__tf_before_first_question_dim { 0.3em } \dim_set:Nn \l__tf_between_questions_dim { 0.7em } \NewDocumentEnvironment{TF}{ O{bracket} } { \int_zero:N \l__tf_question_counter_int \str_if_eq:nnTF {#1} {bracket} { \bool_set_true:N \l__tf_style_bool } { \bool_set_false:N \l__tf_style_bool } } { \vspace{0.3em} } % \end{macrocode} % \end{environment} % \begin{macro}{\TFQuestion} % Defines a True/False question. % \begin{macrocode} \NewDocumentCommand{\TFQuestion}{ m m } { \int_incr:N \l__tf_question_counter_int \int_compare:nNnTF { \l__tf_question_counter_int } = { 1 } { \par\vspace{\l__tf_before_first_question_dim} } { \par\vspace{\l__tf_between_questions_dim} } \par\noindent \makebox[5.0mm][r] { \PrintNumber{\l__tf_question_counter_int}\vphantom{(}. }% \hspace{0.7em}% \bool_if:NTF \l__tf_style_bool { \parbox[t]{\dim_eval:n{\linewidth-8.0mm}} { \setlength{\baselineskip}{1.2\normalbaselineskip} #1\unskip\nobreak\hspace{1em}% \makebox[3em][c]{( \hspace{1.5em} )} \par } } { \parbox[t] {\dim_eval:n{\linewidth-8.0mm-\l__tf_option_width_dim}} { \setlength{\baselineskip}{1.2\normalbaselineskip} #1 \par }% \hfill \makebox[\l__tf_option_width_dim][c] { \makebox[3em][c]{True}% \hspace{1em}% \makebox[3em][c]{False} } } \par\prevdepth=\dp\strutbox% \tl_gput_right:Nx \g__question_answer_tl { \exp_not:N \makebox[5.25em][l] { (\PrintNumber{\l__tf_question_counter_int})~ $\Rightarrow$~ #2 }% \quad } } % \end{macrocode} % \end{macro} % \begin{environment}{FillBlank} % Creates fill-in-the-blank questions with optional word bank. % \begin{macrocode} \int_new:N \l__fb_question_counter_int \tl_new:N \l__fb_answer_tl \bool_new:N \l__fb_wordbank_bool \dim_const:Nn \l__fb_number_width_dim { 5.3mm } \dim_new:N \l__fb_before_first_question_dim \dim_new:N \l__fb_between_questions_dim \dim_set:Nn \l__fb_before_first_question_dim { 0.5em } \dim_set:Nn \l__fb_between_questions_dim { 0.8em } \NewDocumentEnvironment{FillBlank}{ O{false} } { \int_zero:N \l__fb_question_counter_int \tl_clear:N \l__fb_answer_tl \str_if_eq:nnTF {#1} {true} { \bool_set_true:N \l__fb_wordbank_bool } { \bool_set_false:N \l__fb_wordbank_bool } } { \tl_gset_eq:NN \g__question_answer_tl \l__fb_answer_tl \vspace{0.35em}% } % \end{macrocode} % \end{environment} % \begin{macro}{\WordBank} % Displays a dynamic word bank box. % \begin{macrocode} \NewDocumentCommand{\WordBank}{ O{\quad} m } { \bool_if:NT \l__fb_wordbank_bool { \par\vspace{0.5em}\noindent \tl_clear:N \l_tmpa_tl \clist_set:Nn \l_tmpa_clist {#2} \hbox_set:Nn \l_tmpa_box { \clist_use:Nn \l_tmpa_clist {#1} } \dim_set:Nn \l_tmpa_dim { \box_wd:N \l_tmpa_box } \dim_set:Nn \l_tmpb_dim { 0.9\linewidth } \dim_compare:nNnTF { \l_tmpa_dim } > { \l_tmpb_dim } { \dim_set:Nn \l_tmpa_dim { \l_tmpb_dim } } { } \dim_add:Nn \l_tmpa_dim { 10pt } \makebox[\linewidth][c] { \fbox {% \begin{minipage}{\l_tmpa_dim} \centering \vspace{4pt} \setlength{\baselineskip}{1.2\normalbaselineskip} \clist_use:Nn \l_tmpa_clist {#1} \vspace{3pt} \end{minipage}% } }% \par\vspace{0.3em} } } % \end{macrocode} % \end{macro} % \begin{macro}{\Blank} % Creates an underline field for student answers. % \begin{macrocode} \NewDocumentCommand{\Blank}{ O{4.25em} } { \underline{\hspace{#1}} } % \end{macrocode} % \end{macro} % \begin{macro}{\FillQuestion} % Defines a fill-in-the-blank question with its answer. % \begin{macrocode} \NewDocumentCommand{\FillQuestion}{ m m } { \int_incr:N \l__fb_question_counter_int \int_compare:nNnTF { \l__fb_question_counter_int } = { 1 } { \par\vspace{\l__fb_before_first_question_dim} } { \par\vspace{\l__fb_between_questions_dim} } \par\noindent \makebox[5.0mm][r] { \PrintNumber{\l__fb_question_counter_int}\vphantom{(}. }% \hspace{0.7em}% \parbox[t]{\dim_eval:n{\linewidth-8.0mm}} { \setlength{\baselineskip}{1.2\normalbaselineskip} #1 \par } \par\prevdepth=\dp\strutbox% \seq_set_split:Nnn \l_tmpa_seq { | } {#2} \int_zero:N \l_tmpa_int \seq_map_inline:Nn \l_tmpa_seq { \int_incr:N \l_tmpa_int \int_compare:nNnTF { \seq_count:N \l_tmpa_seq } > { 1 } { \tl_put_right:Nx \l__fb_answer_tl { \exp_not:N (\PrintNumber{\l__fb_question_counter_int} - \int_use:N \l_tmpa_int)~$\Rightarrow$~##1 \exp_not:N \par \exp_not:N \noindent } } { \tl_put_right:Nx \l__fb_answer_tl { \exp_not:N (\PrintNumber{\l__fb_question_counter_int})~ $\Rightarrow$~ ##1 \exp_not:N \par \exp_not:N \noindent } } } } % \end{macrocode} % \end{macro} % \begin{environment}{Ordering} % Creates sequencing questions with shuffled options. % \begin{macrocode} \int_new:N \l__ord_question_counter_int \int_new:N \l__ord_option_counter_int \int_new:N \l__ord_columns_int \seq_new:N \l__ord_options_seq \seq_new:N \l__ord_original_order_seq \tl_new:N \l__ord_answer_tl \bool_new:N \l__ord_answer_pending_bool \dim_new:N \l__ord_answer_width_dim \dim_set:Nn \l__ord_answer_width_dim { 1.5em } \dim_new:N \l__ord_label_width_dim \dim_new:N \l__ord_label_sep_dim \dim_new:N \l__ord_col_sep_dim \dim_new:N \l__ord_text_width_dim \dim_set:Nn \l__ord_label_width_dim { 1.25em } \dim_set:Nn \l__ord_label_sep_dim { 0.5em } \dim_set:Nn \l__ord_col_sep_dim { 1.5em } \dim_new:N \l__ord_before_first_question_dim \dim_new:N \l__ord_after_question_text_dim \dim_new:N \l__ord_between_questions_dim \dim_new:N \l__ord_after_options_dim \dim_new:N \l__ord_between_option_lines_dim \dim_set:Nn \l__ord_before_first_question_dim { 0.2em } \dim_set:Nn \l__ord_after_question_text_dim { 0.4em } \dim_set:Nn \l__ord_between_questions_dim { 0.3em } \dim_set:Nn \l__ord_after_options_dim { 0.3em } \dim_set:Nn \l__ord_between_option_lines_dim { 0.7em } \NewDocumentEnvironment{Ordering}{ O{4} } { \int_set:Nn \l__ord_columns_int {#1} \int_zero:N \l__ord_question_counter_int \int_zero:N \l__ord_option_counter_int \tl_clear:N \l__ord_answer_tl \seq_clear:N \l__ord_options_seq \seq_clear:N \l__ord_original_order_seq \bool_set_false:N \l__ord_answer_pending_bool \par } { \int_compare:nNnT { \l__ord_option_counter_int } > { 0 } { \__ord_display_options: } \tl_gset_eq:NN \g__question_answer_tl \l__ord_answer_tl \par } % \end{macrocode} % \end{environment} % \begin{macro}{\OrderQuestion} % Defines an ordering question. % \begin{macrocode} \NewDocumentCommand{\OrderQuestion}{ m } { \int_compare:nNnT { \l__ord_option_counter_int } > { 0 } { \__ord_display_options: \par\vspace{\l__ord_after_options_dim} } \int_incr:N \l__ord_question_counter_int \int_compare:nNnTF { \l__ord_question_counter_int } = { 1 } { \par\vspace{\l__ord_before_first_question_dim} } { \par\vspace{\l__ord_between_questions_dim} } \par\noindent \textbf{\PrintNumber{\l__ord_question_counter_int}.~#1} \par\vspace{\l__ord_after_question_text_dim} \int_zero:N \l__ord_option_counter_int \seq_clear:N \l__ord_options_seq \seq_clear:N \l__ord_original_order_seq \bool_set_false:N \l__ord_answer_pending_bool } % \end{macrocode} % \end{macro} % \begin{macro}{\OrderOption} % Defines an option for an ordering question. % \begin{macrocode} \NewDocumentCommand{\OrderOption}{ m } { \int_incr:N \l__ord_option_counter_int \seq_put_right:Nn \l__ord_options_seq {#1} \seq_put_right:Nn \l__ord_original_order_seq {#1} } % \end{macrocode} % \end{macro} % \begin{macro}{\OrderAnswer} % Adds an optional answer space after ordering options. % \begin{macrocode} \NewDocumentCommand{\OrderAnswer}{ O{1.5em} } { \bool_set_true:N \l__ord_answer_pending_bool \dim_set:Nn \l__ord_answer_width_dim {#1} } % \end{macrocode} % \end{macro} % \begin{macro}{\__ord_display_options} % Displays shuffled ordering options and builds the answer key. % \begin{macrocode} \cs_new_protected:Npn \__ord_display_options: { \int_compare:nNnT { \l__ord_option_counter_int } = { 0 } { \msg_warning:nn { ord } { no-options } \par \scan_stop: } \seq_shuffle:N \l__ord_options_seq \int_set:Nn \l_tmpa_int {\int_mod:nn {\l__ord_option_counter_int} {\l__ord_columns_int}} \int_compare:nNnT { \l_tmpa_int } > { 0 } { \int_set:Nn \l_tmpb_int { \l__ord_columns_int - \l_tmpa_int } \prg_replicate:nn { \l_tmpb_int } { \seq_put_right:Nn \l__ord_options_seq { \hspace{0pt} } } } \dim_set:Nn \l_tmpb_dim { \int_eval:n { \l__ord_columns_int - 1 } \l__ord_col_sep_dim } \dim_set:Nn \l_tmpa_dim { ( \linewidth - \l_tmpb_dim ) / \l__ord_columns_int } \dim_set:Nn \l__ord_text_width_dim { \dim_eval:n {\l_tmpa_dim - \l__ord_label_width_dim - \l__ord_label_sep_dim} } \dim_compare:nNnT { \l__ord_text_width_dim } < { 0pt } { \dim_set:Nn \l__ord_text_width_dim { 0pt } } \noindent \int_step_inline:nn { \seq_count:N \l__ord_options_seq } { \tl_set:Nx \l_tmpb_tl {\seq_item:Nn \l__ord_options_seq {##1}} \makebox[\l_tmpa_dim][l] { \makebox[\l__ord_label_width_dim][l] { \int_compare:nNnTF {##1} > {\l__ord_option_counter_int} { \hspace{0pt} } { \seq_item:Nn \g__exam_letters_seq {##1}) } }% \hspace{\l__ord_label_sep_dim}% \parbox[t]{\l__ord_text_width_dim} { \setlength{\baselineskip}{1.2\normalbaselineskip} \raggedright \l_tmpb_tl \par } } \int_compare:nNnF { \int_mod:nn {##1} { \l__ord_columns_int } } = { 0 } { \hspace{\l__ord_col_sep_dim} } \int_compare:nNnT { \int_mod:nn {##1} { \l__ord_columns_int } } = { 0 } { \par\prevdepth=\dp\strutbox% \vspace{\l__ord_between_option_lines_dim} \noindent } } \par \__ord_build_correct_order: \bool_if:NT \l__ord_answer_pending_bool { \__ord_print_answer: \bool_set_false:N \l__ord_answer_pending_bool } } % \end{macrocode} % \end{macro} % \begin{macro}{\__ord_build_correct_order} % Builds the correct order string for the answer key. % \begin{macrocode} \cs_new_protected:Npn \__ord_build_correct_order: { \tl_clear:N \l_tmpa_tl \int_step_inline:nn { \l__ord_option_counter_int } { \int_zero:N \l_tmpb_int \tl_set:Nx \l_tmpb_tl { \seq_item:Nn \l__ord_original_order_seq {##1} } \int_step_inline:nn { \l__ord_option_counter_int } { \tl_set:Nx \l_tmpc_tl { \seq_item:Nn \l__ord_options_seq {####1} } \tl_if_eq:NNT \l_tmpb_tl \l_tmpc_tl { \int_set:Nn \l_tmpb_int {####1} } } \tl_put_right:Nx \l_tmpa_tl {\seq_item:Nn \g__exam_letters_seq {\int_use:N \l_tmpb_int}} \int_compare:nNnF {##1} = { \l__ord_option_counter_int } { \tl_put_right:Nn \l_tmpa_tl { ~,~ } } } \tl_put_right:Nx \l__ord_answer_tl { \exp_not:N \makebox[4em][l] { (\PrintNumber{\l__ord_question_counter_int})~ $\Rightarrow$~ \l_tmpa_tl }% \par \noindent } } % \end{macrocode} % \end{macro} % \begin{macro}{\__ord_print_answer} % Prints the answer space for ordering questions. % \begin{macrocode} \cs_new_protected:Npn \__ord_print_answer: { \par \noindent Order:\quad \int_step_inline:nn { \l__ord_option_counter_int } { \underline{\hspace{\l__ord_answer_width_dim}}\, \int_compare:nNnT {##1} < {\l__ord_option_counter_int} { ,\ } } \par\vspace{0.3\baselineskip} } % \end{macrocode} % \end{macro} % \begin{environment}{Matching} % Creates two-column matching questions with shuffled right column. % \begin{macrocode} \seq_new:N \l__match_left_seq \seq_new:N \l__match_right_seq \seq_new:N \l__match_index_seq \int_new:N \l__match_count_int \tl_new:N \l__match_answer_tl \dim_new:N \l__match_label_width_dim \dim_new:N \l__match_label_sep_dim \dim_new:N \l__match_col_sep_dim \dim_new:N \l__match_left_text_width_dim \dim_new:N \l__match_right_text_width_dim \dim_new:N \l__match_left_width_dim \dim_new:N \l__match_right_width_dim \dim_new:N \l__match_before_first_dim \dim_new:N \l__match_between_pairs_dim \dim_set:Nn \l__match_label_width_dim { 1.5em } \dim_set:Nn \l__match_label_sep_dim { 0.5em } \dim_set:Nn \l__match_col_sep_dim { 2em } \dim_set:Nn \l__match_before_first_dim { 0.3em } \dim_set:Nn \l__match_between_pairs_dim { 0.7em } \NewDocumentEnvironment{Matching}{ O{0.5} } { \seq_clear:N \l__match_left_seq \seq_clear:N \l__match_right_seq \seq_clear:N \l__match_index_seq \tl_clear:N \l__match_answer_tl \dim_set:Nn \l__match_left_width_dim {#1\linewidth-\l__match_label_width_dim-\l__match_label_sep_dim} \dim_set:Nn \l__match_right_width_dim {\linewidth - \l__match_left_width_dim - \l__match_col_sep_dim} \dim_set:Nn \l__match_left_text_width_dim { \l__match_left_width_dim - \l__match_label_width_dim - \l__match_label_sep_dim } \dim_set:Nn \l__match_right_text_width_dim { \l__match_right_width_dim - \l__match_label_width_dim - \l__match_label_sep_dim } } { \int_compare:nNnT { \seq_count:N \l__match_left_seq } = { 0 } { \msg_error:nn { matching } { empty-pair } } \int_compare:nNnF { \seq_count:N \l__match_left_seq } = { \seq_count:N \l__match_right_seq } { \msg_warning:nnx { matching } { odd-number } { \int_use:N \seq_count:N \l__match_left_seq } { \int_use:N \seq_count:N \l__match_right_seq } } \int_set:Nn \l__match_count_int { \seq_count:N \l__match_right_seq } \int_step_inline:nn { \l__match_count_int } { \seq_put_right:Nn \l__match_index_seq {##1} } \seq_shuffle:N \l__match_index_seq \par\vspace{\l__match_before_first_dim} \noindent \begin{minipage}[t]{\l__match_left_width_dim} \raggedright \int_step_inline:nn { \l__match_count_int } { \makebox[\l__match_label_width_dim][r] { \PrintNumber{##1}) }% \hspace{\l__match_label_sep_dim}% \parbox[t]{\l__match_left_text_width_dim} { \setlength{\baselineskip}{1.2\normalbaselineskip} \raggedright \seq_item:Nn \l__match_left_seq {##1} \par \vspace{0.1em} } \par\prevdepth=\dp\strutbox% \vspace{\l__match_between_pairs_dim} } \end{minipage} \hspace{\l__match_col_sep_dim} \begin{minipage}[t]{\l__match_right_width_dim} \raggedright \int_step_inline:nn { \l__match_count_int } { \makebox[\l__match_label_width_dim][r] { \seq_item:Nn \g__exam_letters_seq {##1}) }% \hspace{\l__match_label_sep_dim}% \parbox[t]{\l__match_right_text_width_dim} { \setlength{\baselineskip}{1.2\normalbaselineskip} \raggedright \seq_item:Nn \l__match_right_seq { \seq_item:Nn \l__match_index_seq {##1} } \par \vspace{0.1em} } \par\prevdepth=\dp\strutbox% \vspace{\l__match_between_pairs_dim} } \end{minipage} \par \tl_clear:N \l__match_answer_tl \int_step_inline:nn { \l__match_count_int } { \int_zero:N \l_tmpa_int \int_step_inline:nn { \l__match_count_int } { \int_compare:nNnT { \seq_item:Nn \l__match_index_seq {####1} } = { ##1 } { \int_set:Nn \l_tmpa_int {####1} } } \tl_put_right:Nx \l__match_answer_tl { \exp_not:N \makebox[5.25em][l] { (\PrintNumber{##1})~ $\Rightarrow$~ (\seq_item:Nn \g__exam_letters_seq { \int_use:N \l_tmpa_int }) }% \qquad } } \tl_gset_eq:NN \g__question_answer_tl \l__match_answer_tl } % \end{macrocode} % \end{environment} % \begin{macro}{\MatchPair} % Defines a matching pair. % \begin{macrocode} \NewDocumentCommand{\MatchPair}{mm} { \seq_put_right:Nn \l__match_left_seq {#1} \seq_put_right:Nn \l__match_right_seq {#2} } % \end{macrocode} % \end{macro} % \begin{environment}{Essay} % Creates essay questions with ruled or blank lines. % \begin{macrocode} \int_new:N \l__essay_question_counter_int \tl_new:N \l__essay_answer_tl \bool_new:N \l__essay_lines_bool \dim_const:Nn \l__essay_number_width_dim { 5.3mm } \dim_new:N \l__essay_line_skip_dim \dim_set:Nn \l__essay_line_skip_dim { 0.4\baselineskip } \dim_new:N \l__essay_before_first_question_dim \dim_new:N \l__essay_between_questions_dim \dim_new:N \l__essay_after_question_dim \dim_set:Nn \l__essay_before_first_question_dim { 0.2em } \dim_set:Nn \l__essay_between_questions_dim { 0.2\baselineskip } \dim_set:Nn \l__essay_after_question_dim { 0.65\baselineskip } \NewDocumentEnvironment{Essay}{ O{true} } { \int_zero:N \l__essay_question_counter_int \tl_clear:N \l__essay_answer_tl \str_if_eq:nnTF {#1} {true} { \bool_set_true:N \l__essay_lines_bool } { \bool_set_false:N \l__essay_lines_bool } } { \tl_gset_eq:NN \g__question_answer_tl \l__essay_answer_tl } % \end{macrocode} % \end{environment} % \begin{macro}{\EssayQuestion} % Defines an essay question (no limit on number of lines). % \begin{macrocode} \NewDocumentCommand{\EssayQuestion}{ O{4} m m } { \int_incr:N \l__essay_question_counter_int \int_set:Nn \l_tmpa_int {#1} \int_compare:nNnTF { \l__essay_question_counter_int } = { 1 } { \par\vspace{\l__essay_before_first_question_dim} } { \par\vspace{\l__essay_between_questions_dim} } \par\noindent \makebox[5.0mm][r]{\PrintNumber{\l__essay_question_counter_int}.}% \hspace{0.7em}% \parbox[t]{\dim_eval:n{\linewidth-8.0mm}} { \setlength{\baselineskip}{1.2\normalbaselineskip} #2 \par } \par\prevdepth=\dp\strutbox% \vspace{\l__essay_after_question_dim} \int_step_inline:nn {#1} { \noindent \hspace*{6.0mm}% \rule{\dim_eval:n{\linewidth-6.0mm}} { \bool_if:NTF \l__essay_lines_bool {0.4pt} {0pt} } \par\vspace{\l__essay_line_skip_dim} } \tl_put_right:Nx \l__essay_answer_tl { \exp_not:N (\PrintNumber{\l__essay_question_counter_int})~ $\Rightarrow$~ #3 \par } } % \end{macrocode} % \end{macro} % \begin{environment}{ShortAnswer} % Creates short answer questions (0, 1, or 2 lines). % \begin{macrocode} \int_new:N \l__short_question_counter_int \tl_new:N \l__short_answer_tl \bool_new:N \l__short_lines_bool \dim_const:Nn \l__short_number_width_dim { 5.3mm } \dim_new:N \l__short_line_height_dim \dim_set:Nn \l__short_line_height_dim { 0.4\baselineskip } \dim_new:N \l__short_before_first_question_dim \dim_new:N \l__short_between_questions_dim \dim_new:N \l__short_after_question_dim \dim_set:Nn \l__short_before_first_question_dim { 0.2em } \dim_set:Nn \l__short_between_questions_dim { 0.2\baselineskip } \dim_set:Nn \l__short_after_question_dim { 0.65\baselineskip } \NewDocumentEnvironment{ShortAnswer}{ O{true} } { \int_zero:N \l__short_question_counter_int \tl_clear:N \l__short_answer_tl \str_if_eq:nnTF {#1} {true} { \bool_set_true:N \l__short_lines_bool } { \bool_set_false:N \l__short_lines_bool } } { \tl_gset_eq:NN \g__question_answer_tl \l__short_answer_tl } % \end{macrocode} % \end{environment} % \begin{macro}{\ShortQuestion} % Defines a short answer question (0, 1, or 2 lines, capped at 2 without warning). % \begin{macrocode} \NewDocumentCommand{\ShortQuestion}{ O{1} m m } { \int_incr:N \l__short_question_counter_int \int_set:Nn \l_tmpa_int {#1} \int_compare:nNnT {#1} > { 2 } { \int_set:Nn \l_tmpa_int { 2 } } \int_compare:nNnTF { \l__short_question_counter_int } = { 1 } { \par\vspace{\l__short_before_first_question_dim} } { \par\vspace{\l__short_between_questions_dim} } \par\noindent \makebox[5.0mm][r]{\PrintNumber{\l__short_question_counter_int}.}% \hspace{0.7em}% \parbox[t]{\dim_eval:n{\linewidth-8.0mm}} { \setlength{\baselineskip}{1.2\normalbaselineskip} #2 \int_compare:nNnT {#1} = { 0 } { \quad \underline{\hspace{6em}} } } \par\prevdepth=\dp\strutbox% \vspace{\l__short_after_question_dim} \int_compare:nNnT {#1} > { 0 } { \int_step_inline:nn { \l_tmpa_int } { \par \noindent \hspace*{6.0mm}% \rule{\dim_eval:n{\linewidth-6.0mm}} { \bool_if:NTF \l__short_lines_bool {0.4pt} {0pt} } \par\vspace{\l__short_line_height_dim} } } \par \tl_put_right:Nx \l__short_answer_tl { \exp_not:N (\PrintNumber{\l__short_question_counter_int})~ $\Rightarrow$~ #3 \par } } % \end{macrocode} % \end{macro} % \begin{environment}{ReadingPassage} % Creates a boxed environment for reading passages. % \begin{macrocode} \NewDocumentEnvironment{ReadingPassage}{ O{} m } { \par \begin{tcolorbox}[ enhanced, breakable, colback=white, colframe=black, arc=0pt, outer~arc=0pt, boxrule=1pt, top=10pt, bottom=10pt, left=10pt, right=10pt, parbox=true, fontupper=\linespread{1.4}\selectfont, coltitle=black, fonttitle=\bfseries, title={\textbf{\tl_if_empty:nTF {#2} {Reading Passage} {#2}}}, #1, attach~boxed~title~to~top~center={ yshift=-3mm, yshifttext=-1mm }, boxed~title~style={ colback=white, colframe=white, left=5pt, right=5pt } ] } { \end{tcolorbox} \par\smallskip } % \end{macrocode} % \end{environment} % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % \iffalse % % \fi % \Finale