From 350675907d948449129d814c5f8bdc5c0310f27e Mon Sep 17 00:00:00 2001 From: mark Date: Wed, 22 Jan 2025 21:13:02 -0800 Subject: [PATCH] q --- lib/typst/local/handout/0.1.0/handout.typ | 280 ++++++++++++++++++++ lib/typst/local/handout/0.1.0/typst.toml | 6 + src/Warm-Ups/A Familiar Concept/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/A Familiar Concept/main.tex | 35 --- src/Warm-Ups/A Familiar Concept/main.typ | 39 +++ src/Warm-Ups/Fuse Timers/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/Fuse Timers/main.tex | 31 --- src/Warm-Ups/Fuse Timers/main.typ | 21 ++ src/Warm-Ups/Mario Kart/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/Mario Kart/main.tex | 54 ---- src/Warm-Ups/Mario Kart/main.typ | 41 +++ src/Warm-Ups/Odd Dice/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/Odd Dice/main.tex | 132 --------- src/Warm-Ups/Odd Dice/main.typ | 87 ++++++ src/Warm-Ups/Partition Products/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/Partition Products/main.tex | 57 ---- src/Warm-Ups/Partition Products/main.typ | 47 ++++ src/Warm-Ups/Prime Factors/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/Prime Factors/main.tex | 34 --- src/Warm-Ups/Prime Factors/main.typ | 29 ++ src/Warm-Ups/Regex/main.tex | 153 ----------- src/Warm-Ups/Regex/main.typ | 138 ++++++++++ src/Warm-Ups/Travellers/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/Travellers/main.tex | 30 --- src/Warm-Ups/Travellers/main.typ | 26 ++ src/Warm-Ups/fmod/handout.typ | 280 ++++++++++++++++++++ src/Warm-Ups/fmod/main.tex | 22 -- src/Warm-Ups/fmod/main.typ | 16 ++ tools/scripts/build.py | 11 +- 29 files changed, 2979 insertions(+), 550 deletions(-) create mode 100755 lib/typst/local/handout/0.1.0/handout.typ create mode 100644 lib/typst/local/handout/0.1.0/typst.toml create mode 100755 src/Warm-Ups/A Familiar Concept/handout.typ delete mode 100755 src/Warm-Ups/A Familiar Concept/main.tex create mode 100644 src/Warm-Ups/A Familiar Concept/main.typ create mode 100755 src/Warm-Ups/Fuse Timers/handout.typ delete mode 100755 src/Warm-Ups/Fuse Timers/main.tex create mode 100644 src/Warm-Ups/Fuse Timers/main.typ create mode 100755 src/Warm-Ups/Mario Kart/handout.typ delete mode 100755 src/Warm-Ups/Mario Kart/main.tex create mode 100644 src/Warm-Ups/Mario Kart/main.typ create mode 100755 src/Warm-Ups/Odd Dice/handout.typ delete mode 100755 src/Warm-Ups/Odd Dice/main.tex create mode 100644 src/Warm-Ups/Odd Dice/main.typ create mode 100755 src/Warm-Ups/Partition Products/handout.typ delete mode 100755 src/Warm-Ups/Partition Products/main.tex create mode 100644 src/Warm-Ups/Partition Products/main.typ create mode 100755 src/Warm-Ups/Prime Factors/handout.typ delete mode 100755 src/Warm-Ups/Prime Factors/main.tex create mode 100644 src/Warm-Ups/Prime Factors/main.typ delete mode 100644 src/Warm-Ups/Regex/main.tex create mode 100644 src/Warm-Ups/Regex/main.typ create mode 100755 src/Warm-Ups/Travellers/handout.typ delete mode 100755 src/Warm-Ups/Travellers/main.tex create mode 100644 src/Warm-Ups/Travellers/main.typ create mode 100755 src/Warm-Ups/fmod/handout.typ delete mode 100755 src/Warm-Ups/fmod/main.tex create mode 100644 src/Warm-Ups/fmod/main.typ diff --git a/lib/typst/local/handout/0.1.0/handout.typ b/lib/typst/local/handout/0.1.0/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/lib/typst/local/handout/0.1.0/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/lib/typst/local/handout/0.1.0/typst.toml b/lib/typst/local/handout/0.1.0/typst.toml new file mode 100644 index 0000000..ed110b7 --- /dev/null +++ b/lib/typst/local/handout/0.1.0/typst.toml @@ -0,0 +1,6 @@ +[package] +name = "handout" +version = "0.1.0" +entrypoint = "handout.typ" +authors = [] +license = "GPL" \ No newline at end of file diff --git a/src/Warm-Ups/A Familiar Concept/handout.typ b/src/Warm-Ups/A Familiar Concept/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/A Familiar Concept/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/A Familiar Concept/main.tex b/src/Warm-Ups/A Familiar Concept/main.tex deleted file mode 100755 index 8a754d3..0000000 --- a/src/Warm-Ups/A Familiar Concept/main.tex +++ /dev/null @@ -1,35 +0,0 @@ -\documentclass[ - solutions, - hidewarning, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - - -\title{Warm-Up: A Familiar Concept} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today} - - -\begin{document} - - \maketitle - - - \problem{} - Let $v = [-5, -2, 0, 1, 4, 1000]$. Find all $x$ that minimize the following metric. \par - $$ - \sum_{\forall i} |v_i - x| = |v_1 - x| + |v_2 - x| + ... + |v_6 - x| - $$ - \vfill - - \problem{} - Let $v = [-5, -2, 0, 1, 4, 1000, 1001]$. Find all $x$ that minimize the metric in \ref{one}. - \vfill - - \problem{} - What is this metric usually called? - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/A Familiar Concept/main.typ b/src/Warm-Ups/A Familiar Concept/main.typ new file mode 100644 index 0000000..eee7119 --- /dev/null +++ b/src/Warm-Ups/A Familiar Concept/main.typ @@ -0,0 +1,39 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: A Familiar Concept], + by: "Mark", +) + +#problem() +Let $v = [-5, -2, 0, 1, 4, 1000]$. Find all $x$ that minimize the following metric: + +#align( + center, + box( + inset: 3mm, + $ + sum_(#sym.forall i) |v_i - x| = |v_1 - x| + |v_2 - x| + ... + |v_6 - x| +$, + ), + ) + +#v(1fr) + +#problem() +Let $v = [-5, -2, 0, 1, 4, 1000, 1001]$. Find all $x$ that minimize the metric in the previous problem. + +#v(1fr) + + +#problem() +What is this metric usually called? + + +#v(0.25fr) diff --git a/src/Warm-Ups/Fuse Timers/handout.typ b/src/Warm-Ups/Fuse Timers/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/Fuse Timers/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/Fuse Timers/main.tex b/src/Warm-Ups/Fuse Timers/main.tex deleted file mode 100755 index b0c5d1a..0000000 --- a/src/Warm-Ups/Fuse Timers/main.tex +++ /dev/null @@ -1,31 +0,0 @@ -\documentclass[ - solutions, - hidewarning, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - - -\title{Warm-Up: Fuse Timers} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today.} - -\begin{document} - - \maketitle - - - \problem{} - Suppose we have two strings and a lighter. Each string takes an hour to fully burn. \par - However, we do not know how fast each part of the string burns: - half might burn in 1 minute, and the rest could take 59. - - \vspace{2mm} - - How would we measure exactly 45 minutes using these strings? - - \vfill - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Fuse Timers/main.typ b/src/Warm-Ups/Fuse Timers/main.typ new file mode 100644 index 0000000..dc53b09 --- /dev/null +++ b/src/Warm-Ups/Fuse Timers/main.typ @@ -0,0 +1,21 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: Fuse Timers], + by: "Mark", +) + +#problem() +Suppose we have two strings and a lighter. Each string takes exactly an hour to fully burn. \ +However, we do not know how fast each part of the string burns: +half might burn in 1 minute, and the rest could take 59. + +#v(2mm) + +How can we measure exactly 45 minutes using these two strings? \ No newline at end of file diff --git a/src/Warm-Ups/Mario Kart/handout.typ b/src/Warm-Ups/Mario Kart/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/Mario Kart/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/Mario Kart/main.tex b/src/Warm-Ups/Mario Kart/main.tex deleted file mode 100755 index f5af8a0..0000000 --- a/src/Warm-Ups/Mario Kart/main.tex +++ /dev/null @@ -1,54 +0,0 @@ -\documentclass[ - solutions, - hidewarning, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - -\title{Warm-Up: Mario Kart} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today} - - -\begin{document} - - \maketitle - - \problem{} - A standard Mario Kart cup consists of 12 players and four races. \par - Each race is scored as follows: - \begin{itemize} - \item 15 points are awarded for first place; - \item 12 for second; - \item and $(13 - \text{place})$ otherwise. - \end{itemize} - In any one race, no players may tie. - A player's score at the end of a cup is the sum of their scores for each of the four races. - - \vspace{2mm} - - An $n$-way tie occurs when the top $n$ players have the same score at the end of a round. \par - What is the largest possible $n$, and how is it achieved? - - \begin{solution} - A 12-way tie is impossible, since the total number of point is not divisible by 12. - - \vspace{2mm} - - A 11-way tie is possible, with a top score of 28: - \begin{itemize} - \item Four players finish $1^\text{st}$, $3^\text{ed}$, $11^\text{th}$, and $12^\text{th}$; - - % spell:off - \item Four players finish $2^\text{nd}$, $4^\text{th}$, $9^\text{th}$, and $10^\text{th}$; - % spell:on - - \item Two players finish fifth twice and seventh twice, - \item One player finishes sixth in each race. - \end{itemize} - The final player always finishes eighth, with a non-tie score of 20. - \end{solution} - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Mario Kart/main.typ b/src/Warm-Ups/Mario Kart/main.typ new file mode 100644 index 0000000..e09a064 --- /dev/null +++ b/src/Warm-Ups/Mario Kart/main.typ @@ -0,0 +1,41 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: Mario Kart], + by: "Mark", +) + +#problem() +A standard Mario Kart cup consists of 12 players and four races. \ +Each race is scored as follows: +- 15 points are awarded for first place; +- 12 for second; +- and $(13 - #text("place"))$ otherwise. + +In any one race, no players may tie. \ +A player's score at the end of a cup is the sum of their scores for each of the four races. + +#v(2mm) + +An $n$-way tie occurs when the top $n$ players have the same score at the end of a round. \ +What is the largest possible $n$, and how is it achieved? + +#solution([ + A 12-way tie is impossible, since the total number of point is not divisible by 12. + + #v(2mm) + + A 11-way tie is possible, with a top score of 28: + - Four players finish $1^#text("st")$, $3^#text("ed")$, $11^#text("th")$, and $12^#text("th")$; + - Four players finish $2^#text("nd")$, $4^#text("th")$, $9^#text("th")$, and $10^#text("th")$; + - Two players finish fifth twice and seventh twice, + - One player finishes sixth in each race. + The final player always finishes eighth, with a non-tie score of 20. + +]) diff --git a/src/Warm-Ups/Odd Dice/handout.typ b/src/Warm-Ups/Odd Dice/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/Odd Dice/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/Odd Dice/main.tex b/src/Warm-Ups/Odd Dice/main.tex deleted file mode 100755 index 270936d..0000000 --- a/src/Warm-Ups/Odd Dice/main.tex +++ /dev/null @@ -1,132 +0,0 @@ -\documentclass[ - nosolutions, - hidewarning, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - - -\usepackage{tikz} -\usetikzlibrary{arrows.meta} -\usetikzlibrary{shapes.geometric} - -% We put nodes in a separate layer, so we can -% slightly overlap with paths for a perfect fit -\pgfdeclarelayer{nodes} -\pgfdeclarelayer{path} -\pgfsetlayers{main,nodes} - -% Layer settings -\tikzset{ - % Layer hack, lets us write - % later = * in scopes. - layer/.style = { - execute at begin scope={\pgfonlayer{#1}}, - execute at end scope={\endpgfonlayer} - }, - % - % Arrowhead tweak - >={Latex[ width=2mm, length=2mm ]}, - % - % Nodes - main/.style = { - draw, - circle, - fill = white, - line width = 0.35mm - } -} - -\title{Warm Up: Odd Dice} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today} - - -\begin{document} - - \maketitle - - \problem{} - - We say a set of dice $\{A, B, C\}$ is \textit{nontransitive} - if, on average, $A$ beats $B$, $B$ beats $C$, and $C$ beats $A$. - In other words, we get a counterintuitive \say{rock - paper - scissors} effect. - - \vspace{2mm} - - Create a set of nontransitive six-sided dice. \par - \hint{All sides should be numbered with positive integers less than 10.} - - \begin{solution} - One possible set can be numbered as follows: - \begin{itemize} - \item Die $A$: $2, 2, 4, 4, 9, 9$ - \item Die $B$: $1, 1, 6, 6, 8, 8$ - \item Die $C$: $3, 3, 5, 5, 7, 7$ - \end{itemize} - - \vspace{4mm} - - Another solution is below: - \begin{itemize} - \item Die $A$: $3, 3, 3, 3, 3, 6$ - \item Die $B$: $2, 2, 2, 5, 5, 5$ - \item Die $C$: $1, 4, 4, 4, 4, 4$ - \end{itemize} - \end{solution} - - \vfill - - \problem{} - Now, consider the set of six-sided dice below: - \begin{itemize} - \item Die $A$: $4, 4, 4, 4, 4, 9$ - \item Die $B$: $3, 3, 3, 3, 8, 8$ - \item Die $C$: $2, 2, 2, 7, 7, 7$ - \item Die $D$: $1, 1, 6, 6, 6, 6$ - \item Die $E$: $0, 5, 5, 5, 5, 5$ - \end{itemize} - On average, which die beats each of the others? Draw a graph. \par - - \begin{solution} - \begin{center} - \begin{tikzpicture}[scale = 0.5] - \begin{scope}[layer = nodes] - \node[main] (a) at (-2, 0.2) {$a$}; - \node[main] (b) at (0, 2) {$b$}; - \node[main] (c) at (2, 0.2) {$c$}; - \node[main] (d) at (1, -2) {$d$}; - \node[main] (e) at (-1, -2) {$e$}; - \end{scope} - - \draw[->] - (a) edge (b) - (b) edge (c) - (c) edge (d) - (d) edge (e) - (e) edge (a) - - (a) edge (c) - (b) edge (d) - (c) edge (e) - (d) edge (a) - (e) edge (b) - ; - \end{tikzpicture} - \end{center} - \end{solution} - - \vfill - - Now, say we roll each die twice. What happens to the graph above? - - \begin{solution} - The direction of each edge is reversed! - \end{solution} - - \vfill - \pagebreak - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Odd Dice/main.typ b/src/Warm-Ups/Odd Dice/main.typ new file mode 100644 index 0000000..626425c --- /dev/null +++ b/src/Warm-Ups/Odd Dice/main.typ @@ -0,0 +1,87 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: Odd Dice], + by: "Mark", +) + +#problem() +We say a set of dice ${A, B, C}$ is _nontransitive_ +if, on average, $A$ beats $B$, $B$ beats $C$, and $C$ beats $A$. +In other words, we get a counterintuitive "rock - paper - scissors" effect. + +#v(2mm) + +Create a set of nontransitive six-sided dice. \ +#hint([All sides should be numbered with positive integers less than 10.]) + +#solution([ + One possible set can be numbered as follows: + - Die $A$: $2, 2, 4, 4, 9, 9$ + - Die $B$: $1, 1, 6, 6, 8, 8$ + - Die $C$: $3, 3, 5, 5, 7, 7$ + + #v(4mm) + + Another solution is below: + - Die $A$: $3, 3, 3, 3, 3, 6$ + - Die $B$: $2, 2, 2, 5, 5, 5$ + - Die $C$: $1, 4, 4, 4, 4, 4$ + +]) + +#v(1fr) + +#problem() +Now, consider the set of six-sided dice below: +- Die $A$: $4, 4, 4, 4, 4, 9$ +- Die $B$: $3, 3, 3, 3, 8, 8$ +- Die $C$: $2, 2, 2, 7, 7, 7$ +- Die $D$: $1, 1, 6, 6, 6, 6$ +- Die $E$: $0, 5, 5, 5, 5, 5$ +On average, which die beats each of the others? Draw a diagram. + +#solution([ +/* + \begin{tikzpicture}[scale = 0.5] + \begin{scope}[layer = nodes] + \node[main] (a) at (-2, 0.2) {$a$}; + \node[main] (b) at (0, 2) {$b$}; + \node[main] (c) at (2, 0.2) {$c$}; + \node[main] (d) at (1, -2) {$d$}; + \node[main] (e) at (-1, -2) {$e$}; + \end{scope} + + \draw[->] + (a) edge (b) + (b) edge (c) + (c) edge (d) + (d) edge (e) + (e) edge (a) + + (a) edge (c) + (b) edge (d) + (c) edge (e) + (d) edge (a) + (e) edge (b) + ; + \end{tikzpicture} + */ +]) + +#v(1fr) + +#problem() +Now, say we roll each die twice. What happens to the graph fromE the previous problem? + +#solution([ + The direction of each edge is reversed! +]) + +#v(1fr) \ No newline at end of file diff --git a/src/Warm-Ups/Partition Products/handout.typ b/src/Warm-Ups/Partition Products/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/Partition Products/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/Partition Products/main.tex b/src/Warm-Ups/Partition Products/main.tex deleted file mode 100755 index a440b7e..0000000 --- a/src/Warm-Ups/Partition Products/main.tex +++ /dev/null @@ -1,57 +0,0 @@ -\documentclass[ - solutions, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - -\title{Warm-Up: Partition Products} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today.} - -\begin{document} - - \maketitle - - \problem{} - Take any positive integer $n$. \par - Now, write it as sum of smaller positive integers: $n = a_1 + a_2 + ... + a_k$ \par - Maximize the product $a_1 \times a_2 \times ... \times a_k$ - - - - \begin{solution} - - \textbf{Interesting Solution:} - - Of course, all $a_i$ should be greater than $1$. \par - Also, all $a_i$ should be smaller than four, since $x \leq x(x-2)$ if $x \geq 4$. \par - Thus, we're left with sequences that only contain 2 and 3. \par - \note{Note that two twos are the same as one four, but we exclude fours for simplicity.} - - \vspace{2mm} - - Finally, we see that $3^2 > 2^3$, so any three twos are better repackaged as two threes. \par - The best sequence $a_i$ thus consists of a maximal number of threes followed by 0, 1, or 2 twos. - - \linehack{} - - - - \textbf{Calculus Solution:} - - First, solve this problem for equal, non-integer $a_i$: - - \vspace{2mm} - - We know $n = \prod{a_i}$, thus $\ln(n) = \sum{\ln(a_i)}$. \par - If all $a_i$ are equal, we get $\ln(n) = k \times \ln(n / k)$. \par - Derive wrt $k$ and set to zero to get $\ln(n / k) = 1$ \par - So $k = n / e$ and $n / k = e \approx 2.7$ - - \vspace{2mm} - - If we try to approximate this with integers, we get the same solution as above. - \end{solution} -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Partition Products/main.typ b/src/Warm-Ups/Partition Products/main.typ new file mode 100644 index 0000000..fbeadc5 --- /dev/null +++ b/src/Warm-Ups/Partition Products/main.typ @@ -0,0 +1,47 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: Partition Products], + by: "Mark", +) + +#problem() +Take any positive integer $n$. \ +Now, write it as sum of smaller positive integers: $n = a_1 + a_2 + ... a_k$ \ +Maximize the product $a_1 #sym.times a_2 #sym.times ... #sym.times a_k$ + + +#solution([ + *Interesting Solution:* + + Of course, all $a_i$ should be greater than $1$. \ + Also, all $a_i$ should be smaller than four, since $x <= x(x-2)$ if $x >= 4$. \ + Thus, we're left with sequences that only contain 2 and 3. \ + #note([Note that two twos are the same as one four, but we exclude fours for simplicity.]) + + #v(2mm) + + Finally, we see that $3^2 > 2^3$, so any three twos are better repackaged as two threes. \ + The best sequence $a_i$ thus consists of a maximal number of threes followed by 0, 1, or 2 twos. + + #v(8mm) + + *Calculus Solution:* + + First, solve this problem for equal, real $a_i$: + #v(2mm) + We know $n = product(a_i)$, thus $ln(n) = sum(ln(a_i))$. \ + If all $a_i$ are equal, we get $ln(n) = k #sym.times ln(n / k)$. \ + Derive wrt $k$ and set to zero to get $ln(n / k) = 1$ \ + So $k = n / e$ and $n / k = e #sym.approx 2.7$ + + #v(2mm) + + If we try to approximate this with integers, we get the same solution as above. +]) \ No newline at end of file diff --git a/src/Warm-Ups/Prime Factors/handout.typ b/src/Warm-Ups/Prime Factors/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/Prime Factors/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/Prime Factors/main.tex b/src/Warm-Ups/Prime Factors/main.tex deleted file mode 100755 index 4f5a400..0000000 --- a/src/Warm-Ups/Prime Factors/main.tex +++ /dev/null @@ -1,34 +0,0 @@ -\documentclass[ - solutions, - singlenumbering, - nopagenumber, - hidewarning -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - -\title{Warm-Up: Prime Factors} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today.} - -\begin{document} - - \maketitle - - \problem{} - What proportion of integers have $2$ as their smallest prime factor? - % 1^2 - \vfill - - - \problem{} - What proportion of integers have $3$ as their second-smallest prime factor? - % 1/6 - \vfill - - - \problem{} - What is the median second-smallest prime factor? - % 37 - \vfill - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Prime Factors/main.typ b/src/Warm-Ups/Prime Factors/main.typ new file mode 100644 index 0000000..0218485 --- /dev/null +++ b/src/Warm-Ups/Prime Factors/main.typ @@ -0,0 +1,29 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: Prime Factors], + by: "Mark", +) + +#problem() +What proportion of integers have $2$ as their smallest prime factor? +#solution([$1 div 2$]) +#v(1fr) + + +#problem() +What proportion of integers have $3$ as their second-smallest prime factor? +#solution([$1 div 6$]) +#v(1fr) + + +#problem() +What is the median second-smallest prime factor? +#solution([37]) +#v(1fr) \ No newline at end of file diff --git a/src/Warm-Ups/Regex/main.tex b/src/Warm-Ups/Regex/main.tex deleted file mode 100644 index a8f48e7..0000000 --- a/src/Warm-Ups/Regex/main.tex +++ /dev/null @@ -1,153 +0,0 @@ -\documentclass[ - solutions, - hidewarning, -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - -\usepackage{xcolor} -\usepackage{soul} -\usepackage{hyperref} - -\definecolor{Light}{gray}{.90} -\sethlcolor{Light} -\newcommand{\htexttt}[1]{\texttt{\hl{#1}}} - - -\title{The Regex Warm-Up} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today} - -\begin{document} - - \maketitle - - - Last time, we discussed Deterministic Finite Automata. One interesting application of these mathematical objects is found in computer science: Regular Expressions. \par - This is often abbreviated \say{regex}, which is pronounced like \say{gif.} - - \vspace{2mm} - - Regex is a language used to specify patterns in a string. You can think of it as a concise way to define a DFA, using text instead of a huge graph. \par - - Often enough, a clever regex pattern can do the work of a few hundred lines of code. - - \vspace{2mm} - - Like the DFAs we've studied, a regex pattern \textit{accepts} or \textit{rejects} a string. However, we don't usually use this terminology with regex, and instead say that a string \textit{matches} or \textit{doesn't match} a pattern. - - \vspace{5mm} - - Regex strings consist of characters, quantifiers, sets, and groups. - - \vspace{5mm} - - \textbf{Quantifiers} \par - Quantifiers specify how many of a character to match. \par - There are four of these: \htexttt{+}, \htexttt{*}, \htexttt{?}, and \htexttt{\{ \}} - - \vspace{2mm} - - \htexttt{+} means \say{match one or more of the preceding token} \par - \htexttt{*} means \say{match zero or more of the preceding token} - - For example, the pattern \htexttt{ca+t} will match the following strings: - \begin{itemize} - \item \texttt{cat} - \item \texttt{caat} - \item \texttt{caaaaaaaat} - \end{itemize} - \htexttt{ca+t} will \textbf{not} match the string \texttt{ct}. \par - The pattern \htexttt{ca*t} will match all the strings above, including \texttt{ct}. - \vspace{2mm} - - - \htexttt{?} means \say{match one or none of the preceding token} \par - The pattern \htexttt{linea?r} will match only \texttt{linear} and \texttt{liner}. - \vspace{2mm} - - Brackets \htexttt{\{min, max\}} are the most flexible quantifier. \par - They specify exactly how many tokens to match: \par - \htexttt{ab\{2\}a} will match only \texttt{abba}. \par - \htexttt{ab\{1,3\}a} will match only \texttt{aba}, \texttt{abba}, and \texttt{abbba}. \par - % spell:off - \htexttt{ab\{2,\}a} will match any \texttt{ab...ba} with at least two \texttt{b}s. - % spell:on - - \vspace{5mm} - - \problem{} - Write the patterns \htexttt{a*} and \htexttt{a+} using only \htexttt{\{ \}}. - \vfill - - \problem{} - Draw a DFA equivalent to the regex pattern \htexttt{01*0}. - \vfill - - \pagebreak - - - - - - - \textbf{Characters, Sets, and Groups} \par - In the previous section, we saw how we can specify characters literally: \par - \texttt{a+} means \say{one or more \texttt{a} character} - - \vspace{2mm} - - There are, of course, other ways we can specify characters. - - \vspace{2mm} - - The first such way is the \textit{set}, denoted \htexttt{[ ]}. A set can pretend to be any character inside it. \par - For example, \htexttt{m[aoy]th} will match \texttt{math}, \texttt{moth}, or \texttt{myth}. \par - \htexttt{a[01]+b} will match \texttt{a0b}, \texttt{a111b}, \texttt{a1100110b}, and any other similar string. \par - You may negate a set with a \htexttt{\textasciicircum}. \par - \htexttt{[\textasciicircum abc]} will match any character except \texttt{a}, \texttt{b}, or \texttt{c}, including symbols and spaces. - - \vspace{2mm} - - If we want to keep characters together, we can use the \textit{group}, denoted \htexttt{( )}. \par - - Groups work exactly as you'd expect, representing an atomic\footnotemark{} group of characters. \par - \htexttt{a(01)+b} will match \texttt{a01b} and \texttt{a010101b}, but will \textbf{not} match \texttt{a0b}, \texttt{a1b}, or \texttt{a1100110b}. - - \footnotetext{In other words, \say{unbreakable}} - - - \problem{} - You are now familiar with most of the tools regex has to offer. \par - Write patterns that match the following strings: - \begin{enumerate}[itemsep=1mm] - \item An ISO-8601 date, like \texttt{2022-10-29}. \par - \hint{Invalid dates like \texttt{2022-13-29} should also be matched.} - - \item An email address. \par - \hint{Don't forget about subdomains, like \texttt{math.ucla.edu}.} - - \item A UCLA room number, like \texttt{MS 5118} or \texttt{Kinsey 1220B}. - - \item Any ISBN-10 of the form \texttt{0-316-00395-7}. \par - \hint{Remember that the check digit may be an \texttt{X}. Dashes are optional.} - - \item A word of even length. \par - \hint{The set \texttt{[A-z]} contains every english letter, capitalized and lowercase. \\ - \texttt{[a-z]} will only match lowercase letters.} - - \item A word with exactly 3 vowels. \par - \hint{The special token \texttt{\textbackslash w} will match any word character. It is equivalent to \texttt{[A-z0-9\_]} \\ \texttt{\_} stands for a literal underscore.} - - \item A word that has even length and exactly 3 vowels. - - \item A sentence that does not start with a capital letter. - \end{enumerate} - - \vfill - - \problem{} - If you'd like to know more, check out \url{https://regexr.com}. It offers an interactive regex prompt, as well as a cheatsheet that explains every other regex token there is. \par - You will find a nice set of challenges at \url{https://alf.nu/RegexGolf}. - I especially encourage you to look into this if you are interested in computer science. -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Regex/main.typ b/src/Warm-Ups/Regex/main.typ new file mode 100644 index 0000000..74b2a77 --- /dev/null +++ b/src/Warm-Ups/Regex/main.typ @@ -0,0 +1,138 @@ +#import "@local/handout:0.1.0": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [The Regex Warm-Up], + by: "Mark", +) + + +Last time, we discussed Deterministic Finite Automata. One interesting application of these mathematical objects is found in computer science: Regular Expressions. \ +This is often abbreviated "regex," which is pronounced like "gif." + +#v(2mm) + +Regex is a language used to specify patterns in a string. You can think of it as a concise way to define a DFA, using text instead of a huge graph. \ + +Often enough, a clever regex pattern can do the work of a few hundred lines of code. + +#v(2mm) + +Like the DFAs we've studied, a regex pattern _accepts_ or _rejects_ a string. However, we don't usually use this terminology with regex, and instead say that a string _matches_ or _doesn't match_ a pattern. + +#v(5mm) + +Regex strings consist of characters, quantifiers, sets, and groups. + +#v(5mm) + + + +*Quantifiers* \ +Quantifiers specify how many of a character to match. \ +There are four of these: `+`, `*`, `?`, and `{ }`. + +#v(4mm) + +`+` means "match one or more of the preceding token" \ +`*` means "match zero or more of the preceding token" + +For example, the pattern `ca+t` will match the following strings: +- `cat` +- `caat` +- `caaaaaaaat` +`ca+t` will *not* match the string `ct`. \ +The pattern `ca*t` will match all the strings above, including `ct`. + + +#v(4mm) + + +`?` means "match one or none of the preceding token" \ +The pattern `linea?r` will match only `linear` and `liner`. + +#v(4mm) + +Brackets `{min, max}` are the most flexible quantifier. \ +They specify exactly how many tokens to match: \ +`ab{2}a` will match only `abba`. \ +`ab{1,3}a` will match only `aba`, `abba`, and `abbba`. \ +`ab{2,}a` will match any `ab...ba` with at least two `b`s. + +#problem() +Write the patterns `a*` and `a+` using only `{ }`. +#v(1fr) + +#problem() +Draw a DFA equivalent to the regex pattern `01*0`. +#v(1fr) + +#pagebreak() + + + + + + +*Characters, Sets, and Groups* \ +In the previous section, we saw how we can specify characters literally: \ +`a+` means "one or more `a` characters" \ +There are, of course, other ways we can specify characters. + +#v(4mm) + +The first such way is the _set_, denoted `[ ]`. A set can pretend to be any character inside it. \ +For example, `m[aoy]th` will match `math`, `moth`, or `myth`. \ +`a[01]+b` will match `a0b`, `a111b`, `a1100110b`, and any other similar string. \ + +#v(4mm) + +We can negate a set with a `^`. \ +`[^abc]` will match any single character except `a`, `b`, or `c`, including symbols and spaces. + +#v(4mm) + +If we want to keep characters together, we can use the _group_, denoted `( )`. \ + +Groups work exactly as you'd expect, representing an atomic#footnote([In other words, "unbreakable"]) group of characters. \ +`a(01)+b` will match `a01b` and `a010101b`, but will *not* match `a0b`, `a1b`, or `a1100110b`. + +#problem() +You are now familiar with most of the tools regex has to offer. \ +Write patterns that match the following strings: + +- An ISO-8601 date, like `2022-10-29`. \ + #hint([Invalid dates like `2022-13-29` should also be matched.]) + +- An email address. \ + #hint([Don't forget about subdomains, like `math.ucla.edu`.]) + +- A UCLA room number, like `MS 5118` or `Kinsey 1220B`. + +- Any ISBN-10 of the form `0-316-00395-7`. \ + #hint([Remember that the check digit may be an `X`. Dashes are optional.]) + +- A word of even length. \ + #hint([The set `[A-z]` contains every english letter, capitalized and lowercase. \ + `[a-z]` will only match lowercase letters.]) + +- A word with exactly 3 vowels. \ + #hint([The special token `\w` will match any word character. \ + It is equivalent to `[A-z0-9_]`. `_` represents a literal underscore. +]) + +- A word that has even length and exactly 3 vowels. + +- A sentence that does not start with a capital letter. +#v(1fr) + +#problem() +If you'd like to know more, check out `https://regexr.com`. +It offers an interactive regex prompt, +as well as a cheatsheet that explains every other regex token there is. \ +You can find a nice set of challenges at `https://alf.nu/RegexGolf`. diff --git a/src/Warm-Ups/Travellers/handout.typ b/src/Warm-Ups/Travellers/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/Travellers/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/Travellers/main.tex b/src/Warm-Ups/Travellers/main.tex deleted file mode 100755 index cc38713..0000000 --- a/src/Warm-Ups/Travellers/main.tex +++ /dev/null @@ -1,30 +0,0 @@ -\documentclass[ - solutions, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - -\title{Warm-Up: Travellers} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today} - -\begin{document} - - \maketitle - - \problem{} - Four travellers are on a plane, each moving along a straight line at an arbitrary constant speed. \par - No two of their paths are parallel, and no three intersect at the same point. \par - We know that traveller A has met travelers B, C, and D, \par - and that traveller B has met C and D (and A). Show that C and D must also have met. \par - - \begin{solution} - When a body travels at a constant speed, its graph with respect to time is a straight line. \par - So, we add time axis in the third dimension, perpendicular to our plane. \par - Naturally, the projection of each of these onto the plane corresponds to a road. - - Now, note that two intersecting lines define a plane and use the conditions in the problem to show that no two lines are parallel. - \end{solution} - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/Travellers/main.typ b/src/Warm-Ups/Travellers/main.typ new file mode 100644 index 0000000..7074959 --- /dev/null +++ b/src/Warm-Ups/Travellers/main.typ @@ -0,0 +1,26 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: Travellers], + by: "Mark", +) + +#problem() +Four travellers are on a plane, each moving along a straight line at an arbitrary constant speed. \ +No two of their paths are parallel, and no three intersect at the same point. \ +We know that traveller A has met travelers B, C, and D, \ +and that traveller B has met C and D (and A). Show that C and D must also have met. + +#solution([ + When a body travels at a constant speed, its graph with respect to time is a straight line. \ + So, we add time axis in the third dimension, perpendicular to our plane. \ + Naturally, the projection of each of these onto the plane corresponds to a road. + + Now, note that two intersecting lines define a plane and use the conditions in the problem to show that no two lines are parallel. +]) \ No newline at end of file diff --git a/src/Warm-Ups/fmod/handout.typ b/src/Warm-Ups/fmod/handout.typ new file mode 100755 index 0000000..90313ca --- /dev/null +++ b/src/Warm-Ups/fmod/handout.typ @@ -0,0 +1,280 @@ + +/// If false, hide instructor info. +/// +/// Compile with the following command to hide solutions: +/// `typst compile main.typ --input show_solutions=false` +/// +/// Solutions are shown by default. This behavior +/// is less surprising than hiding content by default. +#let show_solutions = { + if "show_solutions" in sys.inputs { + // Show solutions unless they're explicitly disabled + not ( + sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" + ) + } else { + // Show solutions by default + true + } +} + +// Colors +#let ored = rgb("D62121") +#let ogrape = rgb("9C36B5") +#let ocyan = rgb("2288BF") +#let oteal = rgb("12B886") +#let ogreen = rgb("37B26D") +#let oblue = rgb("1C7ED6") + + + +// +// MARK: header +// + +#let make_title( + group, + quarter, + title, + subtitle, +) = { + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + align( + center, + stack( + spacing: 7pt, + ( + text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) + ), + line(length: 100%, stroke: 0.2mm), + ( + text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) + ), + line(length: 100%, stroke: 0.2mm), + ), + ), + ), + ) +} + +#let warn = { + set text(ored) + align( + center, + block( + width: 60%, + height: auto, + breakable: false, + fill: rgb(255, 255, 255), + stroke: ored + 2pt, + inset: 3mm, + ( + align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) + + parbreak() + + align( + left, + text( + size: 10pt, + [This handout contains solutions and notes.] + + linebreak() + + [Recompile without solutions before distributing.], + ), + ) + ), + ), + ) +} + +#let preparedby(name) = ( + text( + size: 10pt, + [Prepared by ] + + name + + [ on ] + + datetime + .today() + .display("[month repr:long] [day padding:none], [year]"), + ) +) + +// +// MARK: Solutions +// + +#let solution(content) = { + if show_solutions { + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: ored, + stroke: ored + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: ored.lighten(80%).desaturate(10%), + stroke: ored + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) + } +} + +#let notsolution(content) = { + if not show_solutions { content } +} + + +// +// MARK: Sections +// + +#let generic(t) = block( + above: 8mm, + below: 2mm, + text(weight: "bold", t), +) + +#let _generic_base(kind, ..args) = { + counter("obj").step() + if args.pos().len() == 0 { + generic([ + #kind + #context counter("obj").display(): + ]) + } else { + generic( + [ + #kind + #context counter("obj").display(): + ] + + " " + + args.pos().at(0), + ) + } +} + +#let problem(..args) = _generic_base("Problem", ..args) +#let definition(..args) = _generic_base("Definition", ..args) +#let theorem(..args) = _generic_base("Theorem", ..args) + + +// +// MARK: Misc +// + + +#let hint(content) = { + text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ") + text(fill: rgb(100, 100, 100), content) +} + +#let note(content) = { + text(fill: rgb(100, 100, 100), content) +} + +#let examplesolution(content) = { + let c = oblue + + align( + center, + stack( + block( + width: 100%, + breakable: false, + fill: c, + stroke: c + 2pt, + inset: 1.5mm, + ( + align(left, text(fill: white, weight: "bold", [Example solution:])) + ), + ), + block( + width: 100%, + height: auto, + breakable: false, + fill: c.lighten(80%).desaturate(10%), + stroke: c + 2pt, + inset: 3mm, + align(left, content), + ), + ), + ) +} + + +// +// MARK: wrapper +// + +#let handout( + doc, + group: none, + quarter: none, + title: none, + by: none, + subtitle: none, +) = { + set par(leading: 0.55em, first-line-indent: 0mm, justify: true) + set text(font: "New Computer Modern") + set par(spacing: 0.5em) + show list: set block(spacing: 0.5em, below: 1em) + set heading(numbering: (..nums) => nums.pos().at(0)) + + set page( + margin: 20mm, + width: 8in, + height: 11.5in, + footer: align( + center, + context counter(page).display(), + ), + footer-descent: 5mm, + ) + + + set list( + tight: false, + indent: 5mm, + spacing: 3mm, + ) + + show heading.where(level: 1): it => { + set align(center) + set text(weight: "bold") + block[ + Section #counter(heading).display(): #text(it.body) + ] + } + + make_title( + group, + quarter, + title, + { + if by == none { none } else { [#preparedby(by)\ ] } + if subtitle == none { none } else { subtitle } + }, + ) + + if show_solutions { + warn + } + doc +} + diff --git a/src/Warm-Ups/fmod/main.tex b/src/Warm-Ups/fmod/main.tex deleted file mode 100755 index 693d94e..0000000 --- a/src/Warm-Ups/fmod/main.tex +++ /dev/null @@ -1,22 +0,0 @@ -\documentclass[ - solutions, - hidewarning, - singlenumbering, - nopagenumber -]{../../../lib/tex/ormc_handout} -\usepackage{../../../lib/tex/macros} - - -\title{Warm-Up: \texttt{fmod}} -\uptitler{\smallurl{}} -\subtitle{Prepared by Mark on \today.} - -\begin{document} - - \maketitle - - \problem{} - I'm sure you're all familiar with how \texttt{mod(a, b)} and \texttt{remainder(a, b)} work with integers. \par - Devise an equivalent for floats (i.e, real numbers). - -\end{document} \ No newline at end of file diff --git a/src/Warm-Ups/fmod/main.typ b/src/Warm-Ups/fmod/main.typ new file mode 100644 index 0000000..de3937b --- /dev/null +++ b/src/Warm-Ups/fmod/main.typ @@ -0,0 +1,16 @@ +#import "./handout.typ": * + +#show: doc => handout( + doc, + quarter: link( + "https://betalupi.com/handouts", + "betalupi.com/handouts", + ), + + title: [Warm-Up: `fmod`], + by: "Mark", +) + +#problem() +I'm sure you're all familiar with how `mod(a, b)` and `remainder(a, b)` \ work when `a` and `b` are integers. +Devise an equivalent for floats (i.e, real numbers). diff --git a/tools/scripts/build.py b/tools/scripts/build.py index 5dcc981..e62020a 100644 --- a/tools/scripts/build.py +++ b/tools/scripts/build.py @@ -139,14 +139,18 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None: out = OUT_DIR / out_subdir out.mkdir(parents=True, exist_ok=True) + + res = subprocess.run( [ TYPST_PATH, "compile", + "--package-path", + f"{ROOT}/lib/typst", "--ignore-system-fonts", - "main.typ", "--input", "show_solutions=false", + "main.typ", f"{out}/{handout_file}", ], cwd=source_dir, @@ -164,6 +168,8 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None: [ TYPST_PATH, "compile", + "--package-path", + f"{ROOT}/lib/typst", "--ignore-system-fonts", "main.typ", f"{out}/{solutions_file}", @@ -268,7 +274,8 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None: # # This method does _not_ recurse into subdirectories. def build_dir(base: str, out_sub: str, index: list[IndexEntry]): - builders = [build_typst, build_xetex] + #builders = [build_typst, build_xetex] + builders = [build_typst] for d_str in os.listdir(base): d = base / Path(d_str)