git » alan.git » commit 426ace4

Refine PDF layout and switch to neutral profile codes

author Alan Dipert
2025-12-06 18:27:38 UTC
committer Alan Dipert
2025-12-06 18:27:38 UTC
parent 66b208f3965f370d22a3141b586246b36e466312

Refine PDF layout and switch to neutral profile codes

generator.py +1 -1
main.py +3 -3
render_text.py +39 -14

diff --git a/generator.py b/generator.py
index 4cedb33..4f2b0f5 100644
--- a/generator.py
+++ b/generator.py
@@ -586,7 +586,7 @@ def generate_test(
             }
         )
 
-    proword = {"easy": "ECHO", "medium": "FOXTROT", "hard": "GOLF", "extreme": "HOTEL"}[hardness]
+    proword = {"easy": "MAPLE", "medium": "CEDAR", "hard": "CYPRESS", "extreme": "SEQUOIA"}[hardness]
     meta = {
         "version": "backtrack-0.2",
         "description": "Alan's Language Aptitude iNstrument (ALAN) synthesized via backtracking search",
diff --git a/main.py b/main.py
index fe95dcb..bf41fa7 100644
--- a/main.py
+++ b/main.py
@@ -26,9 +26,9 @@ def parse_args() -> argparse.Namespace:
     )
     parser.add_argument(
         "--profile",
-        choices=["ECHO", "FOXTROT", "GOLF", "HOTEL"],
+        choices=["MAPLE", "CEDAR", "CYPRESS", "SEQUOIA"],
         default=None,
-        help="Alias for hardness without revealing labels in output (ECHO=easy, FOXTROT=medium, GOLF=hard, HOTEL=extreme).",
+        help="Alias for hardness without revealing labels in output (MAPLE=easy, CEDAR=medium, CYPRESS=hard, SEQUOIA=extreme).",
     )
     parser.add_argument(
         "--run-dir",
@@ -54,7 +54,7 @@ def _git_sha() -> str | None:
 
 def main() -> None:
     args = parse_args()
-    proword_map = {"ECHO": "easy", "FOXTROT": "medium", "GOLF": "hard", "HOTEL": "extreme"}
+    proword_map = {"MAPLE": "easy", "CEDAR": "medium", "CYPRESS": "hard", "SEQUOIA": "extreme"}
     hardness = args.hardness
     if args.profile:
         hardness = proword_map[args.profile]
diff --git a/render_text.py b/render_text.py
index 7edaa0b..c11e9a9 100644
--- a/render_text.py
+++ b/render_text.py
@@ -141,7 +141,7 @@ def _booklet_latex(data: Dict[str, Any]) -> str:
 
     lines = [
         r"\documentclass[10pt]{article}",
-        r"\usepackage[margin=0.75in]{geometry}",
+        r"\usepackage[margin=0.65in]{geometry}",
         r"\usepackage[T1]{fontenc}",
         r"\usepackage[scaled=0.95]{helvet}",
         r"\usepackage{microtype}",
@@ -151,29 +151,41 @@ def _booklet_latex(data: Dict[str, Any]) -> str:
         r"\setlength{\parskip}{4pt}",
         r"\setlength{\parindent}{0pt}",
         r"\setlist[itemize]{leftmargin=*,itemsep=2pt,topsep=2pt}",
+        r"\usepackage{xcolor}",
+        r"\usepackage{fancyhdr}",
+        r"\pagestyle{fancy}",
+        r"\fancyhf{}",
+        r"\fancyhead[L]{ALAN}",
+        r"\fancyhead[R]{"
+        + (r"\texttt{" + "; ".join(safe_bits) + r"}" if header_line else "")
+        + r"}",
+        r"\fancyfoot[R]{\thepage}",
         r"\begin{document}",
-        r"\section*{Alan's Language Aptitude iNstrument (ALAN)}",
+        r"\begin{center}",
+        r"{\Large\bfseries Alan's Language Aptitude iNstrument (ALAN)}\\[4pt]",
+        (header_line if header_line else ""),
+        r"\rule{0.9\linewidth}{0.4pt}",
+        r"\end{center}",
     ]
-    if header_line:
-        lines.append(header_line)
     if meta.get("instructions"):
-        lines.append(_tex_escape(meta["instructions"]))
+        lines.append(r"{\color{gray}" + _tex_escape(meta["instructions"]) + r"}")
     if meta.get("rules"):
-        lines.append(r"\subsection*{Grammar Cheat Sheet}")
-        lines.append(r"\begin{itemize}")
+        lines.append(r"\subsection*{\color{gray}Grammar Cheat Sheet}")
+        lines.append(r"\begin{itemize}[leftmargin=1em]")
         for rule in meta["rules"]:
             lines.append(rf"\item {_tex_escape(rule)}")
         lines.append(r"\end{itemize}")
     dict_data = meta.get("dictionary", {})
     if dict_data:
-        lines.append(r"\subsection*{Starter Dictionary}")
+        lines.append(r"\vspace{4pt}\rule{0.9\linewidth}{0.2pt}")
+        lines.append(r"\subsection*{\color{gray}Starter Dictionary}")
         for title, group in [
             ("Nouns", dict_data.get("nouns", {})),
             ("Verbs", dict_data.get("verbs", {})),
             ("Adjectives", dict_data.get("adjectives", {})),
         ]:
             lines.append(rf"\paragraph*{{{_tex_escape(title)}}}")
-            lines.append(r"\begin{itemize}")
+            lines.append(r"\begin{itemize}[leftmargin=1em]")
             for eng, lang in group.items():
                 lines.append(rf"\item {_tex_escape(eng)} = {_tex_escape(lang)}")
             lines.append(r"\end{itemize}")
@@ -187,12 +199,13 @@ def _booklet_latex(data: Dict[str, Any]) -> str:
         lines.append(r"")
         lines.append(r"")
         for q in section.get("questions", []):
-            lines.append(r"\needspace{12\baselineskip}")
-            lines.append(rf"\noindent\textbf{{{q['number']}. {_tex_escape(q['stem'])}}}")
-            lines.append(r"\begin{itemize}[leftmargin=1.25em]")
+            lines.append(r"\needspace{14\baselineskip}")
+            lines.append(rf"\noindent\textbf{{{q['number']}.}} {_tex_escape(q['stem'])}")
+            lines.append(r"\begin{itemize}[leftmargin=1.5em]")
             for opt in q.get("options", []):
                 lines.append(rf"\item[{_tex_escape(opt['label'])})] {_tex_escape(opt['text'])}")
             lines.append(r"\end{itemize}")
+            lines.append(r"\vspace{4pt}")
     lines.append(r"\end{document}")
     return "\n".join(lines)
 
@@ -200,16 +213,22 @@ def _booklet_latex(data: Dict[str, Any]) -> str:
 def _key_latex(data: Dict[str, Any]) -> str:
     lines = [
         r"\documentclass[10pt]{article}",
-        r"\usepackage[margin=0.75in]{geometry}",
+        r"\usepackage[margin=0.65in]{geometry}",
         r"\usepackage[T1]{fontenc}",
         r"\usepackage[scaled=0.95]{helvet}",
         r"\usepackage{microtype}",
         r"\usepackage{enumitem}",
         r"\usepackage{needspace}",
+        r"\usepackage{xcolor}",
+        r"\usepackage{fancyhdr}",
         r"\renewcommand{\familydefault}{\sfdefault}",
         r"\setlength{\parskip}{4pt}",
         r"\setlength{\parindent}{0pt}",
         r"\setlist[itemize]{leftmargin=*,itemsep=2pt,topsep=2pt}",
+        r"\pagestyle{fancy}",
+        r"\fancyhf{}",
+        r"\fancyhead[L]{ALAN}",
+        r"\fancyfoot[R]{\thepage}",
         r"\begin{document}",
         r"\section*{Answer Key}",
     ]
@@ -267,6 +286,11 @@ def main() -> None:
     args = parse_args()
     with open(args.in_path, "r", encoding="utf-8") as f:
         data = json.load(f)
+    run_dir = data.get("meta", {}).get("run_dir")
+    if args.test_pdf is None and run_dir:
+        args.test_pdf = os.path.join(run_dir, "test_booklet.pdf")
+    if args.key_pdf is None and run_dir:
+        args.key_pdf = os.path.join(run_dir, "answer_key.pdf")
     booklet_text = render_booklet(data)
     key_text = render_key(data)
     with open(args.test_out, "w", encoding="utf-8") as f:
@@ -277,7 +301,6 @@ def main() -> None:
         _write_pdf(_booklet_latex(data), args.test_pdf)
     if args.key_pdf:
         _write_pdf(_key_latex(data), args.key_pdf)
-    run_dir = data.get("meta", {}).get("run_dir")
     if run_dir and os.path.isdir(run_dir):
         for src in [args.test_out, args.key_out, args.test_pdf, args.key_pdf]:
             if not src:
@@ -285,6 +308,8 @@ def main() -> None:
             if not os.path.exists(src):
                 continue
             dest = os.path.join(run_dir, os.path.basename(src))
+            if os.path.abspath(dest) == os.path.abspath(src):
+                continue
             try:
                 shutil.copyfile(src, dest)
             except OSError: