我们有一个用于考试的合作设计模板。缺点是,我们必须手动计算每个任务的分数。我的想法是使用计数器自动计算。
我正在寻找:
\task{Java}
Hello World \points{2}
for-each \points{1}
\task{C++}
Bla bla \points{2}
Blub blub \points{4}
\task{Latex}
Foo foo \points{2}
bar bar \points{2}
我想要一个编译后如下所示的文档:
Java(3 分)
你好,世界(2 分)
for-each(1 分)
C++(6 分)
啦啦啦(2 分)
Blub blub (4 分)
乳胶(4 分)
Foo foo(2 分)
酒吧 酒吧 (2 分)
我的想法是在 -command 中创建一个计数器,并在 -command 中将\task
其与 -command 一起使用。实际上,我没能动态更改每个计数器的名称。\addtocounter
\points
这里是从我们的模板中提取的 MWE,我们在 `\task`` 命令中手动计算点数:
\documentclass[12pt,oneside,a4paper,final]{scrartcl}
\newcounter{task}
\setcounter{task}{0}
\newcommand{\points}[1]{
(#1~Points)
}
\newcommand{\task}[2]{
\refstepcounter{task}
\begin{flushleft}
{\LARGE\bf Task \arabic{task}}
\end{flushleft}
{\Large \textbf{#1}}
\leavevmode\hfill ({#2}~Points)\\
}
\begin{document}
\task{Java}{3}
Hello World \points{2}
for-each \points{1}
\task{C++}{5}
Bla bla \points{2}
Blub blub \points{4}
\task{Latex}{4}
Foo foo \points{2}
bar bar \points{2}
\end{document}
从:https://github.com/boldt/tex.stackexchange.com-186897/blob/master/exam.tex
答案1
看起来用户 cslstr 和我有相同的想法 ;-) 我使用了我以前的问题中更改的命令将标签写入文件.aux
,然后使用 读取它\nameref*
。
然而,如果在环境内部,任务的结束就会容易得多。
\documentclass[12pt,oneside,a4paper,final]{scrartcl}
\usepackage{nameref}
\newcounter{task}
\setcounter{task}{0}
\newcounter{creditspertask}[task]
\setcounter{creditspertask}{0}%
\newcommand{\points}[1]{
(#1~Points)
\addtocounter{creditspertask}{#1}%
}
\makeatletter
\newcommand{\WriteCreditsToFile}[1]{%
\immediate\write\@auxout{%
\string\newlabel{credits::\number\value{task}}{{\thesection}{\thepage}{#1}{}}
}% End of writing to AUX file
}%
\makeatother
\AtEndDocument{% For the last one only
\WriteCreditsToFile{\number\value{creditspertask}}%
}%
%
\newcommand{\task}[1]{
\WriteCreditsToFile{\number\value{creditspertask}}
\refstepcounter{task}
\begin{flushleft}
{\LARGE\bfseries Task \arabic{task}}
\end{flushleft}
{\Large \textbf{#1}}
\leavevmode\hfill ({\nameref*{credits::\number\value{task}}}~Points)\\
}
\begin{document}
\task{Java}
Hello World \points{2}
for-each \points{1}
\task{C++}
Bla bla \points{2}
Blub blub \points{4}
\task{Latex}
Foo foo \points{2}
bar bar \points{2}
\end{document}
编辑更新版本,并附0.5
有积分,也是可能的和基本的\listofcredits
\documentclass[12pt,oneside,a4paper,final]{scrartcl}
\usepackage{nameref}
\usepackage{calculator}%
\usepackage{calc}%
\usepackage{totcount}%
\usepackage{forloop}
\newcounter{task}
\setcounter{task}{0}
\xdef\TotalCredits{0}%
\xdef\TaskCredits{0}%
\xdef\SubCredits{0}%
\newcommand{\points}[2]{
\item #1 (#2~Points)
\ADD{\TaskCredits}{#2}{\SubCredits}%
\xdef\TaskCredits{\SubCredits}%
}%
\makeatletter
\newcommand{\WriteCreditsToFile}[1]{%
\immediate\write\@auxout{%
\string\newlabel{credits::\number\value{task}}{{\thesection}{\thepage}{#1}{}}
}% End of writing to AUX file
}%
\makeatother
%
\makeatletter
\AtEndDocument{%
\immediate\write\@auxout{%
\string\newlabel{totalcredits}{{\thesection}{\thepage}{\TotalCredits}{}}
}
}
\makeatother
\newenvironment{Task}[1]{%
\xdef\TaskCredits{0}%
\xdef\SubCredits{0}%
\xdef\CreditsSoFar{0}%
\refstepcounter{task}
\begin{flushleft}
{\LARGE\bfseries Task \arabic{task}}
\end{flushleft}
{\Large \textbf{#1}}
\leavevmode\hfill ({\nameref*{credits::\number\value{task}}}~Points)\\
\begin{itemize} % Just for 'better' typography
}{% Close it
\end{itemize}
\WriteCreditsToFile{\TaskCredits}%
% Count all credits for the summary%
\ADD{\TotalCredits}{\TaskCredits}{\CreditsSoFar}%
\xdef\TotalCredits{\CreditsSoFar}%
}%
\regtotcounter{task}%
\makeatletter%
\newcounter{loop@@counter}%
\newcounter{totaltask@@counter}%
\newcommand{\listofcredits}{%
\setcounter{totaltask@@counter}{\number\totvalue{task}+1}%
\begin{tabular}{lll}
Task number & Total credits & Achieved\tabularnewline
\hline
\forloop{loop@@counter}{1}{\number\value{loop@@counter} < \number\value{totaltask@@counter}}{%
Task \number\value{loop@@counter} & \nameref*{credits::\number\value{loop@@counter}} & \tabularnewline%
} %
& \tabularnewline
\hline
\multicolumn{1}{r}{Total:} & \nameref*{totalcredits} & \tabularnewline%
\end{tabular}
}%
\makeatother
\begin{document}
\listofcredits
\newpage
\begin{Task}{Java}
\points{Hello World}{2.5}
\points{for-each}{2}
\end{Task}%
\begin{Task}{C++}
\points{Bla bla}{2}
\points{blub blub}{4}
\end{Task}
\begin{Task}{Latex}
\points{Foo}{2}
\points{bar}{2}
\end{Task}
\begin{Task}{Fortran54} % ;-)
\points{Write a Fortran 54 code to \LaTeX ;-)}{100}
\points{Write a Babbage machine code to replace \LaTeX ;-)}{1000}
\end{Task}
\end{document}
编辑新版本
由于\nameref*{}
不可扩展,因此必须使用另一种方法进行总结等。新版本将每个任务的总积分写入外部文件,然后再次读取该文件以完成顶部位置和命令的总任务积分\listoftask
。
代码
- 如果所有任务都写入
\jobname.credits
文件则有效 如果有真实数字而不是学分的数学表达式,则有效
需要二运行
不适用于按部分任务编号
如果在某处添加了另一个任务,则会失败,因为
\jobname.credits
仅在第一次运行期间写入。在这种情况下,删除\jobname.aux
和\jobname.credits
,然后再次运行两次。
当然,我无法检查所有内容,输出格式等只是一个主张,我从 OP 答案中借用了代码,这是对我的第一个版本的直接反应,所以我认为这是可以的。
\documentclass[paper=a4,12pt]{scrbook}
\usepackage{calculator}
\usepackage{morewrites}
\usepackage{etoolbox}%
\usepackage{xcolor}%
\usepackage{calc}%
\usepackage{forloop}%
\usepackage{totcount}%
\usepackage{ifthen}%
\usepackage{tikz}%
\newwrite\CreditsFileHandle%
\newcounter{NumberOfLaTeXRuns}%
\newcommand{\WriteFileThreshold}{2}%
\newcommand{\CounterValue}[1]{%
\ifltxcounter{#1}{%
\number\value{#1}}{%
#1}%
}%
\xdef\tempsum{0}%
\xdef\othersum{0}%
\newcommand{\sumup}[1]{%
\ADD{\tempsum}{#1}{\othersum}%
\xdef\tempsum{\othersum}%
}%
\makeatletter
\newcommand{\WriteToFile}[2][\CreditsFileHandle]{%
\immediate\write#1{%
#2%
}%
}%
\newcommand{\CloseForReading}[1][\CreditsFileHandle]{%
\immediate\closein#1%
}%
\newcommand{\CloseForWriting}[1][\CreditsFileHandle]{%
\immediate\closeout#1%
}%
\newcommand{\OpenForReading}[2][\CreditsFileHandle]{%
\immediate\openin#1=#2%
}%
\newcommand{\OpenForWriting}[2][\CreditsFileHandle]{%
\immediate\openout#1=#2%
}%
\xdef\@@TotalCreditsValue{1}%
\listgadd{\CreditsSumList}{}%
\newcommand{\DisplayQuestionAndCredits}[2]{%
\item #1 (\DisplayCredits{#2})%
\listgadd{\CreditsSumList}{#2}%
}%
\newcommand{\CreditsName}{point}%
\newcommand{\CreditsNamePlural}{points}%
\newcommand{\DisplayCredits}[1]{%
\pgfmathequal{#1}{1}%
\ifnumequal{\pgfmathresult}{1}{
#1 \CreditsName%
}{%
#1 \CreditsNamePlural%
}%%
}%
\newcommand{\ReadCreditValueWithSumUp}[2][\CreditsFileHandle]{%
\ReadCreditValue[#1]{#2}%
#2\sumup{#2}%
}%
\newcommand{\ReadCreditValue}[2][\CreditsFileHandle]{%
\read#1 to #2% Read in from file
}%
\newcounter{task}%
\newenvironment{Task}[1]{%
\refstepcounter{task}%
\ifnumequal{\CounterValue{NumberOfLaTeXRuns}}{\WriteFileThreshold}{%
\ReadCreditValue{\@@TotalCreditsValue}%
}{}%
\begin{flushleft}
{\Large \textbf{Task} \textbf{\thetask} -- \textbf{#1}}%%
\hfill \fcolorbox{black}{yellow}{\DisplayCredits{\@@TotalCreditsValue}}%
\end{flushleft}%
\begin{itemize}
}{%
\end{itemize}
\ifnumless{\CounterValue{NumberOfLaTeXRuns}}{\WriteFileThreshold}{%
%Do only sum up when not in final output mode
\sumuplist{\CreditsSumList}%
\WriteToFile{\tempsum}%
}{% No, the number of runs is greater than zero, so ... do nothing
}%
\xdef\CreditsSumList{}%
}%
\newcommand{\sumuplist}[1]{%
\xdef\tempsum{0}%
\forlistloop{\sumup}{#1}%
}%
\regtotcounter{task}%
\newcounter{totaltask@@counter}%
\newcounter{last@@counter}%
\newcounter{loop@@counter}%
\newcommand{\mk}[1]{%
}%
\newcommand{\listoftasks}{%
\gdef\CurrentSumValue{0.0}%
\IfFileExists{\jobname.credits}{%
\CloseForWriting%
\OpenForReading{\jobname.credits}%
\begin{center}
\setcounter{totaltask@@counter}{\number\totvalue{task}+1}%
\setcounter{last@@counter}{\number\totvalue{task}}%
\Huge \textbf{List of Tasks}\normalsize
\vspace{\baselineskip} %
\begin{tabular}{|c||r|c|c|}
\hline
Task number & Total credits & Achieved credits\\
\hline
\hline
\forloop{loop@@counter}{1}{\CounterValue{loop@@counter} < \CounterValue{totaltask@@counter}}{%
\CounterValue{loop@@counter} & %
\ReadCreditValueWithSumUp{\CurrentSumValue}% Do not delete that % character before!
& %
\ifnum\number\value{loop@@counter}<\CounterValue{last@@counter}% %\number\value{last@@counter}
\tabularnewline\hline
\fi%
\xdef\CurrentSumValue{0}%
}%
\tabularnewline%
\hline%
\hline\hline%
\multicolumn{1}{|l||}{Total:} & \tempsum & \tabularnewline%
\hline%
\end{tabular}%
\end{center}%
\newpage% Well, later an \clearpage?
% Now close the handle than open it again for reading total values in the individual tasks to complete
%the values.
\CloseForReading%
\OpenForReading{\jobname.credits}%
}{}%
}%
\AtBeginDocument{%
\refstepcounter{NumberOfLaTeXRuns}%
\ifnumequal{\CounterValue{NumberOfLaTeXRuns}}{\WriteFileThreshold}{%
\CloseForWriting%
\OpenForReading{\jobname.credits}%
}{%
\OpenForWriting{\jobname.credits}%
}%
}%
\AtEndDocument{%
\immediate\closeout\CreditsFileHandle%
\ifnumequal{\CounterValue{NumberOfLaTeXRuns}}{\WriteFileThreshold}{%
\setcounter{NumberOfLaTeXRuns}{1}}{}%
\immediate\write\@auxout{%
\string\setcounter{NumberOfLaTeXRuns}{\number\value{NumberOfLaTeXRuns}}%
}%
}%
\makeatother
\begin{document}
\listoftasks
\begin{Task}{Java}%
\DisplayQuestionAndCredits{Hello World in Java}{10}%
\end{Task}%
\begin{Task}{C++}%
\DisplayQuestionAndCredits{Virtual methods}{10}%
\DisplayQuestionAndCredits{Operator overloading}{15}%
\end{Task}%
\begin{Task}{\LaTeXe}
\DisplayQuestionAndCredits{Reproduce this document ;-)}{2000}%
\DisplayQuestionAndCredits{Are there better sites than TeX.SX?}{10000.14159}%
\end{Task}
\begin{Task}{Fortran 54}
\DisplayQuestionAndCredits{Write a Fortran program better than \LaTeXe }{100}
\DisplayQuestionAndCredits{Write code for a Babbage machine with objects}{200}
\end{Task}
\end{document}
答案2
使用当前版本的exsheets
该包提供了这种可能性。exsheets
有一个命令\addpoints
可以打印和保存当前环境的分数{question}
。问题的分数总和可用作问题属性可以points
通过以下方式检索\GetQuestionProperty{<property>}{<question ID>}
结合exsheets
“创建自定义标题实例的可能性”和命令,\CurrentQuestionID
可以定义一种标题类型,打印正文\addpoints
中保存的点的总和{question}
。
\documentclass{article}
\usepackage{exsheets}
% custom headings instance:
\DeclareInstance{exsheets-heading}{custom}{default}{
% write the sum of points after the title of the question:
title-post-code =
\bfseries~(\GetQuestionProperty{points}{\CurrentQuestionID} Points) ,
% print the title:
attach = { main[l,vc]title[l,vc](0pt,0pt) }
}
% use the newly defined heading instance:
\SetupExSheets{
headings = custom ,
points/name = Point/s
}
\begin{document}
\begin{question}[name=Java]
\begin{enumerate}
\item Hello World (\addpoints{2})
\item for-each (\addpoints{1})
\end{enumerate}
\end{question}
\begin{question}[name=C++]
\begin{enumerate}
\item Bla bla (\addpoints{2})
\item Blub blub (\addpoints{4})
\end{enumerate}
\end{question}
\begin{question}[name=\LaTeX]
\begin{enumerate}
\item Foo foo (\addpoints{2})
\item bar bar (\addpoints{2})
\end{enumerate}
\end{question}
\end{document}
间距看起来有点奇怪,但可以进行调整,例如,通过添加below = .5\baselineskip
标题实例的定义。
使用更新的版本exsheets
(v0.14 2014/06/28,已经在 CTAN 和 TeX Live 2014 中),只需稍加努力就可以定义分级表。诀窍是使用问题属性。为此,我使用已由定义的属性subtitle
、counter
和。命令和}我循环遍历所有问题并检索所需的数据:points
exsheets
\GetQuestionProperty{<property>}{<question id>}
\ForEachQuestion{<code where #1 refers to the question id>
\documentclass{article}
\usepackage{exsheets}[2014/06/28]
% a custom headings instance that uses the `subtitle' property:
\DeclareInstance{exsheets-heading}{custom}{default}{
subtitle-format = \bfseries ,
subtitle-post-code =
\bfseries~(\GetQuestionProperty{points}{\CurrentQuestionID} Points) ,
join = {
title[r,B]number[l,B](.333em,0pt) ;
title[r,B]subtitle[l,B](.333em,0pt)
} ,
attach = { main[l,vc]title[l,vc](0pt,0pt) } ,
below = .5\baselineskip
}
% use the new instance, other settings:
\SetupExSheets{
question/name = Task ,
headings = custom ,
points/name = Point/s
}
% define a grading table that retrieves subtitles and points:
\newcommand*\gradingtable{%
\begin{tabular}{|l|*{3}{c|}c|}\hline
Task &
\ForEachQuestion{%
\GetQuestionProperty{counter}{##1}
\GetQuestionProperty{subtitle}{##1}\iflastquestion{}{&}%
}
& Total \\ \hline
Points &
\ForEachQuestion{\GetQuestionProperty{points}{##1}\iflastquestion{}{&}} &
\pointssum* \\ \hline
Reached &
\ForEachQuestion{\iflastquestion{}{&}} &
\\ \hline
\end{tabular}%
}
\begin{document}
\begin{center}
\gradingtable
\end{center}
\begin{question}[subtitle=Java,ID=Java]
\begin{enumerate}
\item Hello World (\addpoints{2})
\item for-each (\addpoints{1})
\end{enumerate}
\end{question}
\begin{question}[subtitle=C++,ID=C++]
\begin{enumerate}
\item Bla bla (\addpoints{2})
\item Blub blub (\addpoints{4})
\end{enumerate}
\end{question}
\begin{question}[subtitle=\LaTeX,ID=LaTeX]
\begin{enumerate}
\item Foo foo (\addpoints{2})
\item bar bar (\addpoints{2})
\end{enumerate}
\end{question}
答案3
此答案利用现有的\label
ing 功能将总数写入辅助文件。然后可以在\ref{}
需要的地方使用标签值。
正如评论中提到的那样,需要两次传递才能正常工作。
还要注意,\AtEndDocument
用于调用最终\closetask
命令。如果您从不使用,这可能会导致问题\task
...这可以放入带有在第一次使用时设置的标志的条件中\task
,也\task
可以变成使用的环境\begin{task}...\end{task}
。使用环境实际上可能在语义上更有意义,尽管子任务不会得到开箱即用的支持。
\documentclass[12pt,oneside,a4paper,final]{scrartcl}
\newcounter{task}
\setcounter{task}{0}
% Create a new counter to keep track of points for each task
\newcounter{taskpoints}
\setcounter{taskpoints}{0}
% Create \pointslabel{}{} for saving the points total as a label
\makeatletter
\@ifpackageloaded{hyperref}{%
\newcommand{\pointslabel}[2]{%
\protected@write \@auxout {}{\string \newlabel {#1}{{#2}{\thepage}{#2}{#1}{}} }%
\hypertarget{#1}{#2}
}}{%
\newcommand{\pointslabel}[2]{%
\protected@write \@auxout {}{\string \newlabel {#1}{{#2}{}}}}}
\makeatother
% Call \closetask at the end of each task, before beginning next task
\def\closetask{%
\pointslabel{taskpoints:\arabic{task}}{\arabic{taskpoints}}}
\AtEndDocument{\closetask} % Automatically close the last task
% Reset the taskpoints whenever the task increments
\usepackage{chngcntr}
\counterwithin{taskpoints}{task}
\newcommand{\points}[1]{
% Add #1 points to the taskpoints counter
\addtocounter{taskpoints}{#1}
(#1~Points)
}
\newcommand{\task}[1]{
\closetask % Close out previous task
\refstepcounter{task}
\begin{flushleft}
{\LARGE\bf Task \arabic{task}}
\end{flushleft}
{\Large \textbf{#1}}
% Addition of points with \ref to label
\leavevmode\hfill (\ref{taskpoints:\arabic{task}} Points)\\
}
\begin{document}
\task{Java}
Hello World \points{2}
for-each \points{1}
\task{C++}
Bla bla \points{2}
Blub blub \points{4}
\task{Latex}
Foo foo \points{2}
bar bar \points{2}
\end{document}
答案4
这个改进的版本基于 Christian Huper 的回答:
- 它有一个更精美的表格来打印任务列表(修复了表格中的换行)
- 它打印的是“1 point”而不是“1 points”
\documentclass[12pt,oneside,a4paper,final]{scrartcl}
\usepackage{nameref}
\usepackage{calculator}%
\usepackage{calc}%
\usepackage{totcount}%
\usepackage{forloop}
\usepackage{tikz}
\newcounter{task}
\setcounter{task}{0}
\xdef\TotalCredits{0}%
\xdef\TaskCredits{0}%
\xdef\SubCredits{0}%
\newcommand{\printpoints}[1]{#1~\pgfmathequal{#1}{1}\ifnum\pgfmathresult=1 point\else points\fi}
\newcommand{\points}[2]{
\item #1 (\printpoints{#2})
\ADD{\TaskCredits}{#2}{\SubCredits}%
\xdef\TaskCredits{\SubCredits}%
}%
\makeatletter
\newcommand{\WriteCreditsToFile}[1]{%
\immediate\write\@auxout{%
\string\newlabel{credits::\number\value{task}}{{\thesection}{\thepage}{#1}{}}
}% End of writing to AUX file
}%
\makeatother
%
\makeatletter
\AtEndDocument{%
\immediate\write\@auxout{%
\string\newlabel{totalcredits}{{\thesection}{\thepage}{\TotalCredits}{}}
}
}
\makeatother
\newenvironment{Task}[1]{%
\xdef\TaskCredits{0}%
\xdef\SubCredits{0}%
\xdef\CreditsSoFar{0}%
\refstepcounter{task}
\begin{flushleft}
{\LARGE\bfseries Task \arabic{task}}
\end{flushleft}
{\Large \textbf{#1}}
\leavevmode\hfill (\nameref*{credits::\number\value{task}}~Points)\\
\begin{itemize} % Just for 'better' typography
}{% Close it
\end{itemize}
\WriteCreditsToFile{\TaskCredits}%
% Count all credits for the summary%
\ADD{\TotalCredits}{\TaskCredits}{\CreditsSoFar}%
\xdef\TotalCredits{\CreditsSoFar}%
}%
\regtotcounter{task}%
\makeatletter%
\newcounter{loop@@counter}%
\newcounter{totaltask@@counter}%
\newcounter{last@@counter}%
\newcommand{\listoftasks}{%
\begin{center}
\setcounter{totaltask@@counter}{\number\totvalue{task}+1}%
\setcounter{last@@counter}{\number\totvalue{task}}%
\begin{tabular}{|c||r|c|c|}
\hline
Task number & Total credits & Achieved credits\\
\hline
\hline
\forloop{loop@@counter}{1}{\number\value{loop@@counter} < \number\value{totaltask@@counter}}{
\number\value{loop@@counter} & \nameref*{credits::\number\value{loop@@counter}} Points &
\ifnum\number\value{loop@@counter}<\number\value{last@@counter}
\tabularnewline\hline
\fi
}
\tabularnewline
\hline
\hline\hline
Total: & \nameref*{totalcredits} Points & \tabularnewline%
\hline
\end{tabular}
\end{center}
}%
\makeatother
\begin{document}
\listoftasks
\newpage
\begin{Task}{Java}
\points{Hello World}{1}
\end{Task}%
\begin{Task}{C++}
\points{for-each}{0.5}
\points{blub blub}{0.5}
\end{Task}
\begin{Task}{Latex}
\points{Foo}{2}
\points{bar}{2}
\end{Task}
\begin{Task}{Fortran54} % ;-)
\points{Write a Fortran 54 code to \LaTeX ;-)}{100}
\points{Write a Babbage machine code to replace \LaTeX ;-)}{1000}
\end{Task}
\end{document}