From 9cbdf00666af2d820f55f6b087d96f122d54da60 Mon Sep 17 00:00:00 2001 From: Pavitra Pinninti <115882827+PavitraPi@users.noreply.github.com> Date: Sun, 16 Nov 2025 17:48:12 +0530 Subject: [PATCH 1/2] added typ code for hanoi and coin change --- algorithms/coinChange.typ | 119 ++++++++++++++++++++++++++++++++ algorithms/hanoi.typ | 138 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 algorithms/coinChange.typ create mode 100644 algorithms/hanoi.typ diff --git a/algorithms/coinChange.typ b/algorithms/coinChange.typ new file mode 100644 index 0000000..0922150 --- /dev/null +++ b/algorithms/coinChange.typ @@ -0,0 +1,119 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Coin Change + +#set math.equation(numbering: none) + +Given coins of denominations $c_1, c_2, ..., c_k$ and target amount $n$, find the minimum number of coins needed to make that amount. + +Recursive definition: +$ +"coinChange"(n, C) = cases( + 0 & "if " n = 0, + infinity & "if " n < 0, + min_(c in C) (1 + "coinChange"(n - c, C)) & "otherwise" +) +$ + +*As map code:* +$ +I & = NN times "Set"[NN] \ +X_(n,C) & = {0..n} -> NN_bot \ +A & = NN union {infinity} \ +rho(n,C) & = { i -> bot | i in {0..n} } \ +F(x_i) & = cases( + 0 & "if " i = 0, + min{1 + x_(i-c) | c in C, i >= c, x_(i-c) != bot} & "if " i > 0 "and" exists c in C : x_(i-c) != bot, + infinity & "otherwise" + ) \ +pi_(n,C) (x) & = x_n +$ + +#let inst_amount = 11; +#let inst_coins = (1, 3, 4); + +#figure( + caption: [Coin exchange for amount $#inst_amount$ with coins $#inst_coins$], +$#{ + let rho = ((amount, coins)) => { + let state = (:) + for i in range(0, amount + 1) { + state.insert(str(i), none) + } + state + } + + let F_i = (x, coins) => (state_key) => { + let val = x.at(state_key) + if val != none { return val } + + let amount = int(state_key) + + if amount == 0 { + return 0 + } + + let min_coins = none + for coin in coins { + if amount >= coin { + let sub_key = str(amount - coin) + let sub_val = x.at(sub_key, default: none) + if sub_val != none { + let curr = 1 + sub_val + if min_coins == none or curr < min_coins { + min_coins = curr + } + } + } + } + + return min_coins + } + + let F = (x, coins) => { + let x_new = (:) + for (key, val) in x { + x_new.insert(key, F_i(x, coins)(key)) + } + x_new + } + + let pi = ((amount, coins)) => (x) => { + x.at(str(amount), default: none) + } + + let x_h(x, diff_mask:none) = { + set text(size: 8pt) + let rows = () + let sorted_keys = x.keys().sorted(key: k => int(k)) + for key in sorted_keys { + let val = x.at(key) + let display = if val == none { + bot + } else { + str(val) + } + let is_changed = if diff_mask != none and type(diff_mask) == dictionary { + diff_mask.at(key, default: false) + } else { + false + } + + if is_changed { + rows.push(rect(fill: yellow.transparentize(70%), inset: 2pt, width: 100%)[amt=#key: #display]) + } else { + rows.push([amt=#key: #display]) + } + } + stack(dir: ttb, spacing: 3pt, ..rows) + } + + mapcode-viz( + rho, (x) => F(x, inst_coins), pi((inst_amount, inst_coins)), + X_h: x_h, + pi_name: [$mpi ((#inst_amount, #inst_coins))$], + group-size: 4, + cell-size: 40mm, scale-fig: 75% + )((inst_amount, inst_coins)) +}$) \ No newline at end of file diff --git a/algorithms/hanoi.typ b/algorithms/hanoi.typ new file mode 100644 index 0000000..d73589a --- /dev/null +++ b/algorithms/hanoi.typ @@ -0,0 +1,138 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Tower of Hanoi + +#set math.equation(numbering: none) + +The Tower of Hanoi puzzle: move $n$ disks from source rod $s$ to destination rod $d$ using auxiliary rod $a$, where larger disks cannot be placed on smaller ones. + +Recursive definition: +$ +"Hanoi"(n, s, d, a) = cases( + ["Move disk 1 from " s " to " d] & "if " n = 1, + "Hanoi"(n-1, s, a, d) + ["Move disk " n " from " s " to " d] + "Hanoi"(n-1, a, d, s) & "otherwise" +) +$ + +*As map code:* + +$ +I & = n:NN times s:"Rod" times d:"Rod" times a:"Rod" \ +X_(n,s,d,a) & = {1..n} times "Rod"^3 -> "List"["Move"]_bot \ +A & = "List"["Move"] \ +rho(n,s,d,a) & = { (i,p_1,p_2,p_3) -> bot | i in {1..n}, (p_1,p_2,p_3) in "perm"({s,d,a}) } \ +F(x_(i,p_1,p_2,p_3)) & = cases( + ["Move disk 1 from " p_1 " to " p_2] & "if " i = 1, + x_(i-1,p_1,p_3,p_2) + ["Move disk " i " from " p_1 " to " p_2] + x_(i-1,p_3,p_2,p_1) & "if" x_(i-1,p_1,p_3,p_2) != bot "and" x_(i-1,p_3,p_2,p_1) != bot + ) \ +pi_(n,s,d,a) (x) & = x_(n,s,d,a) +$ + +#let inst_n_hanoi = 3; +#let inst_src = "A"; +#let inst_dest = "C"; +#let inst_aux = "B"; + +#figure( + caption: [Tower of Hanoi for $n = #inst_n_hanoi$ disks from #inst_src to #inst_dest using auxiliary #inst_aux], +$#{ + let rho = ((n, src, dest, aux)) => { + let rods = (src, dest, aux) + let perms = ( + (src, dest, aux), (src, aux, dest), + (dest, src, aux), (dest, aux, src), + (aux, src, dest), (aux, dest, src) + ) + let state = (:) + for i in range(1, n + 1) { + for perm in perms { + let key = str(i) + "-" + perm.at(0) + perm.at(1) + perm.at(2) + state.insert(key, none) + } + } + state + } + + let F_i = (x) => (state_key) => { + let val = x.at(state_key) + if val != none { return val } + + let parts = state_key.split("-") + let n = int(parts.at(0)) + let rods_str = parts.at(1) + let s = rods_str.at(0) + let d = rods_str.at(1) + let a = rods_str.at(2) + + if n == 1 { + return ("Move disk 1 from " + s + " to " + d,) + } + + let key1 = str(n - 1) + "-" + s + a + d + let key2 = str(n - 1) + "-" + a + d + s + + let part1 = x.at(key1, default: none) + let part2 = x.at(key2, default: none) + + if part1 != none and part2 != none { + let middle = ("Move disk " + str(n) + " from " + s + " to " + d,) + return part1 + middle + part2 + } + + return none + } + + let F = (x) => { + let x_new = (:) + for (key, val) in x { + x_new.insert(key, F_i(x)(key)) + } + x_new + } + + let pi = ((n, src, dest, aux)) => (x) => { + let key = str(n) + "-" + src + dest + aux + x.at(key, default: none) + } + + let x_h(x, diff_mask:none) = { + set text(size: 7pt) + let rows = () + let sorted_keys = x.keys().sorted() + for key in sorted_keys { + let val = x.at(key) + let display = if val == none { + bot + } else { + let moves_text = val.slice(0, calc.min(2, val.len())).join("; ") + if val.len() > 2 { + moves_text = moves_text + "; ..." + } + [#moves_text] + } + let is_changed = if diff_mask != none and type(diff_mask) == dictionary { + diff_mask.at(key, default: false) + } else { + false + } + + if is_changed { + rows.push(rect(fill: yellow.transparentize(70%), inset: 2pt, width: 100%)[#key: #display]) + } else { + rows.push([#key: #display]) + } + } + stack(dir: ttb, spacing: 3pt, ..rows) + } + + mapcode-viz( + rho, F, pi((inst_n_hanoi, inst_src, inst_dest, inst_aux)), + X_h: x_h, + pi_name: [$mpi ((#inst_n_hanoi, #inst_src, #inst_dest, #inst_aux))$], + group-size: 2, + cell-size: 45mm, scale-fig: 70% + )((inst_n_hanoi, inst_src, inst_dest, inst_aux)) +}$) + +#pagebreak() \ No newline at end of file From 59e61ab95148d02993e939850efabbfb5c598ff7 Mon Sep 17 00:00:00 2001 From: Pavitra Pinninti <115882827+PavitraPi@users.noreply.github.com> Date: Sun, 16 Nov 2025 17:48:46 +0530 Subject: [PATCH 2/2] edited main.typ to include hanoi and coin change --- main.typ | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.typ b/main.typ index 9952d9b..26d25a4 100644 --- a/main.typ +++ b/main.typ @@ -48,6 +48,10 @@ All primitives are _strict_ meaning they do not allow for undefined values (i.e. #include "algorithms/fibonacci.typ" #pagebreak() #include "algorithms/BinomialCoefficients.typ" +#include "algorithms/hanoi.typ" +#pagebreak() +#include "algorithms/coinChange.typ" +#pagebreak() #pagebreak() #include "algorithms/LongestCommonSubsequence.typ" #pagebreak()