% !TEX encoding = UTF-8 Unicode % %% exercisepoints.sty %% A LaTeX package to count exercises and points. %% %% Copyright (c) 2017-2019 Henning Kerstan. % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Henning Kerstan. % % This work consists of the files `exercisepoints.sty' and `exercisepoints.tex'. % % package identification \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{exercisepoints}[% 2019/01/03 v1.2.3 % count exercises and points% ] % switches for custom exercise layout \newif\if@exercisepoints@usecustomlayout% \newif\if@exercisepoints@exercise@layoutdefined% \newif\if@exercisepoints@subexercise@layoutdefined% \DeclareOption{customlayout}{% \@exercisepoints@usecustomlayouttrue% } % this package does not have any other options \DeclareOption*{ \PackageWarning{exercisepoints}{Unknown option '\CurrentOption'} } \ProcessOptions\relax% % avoid nesting (i.e. putting exercises in exercises) \newif\if@exercisepoints@inexercise% \global\@exercisepoints@inexercisefalse% \newif\if@exercisepoints@insubexercise% \global\@exercisepoints@insubexercisefalse% % counters to store number of exercises \newcounter{exercisepoints@exercisecount} \newcounter{exercisepoints@subexercisecount}[exercisepoints@exercisecount] % lengths to store points \newlength{\exercisepoints@currentexercisepoints} \newlength{\exercisepoints@currentsubexercisepoints} \newlength{\exercisepoints@totalpoints} \newlength{\exercisepoints@bonuspoints} % macros to get total points and total number of exercises (whole document) \providecommand{\totalpoints}{0} \providecommand{\numberofexercises}{0} % macros to get info about current exercise(-part) % (to be used in AtBeginExercise or AtEndExercise hooks) \providecommand{\currentexercisetitle}{} \providecommand{\currentsubexercisetitle}{} \providecommand{\currentexercisepoints}{% \if@exercisepoints@inexercise\else% \PackageError{exercisepoints}{'\string\currentexercisepoints' can only be used in exercise or subexercise environment}% \fi% % \ifcsname exercisepoints@points@\currentexercisenumber\endcsname% \@nameuse{exercisepoints@points@\currentexercisenumber}% \else% \textbf{??}% TODO:issue package warning in such a way that it can be used also in section commands \fi% } \providecommand{\currentsubexercisepoints}{% \if@exercisepoints@insubexercise\else% \PackageError{exercisepoints}{'\string\currentsubexercisepoints' can only be used in subexercise environment}% \fi% % \ifcsname exercisepoints@points@\currentexercisenumber.\currentsubexercisenumber\endcsname% \@nameuse{exercisepoints@points@\currentexercisenumber.\currentsubexercisenumber}% \else% \textbf{??}% TODO:issue package warning in such a way that it can be used also in section commands \fi% } \providecommand{\currentexercisenumber}{% \theexercisepoints@exercisecount% } \providecommand{\currentsubexercisenumber}{% \theexercisepoints@subexercisecount% } % hooks to modify the exercise typesetting \providecommand{\AtBeginExercise}[1]{ \renewcommand{\exercisepoints@begin}{#1}% \@exercisepoints@exercise@layoutdefinedtrue% } \providecommand{\AtEndExercise}[1]{ \renewcommand{\exercisepoints@end}{#1} } % the same for subexercises \providecommand{\AtBeginSubexercise}[1]{ \renewcommand{\exercisepoints@sub@begin}{#1} \@exercisepoints@subexercise@layoutdefinedtrue% } \providecommand{\AtEndSubexercise}[1]{ \renewcommand{\exercisepoints@sub@end}{#1} } % storage for the hooks \newcommand{\exercisepoints@begin}{} \newcommand{\exercisepoints@end}{} \newcommand{\exercisepoints@sub@begin}{} \newcommand{\exercisepoints@sub@end}{} % a very simple default exercise style \if@exercisepoints@usecustomlayout\else% \RequirePackage{ifthen}% \AtBeginExercise{% ~\smallskip\\\sffamily% \ifthenelse{\equal{\currentexercisetitle}{}}% {\textbf{Exercise~\currentexercisenumber}} % empty title {% \textbf{Exercise~\currentexercisenumber:} % \currentexercisetitle% }% non-empty title \,~\hfill\textbf{(\currentexercisepoints~Points)}% \smallskip\\\noindent\normalfont% } \AtEndExercise{~\smallskip\\} % \AtBeginSubexercise{% ~\smallskip\\\sffamily% \ifthenelse{\equal{\currentsubexercisetitle}{}}% {\emph{Exercise~\currentexercisenumber.\currentsubexercisenumber}} % empty title {% \emph{Exercise~\currentexercisenumber.\currentsubexercisenumber:} % \emph{\currentsubexercisetitle}% }% non-empty title \,~\hfill\emph{(\currentsubexercisepoints~Points)}% \smallskip\\\noindent\normalfont% } \AtEndSubexercise{~\\} \fi % points commands sets points (additive within an exercise environment) \newcommand{\points}[1]{% \if@exercisepoints@inexercise% \addtolength{\exercisepoints@currentexercisepoints}{#1 pt}% \global\exercisepoints@currentexercisepoints=\exercisepoints@currentexercisepoints% \addtolength{\exercisepoints@totalpoints}{#1 pt}% \global\exercisepoints@totalpoints=\exercisepoints@totalpoints% \if@exercisepoints@insubexercise% \addtolength{\exercisepoints@currentsubexercisepoints}{#1 pt}% \global\exercisepoints@currentsubexercisepoints=\exercisepoints@currentsubexercisepoints% \fi% \else% \PackageError{exercisepoints}{\string\points{...} can only be used within exercise or subexercise environment.}% \fi% } % itempoints units \newcommand{\exercisepoints@itempointsunit@singular}{} \newcommand{\exercisepoints@itempointsunit@plural}{} \newcommand{\setitempointsunit}[2]{% singular, plural \renewcommand{\exercisepoints@itempointsunit@singular}{#1}% \renewcommand{\exercisepoints@itempointsunit@plural}{#2}% } % itempoints calls points and displays points flush right for use in % enumerate environments \RequirePackage{ifthen} \newcommand{\itempoints}[1]{% \points{#1}% % check if exactly 1 points \ifthenelse{\equal{#1}{1}}{% not robust, so issuing 1.0 will not result in correct (singular) form! \ifthenelse{\equal{\exercisepoints@itempointsunit@singular}{}}{% \,~\hfill(#1)% }{% \,~\hfill(#1~\exercisepoints@itempointsunit@singular)% }% }{% \ifthenelse{\equal{\exercisepoints@itempointsunit@plural}{}}{% \,~\hfill(#1)% }{% \,~\hfill(#1~\exercisepoints@itempointsunit@plural)% }% }% } % getpoints retrieves points for a specific exercise number (starting at 0) \newcommand{\getpoints}[1]{% \ifthenelse{#1 < \numberofexercises}% {\exercisepoints@readfromaux{points@#1}}% {\textbf{??}}% } % aux storage function (key-value store using #1 as key and #2 as value) \newcommand{\exercisepoints@storetoaux}[2]{% \immediate\write\@auxout{% \string\global\string\long\string\@namedef{exercisepoints@#1}{#2}% }% } % aux retrieval \newcommand{\exercisepoints@readfromaux}[1]{% \ifcsname exercisepoints@#1\endcsname% \@nameuse{exercisepoints@#1}% \else% \textbf{??}% \PackageWarning{exercisepoints}{% Key 'exercisepoints@#1' not found in aux file. Maybe you need to recompile?% }% \fi% } % exercise environment; optional parameter is title of the respective exercise \newenvironment{exercise}[1][]{% \if@exercisepoints@inexercise% \PackageError{exercisepoints}{You cannot nest exercise environments}% \fi % \if@exercisepoints@exercise@layoutdefined\else% \PackageError{exercisepoints}{Option `customlayout' requires you to define an exercise layout using at least `\string\AtBeginExercise{...}'} \fi % \global\@exercisepoints@inexercisetrue% \setlength{\exercisepoints@currentexercisepoints}{0pt}% \global\exercisepoints@currentexercisepoints=\exercisepoints@currentexercisepoints% \renewcommand{\currentexercisetitle}{#1}% \exercisepoints@begin% }{% \exercisepoints@end% \exercisepoints@storetoaux{points@\theexercisepoints@exercisecount}{\strip@pt\exercisepoints@currentexercisepoints}% \stepcounter{exercisepoints@exercisecount}% \global\@exercisepoints@inexercisefalse% } % exercise environment; optional parameter is title of the respective exercise \newenvironment{subexercise}[1][]{% \if@exercisepoints@insubexercise% \PackageError{exercisepoints}{You cannot nest subexercise environments}% \fi% % \if@exercisepoints@subexercise@layoutdefined\else% \PackageError{exercisepoints}{Option `customlayout' requires you to define a subexercise layout using at least `\string\AtBeginSubexercise{...}'} \fi% \global\@exercisepoints@insubexercisetrue% \setlength{\exercisepoints@currentsubexercisepoints}{0pt}% \global\exercisepoints@currentsubexercisepoints=\exercisepoints@currentsubexercisepoints% \renewcommand{\currentsubexercisetitle}{#1}% \exercisepoints@sub@begin% }{% \exercisepoints@sub@end% \exercisepoints@storetoaux{points@\theexercisepoints@exercisecount.\theexercisepoints@subexercisecount}{\strip@pt\exercisepoints@currentsubexercisepoints}% \stepcounter{exercisepoints@subexercisecount}% \global\@exercisepoints@insubexercisefalse% } \newcommand{\bonuspoints}[1]{% \setlength{\exercisepoints@bonuspoints}{#1 pt}% \global\exercisepoints@bonuspoints=\exercisepoints@bonuspoints% } \newcommand{\getbonuspoints}{% \exercisepoints@readfromaux{points@bonus}% } \newcommand{\totalpointswithbonus}{% \readfromaux{totalpointswithbonus}% } % read values from aux file at begin \AtBeginDocument{ \setlength{\exercisepoints@totalpoints}{0pt}% reset total points length % % set numberofexercises to 0 if not found in aux \ifcsname exercisepoints@numberofexercises\endcsname% \renewcommand{\numberofexercises}{% \exercisepoints@readfromaux{numberofexercises}% }% \fi% % \renewcommand{\totalpoints}{\exercisepoints@readfromaux{points@total}}% \renewcommand{\totalpointswithbonus}{\exercisepoints@readfromaux{points@totalwithbonus}}% } % store values in aux file at end \AtEndDocument{ \exercisepoints@storetoaux{numberofexercises}{\theexercisepoints@exercisecount}% \exercisepoints@storetoaux{points@total}{\strip@pt\exercisepoints@totalpoints}% \exercisepoints@storetoaux{points@bonus}{\strip@pt\exercisepoints@bonuspoints}% \newlength{\exercisepoints@totalpointswithbonus}% \setlength{\exercisepoints@totalpointswithbonus}{\exercisepoints@totalpoints}% \addtolength{\exercisepoints@totalpointswithbonus}{\exercisepoints@bonuspoints}% \exercisepoints@storetoaux{points@totalwithbonus}{\strip@pt\exercisepoints@totalpointswithbonus}% }