1

Good day,

I'm making a customized grading table for the exam class. In particular, I want to delete the first column and append a new one to the end. It seemed that creating a new table altogether would be the way to go.

After searching stackexchange I have found this question, which modifies \part environment and writes every question part and its amount of points to an auxiliary file from which they are placed into a table. I was able to change it to my liking, except for the way scores are displayed. Proposed solution uses question parts by default, while I would like to see only the totals for every question. Hence the question about counting totals for every \question.

My current code (mostly a hackjob of what @Andrew proposed) is as follows:

% redefine \question command to be \myquest
\appto\questions{\let\examquestion\question\let\question\myquestion}
% redefine \part command to be \mypart
\appto\parts{\let\exampart\part\let\part\mypart}

\makeatletter
\ExplSyntaxOn

% this will become a sequence of the part numbers and scores
% like: 1a,10,1b,8,1c,9,2a,6,2b,8,3,12,4,14, ...
\clist_new:N \g_grades_clist
\clist_new:N \g_grades_aux_clist

\int_new:N \g_questions_row_int
\int_new:N \g_scores_row_int
\int_new:N \g_spaces_row_int

\int_new:N \g_grade_total_int
\int_new:N \g_number_of_scores_int
\int_new:N \g_total_questions

% add a question/part number and score to \g_grades_clist
\cs_new:Nn \__add_to_grades_list:nn {
  \clist_gput_right:Nx \g_grades_clist { #1 }
  \clist_gput_right:Nx \g_grades_clist { #2 }
}

\NewDocumentCommand\myquestion{o}{
  \IfNoValueTF{#1}{\examquestion}{
    % don't do anything special inside solutions
    \if@insolution\examquestion[#1]
    \else\examquestion[#1]
      % store both the part number and score in \g_grades_clist
      \__add_to_grades_list:nn { Auf.~\arabic{question} } { #1 }
    \fi
  }
}

\NewDocumentCommand\mypart{o}{
  \IfNoValueTF{#1}{\exampart}{
    % don't do anything special inside solutions
    \if@insolution\exampnrt[#1]
    \else\exampart[#1]
      % store both the part number and score in \g_grades_clist
      \__add_to_grades_list:nn { Auf.~\arabic{question}\alph{partno} } { #1 }
    \fi
  }
}

\AtEndDocument{
  \iow_now:cx { @auxout } {
    \token_to_str:N \SetGradeList { \g_grades_clist  } ^^J
  }
}
% set grade list from the aux file
\NewDocumentCommand\SetGradeList{m}{\clist_gset:Nn \g_grades_aux_clist {#1}}
% Draw quesions
\cs_new:Nn \__add_questions_to_grade_table: {
    \int_gincr:N \g_questions_row_int
       \clist_item:Nn \g_grades_aux_clist {2*\g_questions_row_int-1} \int_compare:nT {\g_questions_row_int < (\g_number_of_scores_int)} { & \__add_questions_to_grade_table: }
}
% Draw scores
\cs_new:Nn \__add_scores_to_grade_table: {
     \int_gincr:N \g_scores_row_int
       \clist_item:Nn \g_grades_aux_clist {2*\g_scores_row_int} \int_compare:nT {\g_scores_row_int < \g_number_of_scores_int} { & \__add_scores_to_grade_table: }
}
% Draw empty spaces
\cs_new:Nn \__add_spaces_to_grade_table: {
     \int_gincr:N \g_spaces_row_int
         \int_compare:nT {\g_spaces_row_int < \g_number_of_scores_int} { & \__add_spaces_to_grade_table: }
}

\NewDocumentCommand\PrintGradeTable{}{% the new grade table
  \int_set:Nn \g_number_of_scores_int {(\clist_count:N \g_grades_aux_clist)/2}
  \int_gzero:N \g_questions_row_int % a counter to step through the rows
  \int_gzero:N \g_scores_row_int % a counter to step through the rows
  \int_gzero:N \g_spaces_row_int % a counter to step through the rows
  % create the grade table
  \renewcommand{\arraystretch}{2}
    \begin{tabular}{|c|*{\int_eval:n {(\clist_count:N \g_grades_aux_clist)/2-1}}{c|}c}
        \hline
        \int_compare:nT {\g_number_of_scores_int>0} { \__add_questions_to_grade_table: } & \multicolumn{1}{l|}{\hphantom{A}~\large\textbf{Note}~\hphantom{A}} \\
        \hline
        \int_compare:nT {\g_number_of_scores_int>0} { \__add_scores_to_grade_table: } & \\
        \hline
        \int_compare:nT {\g_number_of_scores_int>0} { \__add_spaces_to_grade_table: } & \multicolumn{1}{l|}{} \\
        \hline
    \end{tabular}
}
\ExplSyntaxOff

Here is a visual representation of what the code produces: Current grading table

Every exercise in the exam is of the following format:

\question
\begin{parts}
    \part
\end{parts}

So every question always has parts.

What would be the easiest way to do sum up the totals for the parts?

1

1 Answer 1

1

I ended up modifying the built-in table function instead. If anyone needs to do the same, I introduced a shorter version of the emptycols iterator that creates one cell less and chaged all the loops to have ampersand after the main part, so instead of leaving an empty cell before them, they leave one after. That way it's not the first column that has all the names or is empty, but the last one.

All the changed code is as follows:

\def\do@lines@h{%
  % Called only by \@multirowtable.
  % It's either bonus or regular, but not combined:
  \addtocounter{current@row}{1}% Set to the number of the current row
  \setcounter{cols@done}{0}%
  \do@pq@indexloop@h
  % When we finish \do@pq@indexloop@h, either we've finished a
  % complete row of page numbers (or questions), or we've done all
  % the page numbers (or questions) through \last@pq@index, or both:
  \ifnum \value{cols@done} < \value{num@cols}\relax
    % We've inserted all the page or question numbers, and there's
    % room remaining on the current line for \@htword (or \@bhtword):
    \ifnum \value{current@row} = \value{num@rows}\relax
      % This is the last row; put in the total:
      \do@note
    \else
      % This isn't the last row.  We insert (\value{num@cols} -
      % \value{cols@done}) ampersands.
      \setcounter{@iterator}{\value{num@cols}}%
      \addtocounter{@iterator}{-\value{cols@done}}%
      \do@emptycols@h
    \fi
  \fi
  \\
  \hline
  % Point values go here!
  \setcounter{cols@done}{0}%
  \if@bonus
    \do@bptloop@h
  \else
    \do@ptloop@h
  \fi
  % When we finish \do@ptloop@h or \do@bptloop@h, either
  % we've finished a complete row of point values, or we've done all
  % the question (or page) numbers through \last@pq@index, or both:
  \ifnum \value{cols@done} < \value{num@cols}\relax
    % We've inserted all the point values, and there's room
    % remaining on the current line for Total Points:
    \ifnum \value{current@row} = \value{num@rows}\relax
      % This is the last row; put in the total:
      \if@bonus
        \do@totalbpts@h
      \else
        \do@totalpts@h
      \fi

    \else
      % This isn't the last row.  We insert (\value{num@cols} -
      % \value{cols@done}) ampersands.
      \setcounter{@iterator}{\value{num@cols}}%
      \addtocounter{@iterator}{-\value{cols@done}}%
      \do@emptycols@h
    \fi
  \fi
  % We hold off on putting in the "\\ \hline" because we may want to
  % immediately follow it with either an "\end{tabular}" or another
  % "\hline".
  % Scores?
  \if@scores
    \\
    \hline
    \if@bonus
      \hidden@ampersand
    \else
      \hidden@ampersand
    \fi
    \setcounter{cols@done}{0}%
    \do@sloop@h
  \fi
  \ifnum \value{current@row} = \value{num@rows}\relax
    % This is the last line!  End the tabular:
    \\
    \hline
    \end{tabular}%
  \else
    % Don't end the tabular:
    \\
    \hline\hline
  \fi
  % Check if we should repeat:
  \ifnum \value{current@row} < \value{num@rows}\relax
    \let\nextdo@lines@h=\do@lines@h
  \else
    \let\nextdo@lines@h=\relax
  \fi
  \nextdo@lines@h
}% do@lines@h

\def\do@pq@indexloop@h{%
  % Called by both \do@lines@h and \do@comblines@h.
  % We insert at most one row of pq@index:
  \increment@index{pq@index}%
  \ifnum \value{pq@index} > \last@pq@index\relax
    % Do nothing!
  \else
    Aufg. \refto@index{pq@index}%
    \hidden@ampersand
    \addtocounter{cols@done}{1}%
  \fi
  \ifnum \value{pq@index} < \last@pq@index\relax
    \ifnum \value{cols@done} < \value{num@cols}\relax
      \let\nextdo@pq@indexloop@h=\do@pq@indexloop@h
    \else
      \let\nextdo@pq@indexloop@h=\relax
    \fi
  \else
    \let\nextdo@pq@indexloop@h=\relax
  \fi
  \nextdo@pq@indexloop@h
}% do@pq@indexloop@h

\def\do@ptloop@h{%
  % Called by both \do@lines@h and \do@comblines@h.
  % We insert at most one row of non-bonus point values:
  \increment@index{pq@index@pts}%
  \ifnum \value{pq@index@pts} > \last@pq@index\relax
    % Do nothing!
  \else
    \addtocounter{cols@done}{1}%
    \pointsof@index{pq@index@pts}%
    \hidden@ampersand
    \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index@pts}}%
  \fi
  \ifnum \value{pq@index@pts} < \last@pq@index\relax
    \ifnum \value{cols@done} < \value{num@cols}\relax
      \let\nextdo@ptloop@h=\do@ptloop@h
    \else
      \let\nextdo@ptloop@h=\relax
    \fi
  \else
    \let\nextdo@ptloop@h=\relax
  \fi
  \nextdo@ptloop@h
}% do@ptloop@h

\def\do@note{%
  % Called by both \do@lines@h and \do@comblines@h.
  % We insert (\value{num@cols} - \value{cols@done}) ampersands,
  % and then either \@htword or \@bhtword or \@chtword:
  \setcounter{@iterator}{\value{num@cols}}%
  \addtocounter{@iterator}{-\value{cols@done}}%
  \do@shortemptycols@h
  \if@combined
      Gesamt \hidden@ampersand \textbf{Note}
  \else
    \if@bonus
      Gesamt \hidden@ampersand \textbf{Note}
    \else
      Gesamt \hidden@ampersand \textbf{Note}
    \fi
  \fi
}% do@note

\def\do@totalpts@h{%
  % Called by both \do@lines@h and \do@comblines@h.
  % We insert (\value{num@cols} - \value{cols@done}) ampersands
  % and then the total points:
  \setcounter{@iterator}{\value{num@cols}}%
  \addtocounter{@iterator}{-\value{cols@done}}%
  \do@shortemptycols@h
  \prt@tablepoints
}% do@totalpts@h

\def\do@shortemptycols@h{%
  % Called by \do@lines@h, \do@comblines@h, \do@note,
  % \do@totalpts@h, and \do@totalbpts@h.
  % We insert \value{@iterator} ampersands:
  \ifnum \value{@iterator} > 1\relax
    \hidden@ampersand
    \addtocounter{@iterator}{-1}%
    \let\nextdo@emptycols@h=\do@emptycols@h
  \else
    \let\nextdo@emptycols@h=\relax
  \fi
  \nextdo@emptycols@h
}% do@emptycols@h

Producing the following result: enter image description here

All the text parts are hard-coded, since there is no need for variation in my particular case, but could easily be replaced by variables.

1
  • Can you provide the full MWE for your problem please?
    – Alan Jones
    Apr 17, 2022 at 2:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .