Skip to content

Commit

Permalink
[latex] Add command problem_slides
Browse files Browse the repository at this point in the history
  • Loading branch information
mpsijm committed Nov 17, 2024
1 parent 07fe59c commit ca316be
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 12 deletions.
1 change: 1 addition & 0 deletions bin/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ def build_contest_zip(problems, zipfiles, outfile, statement_language):
]
+ list(Path('.').glob(f'contest*.{statement_language}.pdf'))
+ list(Path('.').glob(f'solutions*.{statement_language}.pdf'))
+ list(Path('.').glob(f'problem-slides*.{statement_language}.pdf'))
):
if Path(fname).is_file():
zf.write(
Expand Down
41 changes: 34 additions & 7 deletions bin/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import re
import shutil
import sys
from enum import Enum
from pathlib import Path
from typing import Optional

from colorama import Fore, Style

import config
from contest import contest_yaml
from contest import contest_yaml, problems_yaml
import problem
from util import (
copy_and_substitute,
Expand Down Expand Up @@ -387,19 +388,27 @@ def find_logo() -> Path:
return config.tools_root / 'latex' / 'images' / 'logo-not-found.pdf'


class PdfType(str, Enum):
PROBLEM = 'problem'
PROBLEM_SLIDE = 'problem-slide'
SOLUTION = 'solution'


def build_contest_pdf(
contest: str,
problems: list["problem.Problem"],
tmpdir: Path,
language: str,
solutions=False,
build_type=PdfType.PROBLEM,
web=False,
) -> bool:
builddir = tmpdir / contest / 'latex' / language
builddir.mkdir(parents=True, exist_ok=True)
build_type = 'solution' if solutions else 'problem'

main_file = 'solutions' if solutions else 'contest'
problem_slides = build_type == PdfType.PROBLEM_SLIDE
solutions = build_type == PdfType.SOLUTION

main_file = 'problem-slides' if problem_slides else 'solutions' if solutions else 'contest'
main_file += '-web.tex' if web else '.tex'

bar = PrintBar(f'{main_file[:-3]}{language}.pdf')
Expand Down Expand Up @@ -448,6 +457,8 @@ def build_contest_pdf(
else config.tools_root / 'latex' / f'contest-{build_type}.tex'
).read_text()

probyaml = problems_yaml()

for problem in problems:
if build_type == 'problem':
prepare_problem(problem, language)
Expand All @@ -465,12 +476,28 @@ def build_contest_pdf(
bar.warn(f'solution.{language}.tex not found', problem.name)
continue

background = next(
(p['rgb'] for p in probyaml if p['id'] == str(problem.path) and 'rgb' in p), '#ffffff'
)[1:]
# Source: https://github.com/DOMjudge/domjudge/blob/095854650facda41dbb40966e70199840b887e33/webapp/src/Twig/TwigExtension.php#L1056
foreground = (
'000000'
if sum(int(background[i : i + 2], 16) for i in range(0, 6, 2)) > 450
else 'ffffff'
)
border = "".join(
("00" + hex(max(0, int(background[i : i + 2], 16) - 64))[2:])[-2:]
for i in range(0, 6, 2)
)
problems_data += substitute(
per_problem_data,
{
'problemlabel': problem.label,
'problemyamlname': problem.settings.name[language].replace('_', ' '),
'problemauthor': problem.settings.author,
'problembackground': background,
'problemforeground': foreground,
'problemborder': border,
'timelimit': get_tl(problem),
'problemdir': problem.path.absolute().as_posix(),
'problemdirname': problem.name,
Expand All @@ -492,9 +519,9 @@ def build_contest_pdf(
return build_latex_pdf(builddir, Path(main_file), language, bar)


def build_contest_pdfs(contest, problems, tmpdir, lang=None, solutions=False, web=False):
def build_contest_pdfs(contest, problems, tmpdir, lang=None, build_type=PdfType.PROBLEM, web=False):
if lang:
return build_contest_pdf(contest, problems, tmpdir, lang, solutions, web)
return build_contest_pdf(contest, problems, tmpdir, lang, build_type, web)

"""Build contest PDFs for all available languages"""
statement_languages = set.intersection(*(set(p.statement_languages) for p in problems))
Expand All @@ -519,7 +546,7 @@ def build_contest_pdfs(contest, problems, tmpdir, lang=None, solutions=False, we
color_type=MessageType.FATAL,
)
return all(
[build_contest_pdf(contest, problems, tmpdir, lang, solutions, web) for lang in languages]
build_contest_pdf(contest, problems, tmpdir, lang, build_type, web) for lang in languages
)


Expand Down
55 changes: 50 additions & 5 deletions bin/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,26 @@ def build_parser():
pdfparser.add_argument('--web', action='store_true', help='Create a web version of the pdf.')
pdfparser.add_argument('-1', action='store_true', help='Only run the LaTeX compiler once.')

# Problem slides
pdfparser = subparsers.add_parser(
'problem_slides', parents=[global_parser], help='Build the problem slides pdf.'
)
# pdfparser.add_argument(
# '--all',
# '-a',
# action='store_true',
# help='Create problem statements for individual problems as well.',
# )
pdfparser.add_argument('--no-timelimit', action='store_true', help='Do not print timelimits.')
pdfparser.add_argument(
'--watch',
'-w',
action='store_true',
help='Continuously compile the pdf whenever a `problem_statement.tex` changes. Note that this does not pick up changes to `*.yaml` configuration files.',
)
# pdfparser.add_argument('--web', action='store_true', help='Create a web version of the pdf.')
pdfparser.add_argument('-1', action='store_true', help='Only run the LaTeX compiler once.')

# Solution slides
solparser = subparsers.add_parser(
'solutions', parents=[global_parser], help='Build the solution slides pdf.'
Expand Down Expand Up @@ -1059,7 +1079,16 @@ def run_parsed_arguments(args):

if action in ['solutions']:
success &= latex.build_contest_pdfs(
contest, problems, tmpdir, solutions=True, web=config.args.web
contest, problems, tmpdir, build_type=latex.PdfType.SOLUTION, web=config.args.web
)

if action in ['problem_slides']:
success &= latex.build_contest_pdfs(
contest,
problems,
tmpdir,
build_type=latex.PdfType.PROBLEM_SLIDE,
web=config.args.web,
)

if action in ['zip']:
Expand All @@ -1073,11 +1102,27 @@ def run_parsed_arguments(args):
contest, problems, tmpdir, statement_language, web=True
)
if not config.args.no_solutions:
success &= latex.build_contest_pdfs(
contest, problems, tmpdir, statement_language, solutions=True
success &= latex.build_contest_pdf(
contest,
problems,
tmpdir,
statement_language,
build_type=latex.PdfType.SOLUTION,
)
success &= latex.build_contest_pdf(
contest,
problems,
tmpdir,
statement_language,
build_type=latex.PdfType.SOLUTION,
web=True,
)
success &= latex.build_contest_pdfs(
contest, problems, tmpdir, statement_language, solutions=True, web=True
success &= latex.build_contest_pdf(
contest,
problems,
tmpdir,
statement_language,
build_type=latex.PdfType.PROBLEM_SLIDE,
)

outfile = contest + '.zip'
Expand Down
17 changes: 17 additions & 0 deletions latex/contest-problem-slide.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
\begingroup\graphicspath{{{%problemdir%}/problem_statement/}}
\renewcommand{\problemlabel}{{%problemlabel%}}
\renewcommand{\problemyamlname}{{%problemyamlname%}}
\renewcommand{\problemauthor}{{%problemauthor%}}
\renewcommand{\problembackground}{{%problembackground%}}
\renewcommand{\problemforeground}{{%problemforeground%}}
\renewcommand{\problemborder}{{%problemborder%}}
\renewcommand{\timelimit}{{%timelimit%}}
\input{{%problemdir%}/problem_statement/problem-slide.\lang.tex}
\renewcommand{\problemlabel}{}
\renewcommand{\problemyamlname}{}
\renewcommand{\problemauthor}{}
\renewcommand{\problembackground}{}
\renewcommand{\problemforeground}{}
\renewcommand{\problemborder}{}
\renewcommand{\timelimit}{}
\endgroup
3 changes: 3 additions & 0 deletions latex/contest-solution.tex
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@
\renewcommand{\timelimit}{{%timelimit%}}
\input{{%problemdir%}/problem_statement/solution.\lang.tex}
\renewcommand{\problemlabel}{}
\renewcommand{\problemyamlname}{}
\renewcommand{\problemauthor}{}
\renewcommand{\timelimit}{}
\endgroup
101 changes: 101 additions & 0 deletions latex/problem-slides.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
\documentclass[rgb,dvipsnames,aspectratio=169,9pt,t]{beamer}

\usepackage[T1, OT1]{fontenc}
\DeclareTextSymbolDefault{\dh}{T1}
\usepackage[english]{babel}
\usepackage{lmodern}

%-------------------------------------------------------------------------------
% The following are required for most problems:
%-------------------------------------------------------------------------------
\usepackage{amsmath,amssymb}
\usepackage{pgf,tikz}
\usepackage{mathrsfs}
\usetikzlibrary{arrows}
\usetikzlibrary{shapes}
\usetikzlibrary{backgrounds}
\usetikzlibrary{patterns}
\usetikzlibrary{positioning}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.15}
\usepackage{graphicx}
\usepackage{listings}
%\usepackage{subcaption}
\usepackage{algorithm}
\usepackage[makeroom]{cancel}
\usepackage[noend]{algpseudocode}
\usepackage{standalone}
\usepackage{ifthen}
\usepackage{tcolorbox}
\usepackage[autoplay,controls,loop,poster=last]{animate}

\lstset{
backgroundcolor=\color{white},
tabsize=4,
language=python,
basicstyle=\footnotesize\ttfamily,
breaklines=true,
keywordstyle=\color[rgb]{0, 0, 1},
commentstyle=\color[rgb]{0, 0.5, 0},
stringstyle=\color{red}
}

\newcommand{\timelimit}{0.0s}
\newcommand{\problemlabel}{} % Empty to hide activity chart
\newcommand{\problemauthor}{Problem author}
\newcommand{\problembackground}{}
\newcommand{\problemforeground}{}
\newcommand{\problemborder}{}
% TODO: Clean these up
\newcommand{\problemyamlname}{Problem name}
\newcommand{\fullproblemtitle}{\problemlabel: \problemyamlname}
\newcommand{\problemtitle}{\problemyamlname}

\usetheme[numbering=none,block=fill]{metropolis}

\newcommand{\illustration}[3]{
\begin{column}[T]{#1\textwidth}
\includegraphics[width=\textwidth]{#2}
\ifstrempty{#3}{
\vspace{-5pt}
}{
\begin{flushright}
\vspace{-5pt}
\tiny #3
\end{flushright}
}
\end{column}
}

\setbeamertemplate{frametitle}{%
\nointerlineskip%
\vspace{1em}%
\begin{minipage}{0.06\paperwidth}%
\begin{tikzpicture}
\definecolor{problembackground}{HTML}{\problembackground}
\definecolor{problemforeground}{HTML}{\problemforeground}
\definecolor{problemborder}{HTML}{\problemborder}
\node[rectangle,rounded corners,thick,minimum size=2em,draw=problemborder,fill=problembackground,text=problemforeground] (0, 0) {\Huge\problemlabel};
\end{tikzpicture}
\end{minipage}%
\begin{minipage}{0.8\paperwidth}%
\color{black}%
\ifdefempty{\problemlabel}{%
\insertframetitle\strut%
}{%
\problemtitle%
\\[0.3em]%
\tiny%
Time limit: \timelimit{}s%
\quad\quad%
Problem Author: \problemauthor%
\strut%
}%
\end{minipage}%
\hfill%
}

\begin{document}
\input{./contest-problem-slides.tex}
\end{document}

0 comments on commit ca316be

Please sign in to comment.