TeX Alchemist Online

TeX のこと,フォントのこと,Mac のこと

学習塾でのLaTeX活用事例集 ~[改訂第9版]LaTeX美文書作成入門の補足~

この記事は TeX & LaTeX Advent Calendar 2023 の4日目の記事です。3日目はuwabamiさんでした。 5日目はYarakashi_Kikohshiさんです。


【目次】


LaTeXを使って幸せになる方法とは?

今年の TeX & LaTeX Advent Calendar 2023 の重点テーマは「(La)TeXで幸せになる方法」だそうです。皆さん,LaTeXを使って何ができると,幸せになれるでしょうか? 誰しもが,LaTeXを使って学校・塾・予備校といった教育機関の運営を効率化して幸せになりたい!という願望を抱いたことがあるのではないでしょうか!?

……というのはちょっと限定的すぎたかもしれませんが,教育機関に限らず,文書生成にまつわるルーチンワークが存在する組織であるならば,LaTeXによってその運営を効率化することで幸せになれる可能性があります。

[改訂第9版]LaTeX美文書作成入門 今月発売!

さて,今月9日にいよいよ[改訂第9版]LaTeX美文書作成入門が発売となります。

gihyo.jp

今回,私はこの『美文書』に「学習塾におけるLaTeXの活用」と題したコラムを寄稿する機会を頂きました。このコラムでは,LaTeXを使って学習塾の運営を効率化する種々の手法について紹介しました。ここで紹介した手法は,教育機関に留まらず,幅広い分野の会社や組織においても活用できるはずです。いかなる組織であれ,文書生成にまつわるワークフローはLaTeXによって効率化できうるという,LaTeXの持つ高いポテンシャルを伝えることが,今回の執筆の主旨でありました。

ただし,書籍においては紙面の都合がありますので,今回のコラムではあくまでアイデアや実装方針を述べるに留まり,具体的なコード例を紹介することはできませんでした。そこで,今回の TeX & LaTeX Advent Calendar 2023 の機会を利用して,このコラムで述べたアイデアの具体的実装例を紹介してみることとしましょう。

とはいえ,それぞれの手法は,その多くが,このブログや講演などの機会で既に紹介したことがあります。ですが,情報があちこちに散逸していますので,ここで改めて情報を集約しておく意義はあるでしょう。

差し込み印刷

コラムではLaTeXによる差し込み印刷の手法を述べました。この手法の詳細については, TeX & LaTeX Advent Calendar 2020 の記事で既に解説したことがあります。

doratex.hatenablog.jp

また,これを受けて,LaTeXユーザが差し込み印刷をより幸せに行うための bxkvcmd パッケージが,ZRさんによって作られました。

答案の切り貼り&電子採点&復元

コラムでは,次のような紙実施&電子採点を融合した採点ワークフローを紹介しました。

  1. 生徒ごとに個別化された答案用紙をLaTeXで生成し,印刷して紙で試験を実施する。
  2. 回収した答案用紙をスキャンしてPDFとする。
  3. 設問単位で解答用紙を電子的に切り刻んだ採点フォームをLaTeXで生成する。
  4. iPad上で電子採点・添削を行う。
  5. 採点後の採点フォームをLaTeXで統合して元の解答用紙を復元して返却する。

この手法については,TeXConf 2017 の講演(日本大学湘南キャンパス,2017年)で紹介しました。

また,このときの手法をもう少し改良したバージョンを,TUG 2019(米カリフォルニア州パロアルト,2019年)の講演で紹介しました。

なお,ステップ1で必要になる「生徒ごとに個別化された答案用紙」を生成するために,QRコードを大量生成してLaTeX文書に埋め込む必要があります。その手法については次の記事で解説しました。

doratex.hatenablog.jp

「問題内容の定義」と「教材ごとの問題使用状況の定義」の分離

コラムでは,データベースの正規化と同様の発想で,「問題内容の定義」と「教材ごとの問題使用状況の定義」を分離しておくと,教材改訂における保守性が向上するというアイデアも述べました。その具体的なコード例は,TeX & LaTeX Advent Calendar 2016 の次の記事で紹介されています。

qiita.com

日付演算

コラムでは,LaTeXの演算機能によって「コンパイルし直せば常に今年のカレンダー上で正しい日付・曜日が出力される文書」が作れることを紹介しました。実際,実務的な文書作成においては,

  • 2023年4月1日の247日後は何年何月何日・何曜日か?
  • 入試本番まで残り何日か?

といった日付演算を行う機会がよくあります。

曜日取得

特定日付の曜日取得であれば,『美文書』に紹介されている Zeller の公式が使えます。okumacro.sty\曜 はその実装です。

日付演算

日付演算については,グレゴリオ暦のYYYY/MM/DDを一度(修正)ユリウス通日に換算してから加算や差分の演算を行うのがよいです。

TeXによる(修正)ユリウス通日計算の実装例は,次のような事例が見られます。

自分は,e-TeX の \numexpr を活用して,グレゴリオ暦とユリウス通日との換算を実装しました。ただし,\numexpr における整数同士の除算は,多くのプログラミング言語における整数除算と異なり,商が切り捨てではなく四捨五入となっている点に注意が必要です。この「四捨五入除算」が何とも扱いにくいので,普通のプログラミング言語における除算と同様に切り捨て除算を行う \truncdiv を定義しておくと便利です。ここでは TeX StackExchange における ShreevatsaR 氏の実装例を使いましょう。

% #1 を #2 で割った余りを算出
\def\moduloop#1#2{%
  \numexpr
    \ifnum\numexpr((#1)-((#1)/(#2))*(#2))\relax<0
      ((#1)-((#1)/(#2))*(#2)+(#2))%
    \else
      ((#1)-((#1)/(#2))*(#2))%
    \fi
  \relax
}

% #1 を #2 で割った商(四捨五入ではなく切り捨て)を算出
\def\truncdiv#1#2{\numexpr(((#1)-\moduloop{#1}{#2})/(#2))\relax}

\newcount\@tempY
\newcount\@tempM
\newcount\@tempD
\newcount\JD

% グレゴリオ暦 → ユリウス通日(結果は \JD に格納される)
\def\YMDtoJD#1#2#3{%
  \@tempY=\numexpr#1\relax
  \@tempM=\numexpr#2\relax
  \@tempD=\numexpr#3\relax
  \JD=-32044\relax
  \ifnum\@tempM<3
    \advance\@tempY\m@ne
    \advance\@tempM12\relax
  \fi
  \advance\@tempY4800\relax
  \advance\@tempM-3\relax
  \advance\@tempD\m@ne
  \@tempcnta=\numexpr\truncdiv{\@tempY}{400}\relax
  \advance\@tempY\numexpr-\@tempcnta*400\relax
  \advance\JD\numexpr\@tempcnta*146097\relax
  \@tempcnta=\numexpr\truncdiv{\@tempY}{100}\relax
  \advance\@tempY\numexpr-\@tempcnta*100\relax
  \advance\JD\numexpr\@tempcnta*36524\relax
  \@tempcnta=\numexpr\truncdiv{\@tempY}{4}\relax
  \advance\@tempY\numexpr-\@tempcnta*4\relax
  \advance\JD\numexpr\@tempcnta*1461+\@tempY*365\relax
  \@tempcnta=\numexpr\truncdiv{\@tempM}{5}\relax
  \advance\@tempM\numexpr-\@tempcnta*5\relax
  \advance\JD\numexpr\@tempcnta*153\relax
  \@tempcnta=\numexpr\truncdiv{\@tempM}{2}\relax
  \advance\@tempM\numexpr-\@tempcnta*2\relax
  \advance\JD\numexpr\@tempcnta*61+\@tempM*31+\@tempD\relax
}

\newcount\GregorianY
\newcount\GregorianM
\newcount\GregorianD

% ユリウス通日 → グレゴリオ暦(結果は \GregorianY / \GregorianM / \GregorianD に格納される)
\def\JDtoYMD#1{%
  \@tempcnta=\numexpr#1+32044\relax
  \GregorianY=-4800\relax
  \GregorianM=3\relax
  \GregorianD=\@ne
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{146097}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*146097\relax
  \advance\GregorianY\numexpr\@tempcntb*400\relax
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{36524}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*36524\relax
  %
  \ifnum\@tempcntb=4
    \advance\@tempcntb\m@ne
    \advance\@tempcnta36524\relax
  \fi
  \advance\GregorianY\numexpr\@tempcntb*100\relax
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{1461}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*1461\relax
  \advance\GregorianY\numexpr\@tempcntb*4\relax
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{365}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*365\relax
  %
  \ifnum\@tempcntb=4
    \advance\@tempcntb\m@ne
    \advance\@tempcnta365\relax
  \fi
  \advance\GregorianY\@tempcntb
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{153}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*153\relax
  \advance\GregorianM\numexpr\@tempcntb*5\relax
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{61}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*61\relax
  \advance\GregorianM\numexpr\@tempcntb*2\relax
  %
  \@tempcntb=\numexpr\truncdiv{\@tempcnta}{31}\relax
  \advance\@tempcnta\numexpr-\@tempcntb*31\relax
  \advance\GregorianM\@tempcntb
  %
  \advance\GregorianD\@tempcnta
  %
  \ifnum\GregorianM>12
    \advance\GregorianY\@ne
    \advance\GregorianM-12\relax
  \fi
}

使用例

日付の加算

例えば「2023年4月1日の247日後は何年何月何日・何曜日か?」であれば,次のように算出できます。

\def\n日後を出力#1#2#3#4{%
  % まずは元日付のユリウス通日を算出
  \YMDtoJD{#1}{#2}{#3}%
  % 日数を加算
  \advance\JD#4
  % グレゴリオ暦に復元
  \JDtoYMD{\JD}%
  % 結果出力
  \the\GregorianY\the\GregorianM\the\GregorianD 日(
  % 曜日は7で割ればよい
  \ifcase\moduloop{\JD}{7}\or\or\or\or\or\or\fi
  曜日)
}

2023年4月1日の247日後は\n日後を出力{2023}{4}{1}{247}です。

出力結果

2つの日付の間の日数の算出

例えば「今日から大学入学共通テストまでの残り日数」であれば,次のように算出できます。

\newcount\dateDiffCount
\newcount\@tempcntc

% #1年#2月#3日 と #4年#5月#6日 の日数差を求めて \dateDiffCount に代入する
\def\dateDiff#1#2#3#4#5#6{%
  % 起点となる日付のユリウス通日を保存
  \YMDtoJD{#1}{#2}{#3}%
  \@tempcntc=\JD
  % 終点となる日付のユリウス通日を算出
  \YMDtoJD{#4}{#5}{#6}%
  % 差を算出
  \dateDiffCount=\numexpr\JD-\@tempcntc\relax
}

\dateDiff{\year}{\month}{\day}{2024}{1}{13}
大学入学共通テストまで残り\the\dateDiffCount 日です!

出力結果