From 5db28fa5058a5d942b2baab525e4c709c6bb51d8 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:06:57 +0700 Subject: [PATCH 01/30] Create lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/preview/v-exam/0.1.0/lib.typ diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -0,0 +1 @@ + From 4a0da82b4dc7804326130177a34c7c286c0ec215 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:07:49 +0700 Subject: [PATCH 02/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 1350 +++++++++++++++++++++++++ 1 file changed, 1350 insertions(+) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 8b13789179..bacb9125a4 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -1 +1,1351 @@ +#import "@preview/cetz:0.5.2" +#import "@preview/rustycure:0.2.0": qr-code +// ========================================== +// 1. CÀI ĐẶT CHUNG & BẢNG MÀU THIẾT LẬP +// ========================================== +#let toan-setup(body, math-color: black, math-size: 1.2em, nmsize: 1em) = { + show math.frac: it => { + set text(fill: math-color, size: math-size) + math.display(it) + } + show math.equation: it => { + set text(size: nmsize) + it + } + show list: it => { + let any-frac = it.children.any(item => { + let r = repr(item.body) + r.contains("frac") and not r.contains("list(") + }) + if any-frac { + set list(spacing: 1.1em) + it + } else { it } + } + body +} + +#let mausac = ( + lg : rgb("#a8f6f13c"), + duong: rgb("#0057b8"), + cau_pa: rgb("#1505f2"), + daT: rgb("#f3072a") +) + +#let to-abc(idx) = ("A", "B", "C", "D").at(idx) +#let to-ds(arr) = { + let res = "" + for v in arr { if v == 1 { res += "Đ" } else { res += "S" } } + res +} + +// ========================================== +// 2. THUẬT TOÁN BĂM & XÁO TRỘN ĐỀ +// ========================================== +#let ham-bam(index, seed) = { + let h = index * 1664525 + seed * 1013904223 + h = calc.rem(h, 4294967296) + h = calc.rem(h * 279470273, 4294967296) + return h +} + +#let tron-mang(arr, seed) = { + if arr.len() <= 1 { return arr } + let pairs = arr.enumerate().map((pair) => { + let (i, item) = pair + (ham-bam(i, seed), item) + }) + let n = pairs.len() + let sorted-pairs = () + let remaining = pairs + + for i in range(n) { + let min-idx = 0 + for j in range(1, remaining.len()) { + if remaining.at(j).at(0) < remaining.at(min-idx).at(0) { + min-idx = j + } + } + sorted-pairs.push(remaining.at(min-idx)) + remaining = remaining.slice(0, min-idx) + remaining.slice(min-idx + 1) + } + return sorted-pairs.map(p => p.at(1)) +} + +#let tron-mang-theo-lv(arr, seed) = { + if arr.len() <= 1 { return arr } + let get-lv(item) = item.at("lv", default: 1) + + let nhom1 = arr.filter(q => get-lv(q) == 1) + let nhom2 = arr.filter(q => get-lv(q) == 2) + let nhom3 = arr.filter(q => get-lv(q) == 3) + let nhom_khac = arr.filter(q => { + let lv = get-lv(q) + lv != 1 and lv != 2 and lv != 3 + }) + + return tron-mang(nhom1, seed + 11) + tron-mang(nhom2, seed + 22) + tron-mang(nhom3, seed + 33) + tron-mang(nhom_khac, seed + 44) +} + +#let xao-theo-tuy-chon(arr, seed, theo_lv: false) = { + if theo_lv { + tron-mang-theo-lv(arr, seed) + } else { + tron-mang(arr, seed) + } +} + +// ========================================== +// 3. HÀM TẠO QR & HIỂN THỊ LỜI GIẢI +// ========================================== +#let tao-QRcode-key(results) = { + let all_content = "" + for entry in results { + let ma_de = str(entry.value.seed) + let part1 = entry.value.part1.join("") + let part2 = entry.value.part2.join("") + let part3 = entry.value.part3.map(str).join("|") + all_content += ma_de + "\n" + part1 + "\n" + part2 + "\n" + part3 + "\n" + } + return all_content +} + +#let hienthi-lg(q, q_type, idx, seed, opt_indices: none, tf_indices: none) = { + toan-setup({ + v(-0.4em) + block( + width: 100%, + inset: (y: 0.5em, x: 0.5em, left: 8pt, right: 8pt), + fill: mausac.lg, + radius: (right: 4pt), + stroke: (left: 2pt + mausac.duong) + )[ + #v(0.2em) + #if q_type == "NLC" { + let correct_idx = if opt_indices != none { opt_indices.position(i => i == q.da) } else { q.da } + text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #to-abc(correct_idx)*\ ] + text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[*Lời giải:*] + } else if q_type == "TF" or q_type == "tf" { + let correct_ans = if tf_indices != none { to-ds(tf_indices.map(i => q.da.at(i))) } else { to-ds(q.da) } + text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #correct_ans*\ ] + text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[ *Lời giải:*] + } else if q_type == "TLN" { + text(fill: blue.darken(100%), size: 11pt)[*Kết quả: #q.da*] + text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[\ *Lời giải:*] + } else if q_type == "TL" { + text(fill: red.darken(0%), weight: "bold", font: "UTM A&S Graceland", size: 16pt)[*Lời giải:*] + } + + #if (q_type == "TF" or q_type == "tf") and type(q.lg) == array { + let indices = if tf_indices != none { tf_indices } else { range(q.lg.len()) } + let labels = ("a)", "b)", "c)", "d)") + + list( + marker: none, + spacing: 0.7em, + ..indices.enumerate().map(((new_i, orig_i)) => { + let is_true = q.da.at(orig_i) == 1 + let status_str = if is_true { "Đúng" } else { "Sai" } + let lg_content = if orig_i < q.lg.len() { q.lg.at(orig_i) } else { [] } + + [#text(fill: mausac.cau_pa, weight: "bold")[#labels.at(new_i) - #status_str:] #text(fill: blue.darken(100%), style: "italic")[#lg_content]] + }) + ) + } else { + text(fill: blue.darken(100%), style: "italic")[#q.lg] + } + ] + v(-0.1em) + }) +} + +// ========================================== +// 4. BÀI TẬP INLINE / ÔN TẬP TÀI LIỆU +// ========================================== +#let render_sub_sol(q, type_str, show_lg) = { + if not show_lg { return } + v(-0.8em) + block( + width: 100%, + stroke: (left: 2.5pt + mausac.duong), + fill: mausac.lg, + inset: (x: 10pt, y: 8pt), + radius: (right: 4pt), + breakable: true + )[ + #set par(leading: 0.65em) + #if type_str == "NLC" [ + #text(fill: mausac.duong, weight: "bold")[► Lời giải: \ ] + #if "lg" in q and q.lg != none and q.lg != [] [ #q.lg ] else [ Chưa có lời giải.] + ] + #if type_str == "TF" [ + #text(fill: mausac.duong, weight: "bold")[► Đáp án:] #text(fill: mausac.daT, weight: "bold")[#to-ds(q.da)] \ + #if "lg" in q and q.lg != none and q.lg != [] [ + #if type(q.lg) == array [ + #let labels = ("a)", "b)", "c)", "d)") + #list( + marker: none, + spacing: 0.7em, + ..q.lg.enumerate().map(((i, lg_item)) => { + let is_true = q.da.at(i) == 1 + let status_str = if is_true { "Đúng" } else { "Sai" } + [#text(fill: mausac.cau_pa, weight: "bold")[#labels.at(i) #status_str]\ #lg_item] + }) + ) + ] else [ + #q.lg + ] + ] else [ Chưa có lời giải.] + ] + #if type_str == "TLN" [ + #text(fill: mausac.duong, weight: "bold")[► Kết quả:] #text(fill: mausac.daT, weight: "bold")[#q.da] \ + #if "lg" in q and q.lg != none and q.lg != [] [ #v(0.01em)#q.lg #v(0.2em)] else [ Chưa có lời giải.] + ] + #if type_str == "TL" [ + #text(fill: mausac.duong, weight: "bold")[► Lời giải chi tiết:] \ + #if "lg" in q and q.lg != none and q.lg != [] [ #q.lg ] else [ Chưa có lời giải.] + ] + ] +} + +#let baitap_inline( + cm: 1, + bank_data, + title: none, + seed: 0, + num_nlc: none, + num_tf: none, + num_tln: none, + num_tl: none, + show_lg: false, + dong_ke: none, + co_NLC: none, + co_tf: none, + co_TLN: none, + co_TL: none, + theo_lv: false, +) = { + let cfg_nlc = if num_nlc != none { num_nlc } else { co_NLC } + let cfg_tf = if num_tf != none { num_tf } else { co_tf } + let cfg_tln = if num_tln != none { num_tln } else { co_TLN } + let cfg_tl = if num_tl != none { num_tl } else { co_TL } + + let actual_bank = if type(bank_data) == dictionary and "data" in bank_data { + bank_data.data + } else if type(bank_data) == module { + bank_data.data + } else { + bank_data + } + + let std_bank = actual_bank.map(q => { + if "cau_hoi_con" in q and type(q.cau_hoi_con) == array and q.cau_hoi_con.len() > 0 { + let is_c = q.at("is_chum", default: q.cau_hoi_con.len() > 1) + let dk = q.at("du_kien", default: none) + let q_type = q.at("type", default: q.cau_hoi_con.at(0).at("type", default: "NLC")) + let q_lv = q.at("lv", default: 1) + ( + type: q_type, + lv: q_lv, + is_chum: is_c, + du_kien: dk, + cau_hoi_con: q.cau_hoi_con + ) + } else { + ( + type: q.at("type", default: "NLC"), + lv: q.at("lv", default: 1), + is_chum: false, + du_kien: none, + cau_hoi_con: (q,) + ) + } + }) + + let rut_cau(q_type, dem_config, sub_seed) = { + let loc_ques = std_bank.filter(q => q.type == q_type) + if loc_ques.len() == 0 or dem_config == none or dem_config == 0 { return () } + + let get_q_lv(item) = { + if "lv" in item { item.lv } + else if item.cau_hoi_con.len() > 0 and "lv" in item.cau_hoi_con.at(0) { item.cau_hoi_con.at(0).lv } + else { 1 } + } + + if type(dem_config) == int { + let processing = if seed == none { loc_ques } else { xao-theo-tuy-chon(loc_ques, seed + sub_seed, theo_lv: theo_lv) } + return processing.slice(0, calc.min(dem_config, processing.len())) + } + + if type(dem_config) == array { + let nb_req = dem_config.at(0, default: 0) + let th_req = dem_config.at(1, default: 0) + let vd_req = dem_config.at(2, default: 0) + + let b_nb = loc_ques.filter(q => get_q_lv(q) == 1) + let b_th = loc_ques.filter(q => get_q_lv(q) == 2) + let b_vd = loc_ques.filter(q => get_q_lv(q) == 3) + + if seed != none { + b_nb = tron-mang(b_nb, seed + sub_seed + 11) + b_th = tron-mang(b_th, seed + sub_seed + 22) + b_vd = tron-mang(b_vd, seed + sub_seed + 33) + } + + let res_nb = b_nb.slice(0, calc.min(nb_req, b_nb.len())) + let res_th = b_th.slice(0, calc.min(th_req, b_th.len())) + let res_vd = b_vd.slice(0, calc.min(vd_req, b_vd.len())) + + return res_nb + res_th + res_vd + } + + return loc_ques + } + + let ds_NLC = rut_cau("NLC", cfg_nlc, 107) + let ds_TF = rut_cau("TF", cfg_tf, 233) + let ds_TLN = rut_cau("TLN", cfg_tln, 357) + let ds_TL = rut_cau("TL", cfg_tl, 491) + + toan-setup({ + if title != none and title != "" { + v(0.5em) + align(center)[#text(fill: mausac.duong, weight: "bold", size: 13pt)[#title]] + v(0.3em) + } + + // PHẦN I: NLC + if ds_NLC.len() > 0 { + set par(first-line-indent: 0pt) + v(-0.5em) + if cm == 1 { + text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẮC NGHIỆM NHIỀU LỰA CHỌN] + } + let c_idx = 0 + for item in ds_NLC { + if item.du_kien != none and item.du_kien != [] { + let n_sub = item.cau_hoi_con.len() + let start_c = c_idx + 1 + let end_c = c_idx + n_sub + block(width: 100%, breakable: false)[ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau_pa, weight: "bold")[Dữ kiện dùng cho từ Câu #start_c đến Câu #end_c:] \ + #v(0.1em) #item.du_kien + ] + ] + } + + for q in item.cau_hoi_con { + c_idx += 1 + v(-0.4em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, + gutter: 3pt, + row-gutter: 8pt, + align: (left + top, center + top), + [ + #v(-0.4em) + #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd \ + #v(-0.3em) + + #let is_img_option = q.pa.any(opt => { + let r = repr(opt) + r.contains("image(") or r.contains("cetz") or r.contains("canvas") + }) + + #if is_img_option [ + #let n_cols = if "cot" in q { q.cot } else { 4 } + #grid( + columns: (1fr,) * n_cols, + column-gutter: 0.8em, + row-gutter: 0.5em, + align: center + horizon, + ..q.pa.enumerate().map(((i, v)) => { + let is_correct = show_lg and ("da" in q) and (i == q.da) + let label_text = [#h(1em)*#to-abc(i).*] + let formatted_label = if is_correct { underline(text(fill: mausac.daT, weight: "bold")[#label_text]) } else { text(fill: mausac.cau_pa)[#label_text] } + align(left)[#grid(columns:(auto,1fr), column-gutter:10pt, [#formatted_label], [#v])] + }) + ) + ] else [ + #let n_cols = if "cot" in q { q.cot } else { 4 } + #grid( + columns: (1fr,) * n_cols, + row-gutter: 0.95em, + column-gutter: 0.1em, + align: if n_cols > 1 { left + horizon } else { left }, + inset: (x: 1em), + ..q.pa.enumerate().map(((i, v)) => { + let is_correct = show_lg and ("da" in q) and (i == q.da) + let label_text = [*#to-abc(i).*] + let formatted_label = if is_correct { underline(text(fill: mausac.daT, weight: "bold")[#label_text]) } else { text(fill: mausac.cau_pa)[#label_text] } + box[#grid(columns: (auto, 1fr), gutter: 2pt, align: left, formatted_label, v)] + }) + ) #v(0.5em) + ] + ], + if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } ] + ) + ] + v(-0.7em) + render_sub_sol(q, "NLC", show_lg) + } + } + } + + // PHẦN II: TF + if ds_TF.len() > 0 { + set par(first-line-indent: 0pt) + v(-0.1em) + if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } + let c_idx = 0 + for item in ds_TF { + if item.du_kien != none and item.du_kien != [] { + let n_sub = item.cau_hoi_con.len() + let start_c = c_idx + 1 + let end_c = c_idx + n_sub + block(width: 100%, breakable: false)[ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau_pa, weight: "bold")[Dữ kiện dùng cho Câu #start_c đến Câu #end_c:] \ + #v(0.1em) #item.du_kien + ] + ] + } + for q in item.cau_hoi_con { + c_idx += 1 + v(-0.6em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, + gutter: 10pt, + align: (left + top, center + top), + [ + #v(0.2em) + #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd \ + #list( + marker: none, + spacing: 0.7em, + ..q.ytf.enumerate().map(((i, sq)) => { + let label_text = [#("a)", "b)", "c)", "d)").at(i)] + let formatted_label = text(fill: mausac.cau_pa, weight: "bold")[#h(0.5em) #label_text] + let ans_str = if show_lg and ("da" in q) and type(q.da) == array and i < q.da.len() { + if q.da.at(i) == 1 { " [Đúng]" } else { " [Sai]" } + } else { "" } + [#formatted_label #sq #text(fill: mausac.daT, weight: "bold")[#ans_str]] + }) + ) + ], + if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } ] + ) + ] + v(-0.8em) + render_sub_sol(q, "TF", show_lg) + } + } + } + + // PHẦN III: TLN + if ds_TLN.len() > 0 { + set par(first-line-indent: 0pt) + v(-0.5em) + if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } + let c_idx = 0 + for item in ds_TLN { + if item.du_kien != none and item.du_kien != [] { + let n_sub = item.cau_hoi_con.len() + let start_c = c_idx + 1 + let end_c = c_idx + n_sub + block(width: 100%, breakable: false)[ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau_pa, weight: "bold", style: "italic")[Dữ kiện dùng cho Câu #start_c đến Câu #end_c:] \ + #v(0.1em) #text(style: "italic")[#item.du_kien] + ] + ] + } + for q in item.cau_hoi_con { + c_idx += 1 + v(-0.8em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, + gutter: 10pt, + row-gutter: 10pt, + align: (left + top, center + horizon), + [ + #v(-0.1em) + #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd + #v(0.1em) + #if not show_lg [ + #grid( + columns: (auto, auto), + column-gutter: 8pt, + align: horizon, + [*Trả lời:*], + [#(for i in range(4) { box(width: 1.2em, height: 1.2em, stroke: 0.4pt + gray.darken(80%), radius: 1pt); h(2pt) })] + ) + #v(-0.4em) + #let num_lines = if dong_ke == none or dong_ke == 0 { none + } else if "dong_ke" in q and q.dong_ke != none { q.dong_ke + } else { dong_ke } + #if num_lines != none and type(num_lines) == int and num_lines > 0 { + v(0.3em) + for i in range(num_lines) { + v(0.4em) + line(length: 100%, stroke: (dash: "dotted", thickness: 0.75pt, paint: gray.darken(80%))) + } + } + ] + ], + if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(0.2em)] + ) + ] + v(-0.4em) + render_sub_sol(q, "TLN", show_lg) + } + } + } + + // PHẦN IV: TL + if ds_TL.len() > 0 { + set par(first-line-indent: 0pt) + v(-0.5em) + if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 11pt)[► BÀI TẬP TỰ LUẬN] } + let c_idx = 0 + for item in ds_TL { + for q in item.cau_hoi_con { + c_idx += 1 + v(-0.4em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, + gutter: 10pt, + align: (left + top, center + top), + [ + #v(-0.4em) + #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd + #v(0.5em) + ], + if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(1em)] + ) + #v(-0.8em) + #if not show_lg [ + #let num_lines = if dong_ke == none or dong_ke == 0 { none + } else if "dong_ke" in q and q.dong_ke != none { q.dong_ke + } else { dong_ke } + #if num_lines != none and type(num_lines) == int and num_lines > 0 { + v(0.3em) + for i in range(num_lines) { + v(0.15em) + line(length: 100%, stroke: (dash: "dotted", thickness: 0.75pt, paint: gray.darken(80%))) + v(0.35em) + } + } + ] + #v(0.4em) + ] + v(-0.8em) + render_sub_sol(q, "TL", show_lg) + } + } + } + }) +} + +// ========================================== +// 5. TRỘN ĐỀ THI +// ========================================== +#let render_test( + ma_de, + q_bank, + matrix, + info, + is_first: false, + show_lg: false, + tf_mode: "full", + nlc_mode: "full", + theo_lv: false, +) = { + if not is_first { + context { counter(page).update(1) } + } + + let seed = int(ma_de) + + let raw_NLC = q_bank.filter(matrix.NLC_loc) + let xao_NLC = xao-theo-tuy-chon(raw_NLC, seed + 107, theo_lv: theo_lv) + let NLC_dem = calc.min(matrix.NLC_dem, xao_NLC.len()) + let s_NLC = xao_NLC.slice(0, NLC_dem) + + let raw_tf = q_bank.filter(matrix.tf_loc) + let xao_tf = xao-theo-tuy-chon(raw_tf, seed + 233, theo_lv: theo_lv) + let tf_dem = calc.min(matrix.tf_dem, xao_tf.len()) + let s_tf = xao_tf.slice(0, tf_dem) + + let raw_TLN = q_bank.filter(matrix.TLN_loc) + let xao_TLN = xao-theo-tuy-chon(raw_TLN, seed + 357, theo_lv: theo_lv) + let TLN_dem = calc.min(matrix.TLN_dem, xao_TLN.len()) + let s_TLN = xao_TLN.slice(0, TLN_dem) + + let raw_TL = q_bank.filter(matrix.TL_loc) + let xao_TL = xao-theo-tuy-chon(raw_TL, seed + 491, theo_lv: theo_lv) + let TL_dem = calc.min(matrix.TL_dem, xao_TL.len()) + let s_TL = xao_TL.slice(0, TL_dem) + + let part1_ans = () + let part2_ans = () + let part3_ans = () + let part4_ans = () + + toan-setup({ + set page(paper: "a4", margin: 1.2cm, footer: context [ + #set text(size: 9pt); *#h(1fr) Trang #counter(page).display() - Mã đề #ma_de* + ]) + + grid( + columns: (1.2fr, 1fr), + gutter: 10pt, + align(center)[ + #text(size: 11pt)[#info.so_gd] \ + #text(size: 11pt)[#strong(info.truong)] \ + #v(-0.5em) + #line(length: 40%, stroke: 0.5pt) + ], + align(center)[ + #text(size: 11pt)[#strong(info.ky_thi)] \ + #text(size: 11pt)[Môn: #strong[#info.mon]] \ + #text(size: 10pt)[Thời gian: #emph[#info.thoi_gian]] + ] + ) + grid(columns: (1fr, auto), + [Họ tên: ..............................................................................\ + #v(0.1em) + Lớp: ................ + Số báo danh: ....................... + Phòng thi: ............], + box(stroke: 0.8pt + black, inset: (x: 6pt, y: 6pt))[#strong[Mã đề: #ma_de]] + ) + line(length: 100%, stroke: 0.5pt) + + if s_NLC.len() > 0 { + let tong_so_cau = s_NLC.fold(0, (acc, q) => { + if "is_chum" in q and q.is_chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } + }) + set par(first-line-indent: 0pt) + v(-0.1em) + text(fill: mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong_so_cau.* #emph[*Mỗi câu thí sinh chỉ được chọn một phương án.*]#v(0.2em)] + + let c_idx = 0 + for item in s_NLC { + let is_item_chum = "is_chum" in item and item.is_chum == true and "cau_hoi_con" in item + if is_item_chum { + let n_sub = item.cau_hoi_con.len() + let start_num = c_idx + 1 + let end_num = c_idx + n_sub + v(0.2em) + block(width: 100%, breakable: false)[ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau_pa)[*Dữ kiện dùng cho từ Câu #start_num đến Câu #end_num:*] \ + #v(0.1em) #item.du_kien + ] + ] + } + + let ds_cau_can_ve = if is_item_chum { item.cau_hoi_con } else { (item,) } + + for q in ds_cau_can_ve { + let opt_indices = if seed == 0 or nlc_mode == "none" { range(4) } else { tron-mang(range(4), seed + c_idx * 73) } + let new_opts = opt_indices.map(i => q.pa.at(i)) + part1_ans.push(to-abc(opt_indices.position(i => i == q.da))) + + v(-0.2em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, + gutter: 10pt, + align: (left + top, center + horizon), + [ + #v(-0.3em) + #text(fill: mausac.cau_pa)[*Câu #(c_idx + 1).*] #q.nd \ + #v(-0.3em) + #let is_img_option = new_opts.any(opt => { + let r = repr(opt) + r.contains("image(") or r.contains("cetz") or r.contains("canvas") + }) + #if is_img_option [ + #grid( + columns: (1fr, 1fr, 1fr, 1fr), + column-gutter: 0.8em, row-gutter: 0.5em, align: center + horizon, + ..new_opts.enumerate().map(((i, v)) => [#align(center)[#text(fill: mausac.cau_pa)[*#to-abc(i).*]) #v]]) + ) + ] else [ + #let n_cols = if "cot" in q { q.cot } else { 4 } + #grid( + columns: (1fr,) * n_cols, row-gutter: 0.6em, column-gutter: 1.2em, align: left + horizon, + ..new_opts.enumerate().map(((i, v)) => [#text(fill: mausac.cau_pa)[#h(1em)*#to-abc(i).*] #v]) + ) + ] + ], + if has_img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + ) + ] + v(-0.8em) + if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "NLC", c_idx, seed, opt_indices: opt_indices) } + v(-0.2em) + c_idx += 1 + } + } + } + + if s_tf.len() > 0 { + set par(first-line-indent: 0pt) + v(0.5em); text(mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #s_tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] + for (idx, q) in s_tf.enumerate() { + let sub_indices = if tf_mode == "none" { range(4) } + else if tf_mode == "y_only" { + let content_str = repr(q.nd) + repr(q.ytf) + let content_hash = calc.rem(content_str.len() * 265435761, 123456789) + tron-mang(range(4), content_hash * 31 + int(ma_de) * 7919) + } else { tron-mang(range(4), seed + idx * 109 + int(ma_de) * 10000) } + let new_subs = sub_indices.map(i => q.ytf.at(i)) + part2_ans.push(to-ds(sub_indices.map(i => q.da.at(i)))) + v(-0.3em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), + [ + #text(fill: mausac.cau_pa)[*Câu #(idx + 1).* ]#q.nd \ + #list(marker: none, spacing: 0.7em, ..new_subs.enumerate().map(((i, sq)) => [#h(0.5em) #text(fill: mausac.cau_pa)[#strong[#("a)", "b)", "c)", "d)").at(i)]] #sq])) + ], + if has_img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + ) + ] + v(-0.4em) + if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TF", idx + s_NLC.len(), seed, tf_indices: sub_indices) } + v(-0.3em) + } + } + + if s_TLN.len() > 0 { + let tong_so_cau = s_TLN.fold(0, (acc, q) => { + if "is_chum" in q and q.is_chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } + }) + set par(first-line-indent: 0pt) + v(0.5em); text(fill: mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong_so_cau.*] + let c_idx = 0 + for item in s_TLN { + let is_item_chum = "is_chum" in item and item.is_chum == true and "cau_hoi_con" in item + let ds_cau_can_ve = if is_item_chum { item.cau_hoi_con } else { (item,) } + + if is_item_chum { + let n_sub = item.cau_hoi_con.len() + let start_num = c_idx + 1 + let end_num = c_idx + n_sub + v(0.2em) + block(width: 100%, breakable: false)[ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau_pa)[*Dữ kiện dùng cho từ Câu #start_num đến Câu #end_num:*] \ + #v(0.1em) #item.du_kien + ] + ] + } + + for q in ds_cau_can_ve { + part3_ans.push(q.da) + v(-0.5em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), + [ + #text(fill: mausac.cau_pa)[*Câu #(c_idx + 1).* ]#q.nd + #if not show_lg [ + #v(-0.4em) + #pad(left: 0em)[ + #grid(columns: (auto, auto), column-gutter: 10pt, align: (left + horizon, left + horizon), [*Trả lời:*], [#(for i in range(4) { box(width: 1.2em, height: 1.2em, stroke: 0.3pt); h(3pt) })]) + ] + ] + ], + if has_img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + ) + ] + v(-1em) + if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TLN", c_idx + s_NLC.len() + s_tf.len(), seed) } + v(-0.2em) + c_idx += 1 + } + } + } + + if s_TL.len() > 0 { + set par(first-line-indent: 0pt) + v(0.3em); text(mausac.cau_pa)[*► TỰ LUẬN (#s_TL.len() câu)*] + v(-0.3em) + for (idx, q) in s_TL.enumerate() { + part4_ans.push((nd: q.nd, lg: q.lg)) + v(-0.3em) + block(width: 100%, inset: (y: 0.3em), breakable: true)[ + #let has_img = "hv" in q and q.hv != none and q.hv != "" + #grid( + columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + top), + [ #text(fill: mausac.cau_pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], + if has_img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + ) + #if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TL", idx, seed) } + #v(-0.3em) + ] + } + } + + align(center)[#text(size: 11pt)[#strong[---- hết ----]]] + }) + + [#metadata(( + seed: ma_de, + part1: part1_ans, + part2: part2_ans, + part3: part3_ans, + part4: part4_ans + )) ] +} + +#let in_dapan_TL(results) = { + context { + counter(page).update(1) + set page(footer: none) + } + toan-setup({ + align(center)[#text(20pt, weight: "bold")[HƯỚNG DẪN CHẤM TỰ LUẬN]] + v(-0.2em) + for entry in results { + let ma_de = str(entry.value.seed) + let lg_TL = entry.value.part4 + if lg_TL.len() > 0 { + align(left)[ + #block(fill: gray.lighten(80%), inset: 5pt, radius: 4pt)[ + #text(14pt, weight: "bold")[Mã đề: #ma_de] + ] + #v(-0.51em) + ] + for (idx, ans) in lg_TL.enumerate() { + align(left)[ + #text(12pt)[*Câu #(idx + 1). * #ans.nd] + #v(-0.5em) + #text(11pt, fill: blue.darken(40%))[*Lời giải:* ] + #v(-0.5em) + #block(inset: 12pt, fill: yellow.lighten(95%), radius: 4pt, width: 100%)[ + #text(fill: mausac.cau_pa, style: "italic")[#ans.lg] + ] + #v(-0.5em) + ] + } + } + } + }) +} + +#let rut_cauLevel(raw_bank, q_type, dem_config, seed) = { + let actual_bank = if type(raw_bank) == dictionary and "data" in raw_bank { raw_bank.data } + else if type(raw_bank) == module { raw_bank.data } else { raw_bank } + + let loc_ques = actual_bank.filter(q => q.type == q_type) + if loc_ques.len() == 0 { return () } + + let bank_chum = loc_ques.filter(q => "is_chum" in q and q.is_chum == true) + let bank_don = loc_ques.filter(q => not ("is_chum" in q and q.is_chum == true)) + + let safe-slice(arr, req_count) = { + if req_count <= 0 or arr.len() == 0 { return () } + let take = calc.min(req_count, arr.len()) + return arr.slice(0, take) + } + + let xao_chum = tron-mang(bank_chum, seed) + let xao_don = tron-mang(bank_don, seed + 101) + + let nb_req = 0 + let th_req = 0 + let vd_req = 0 + let chum_req = 0 + + if type(dem_config) == array { + nb_req = dem_config.at(0, default: 0) + th_req = dem_config.at(1, default: 0) + vd_req = dem_config.at(2, default: 0) + } else if type(dem_config) == dictionary { + let don_arr = dem_config.at("don", default: (0, 0, 0)) + nb_req = don_arr.at(0, default: 0) + th_req = don_arr.at(1, default: 0) + vd_req = don_arr.at(2, default: 0) + chum_req = dem_config.at("chum", default: 0) + } else if type(dem_config) == int { + nb_req = dem_config + } + + let res_chum = safe-slice(xao_chum, chum_req) + + let b_nb = xao_don.filter(q => ("lv" in q and q.lv == 1) or not ("lv" in q)) + let b_th = xao_don.filter(q => "lv" in q and q.lv == 2) + let b_vd = xao_don.filter(q => "lv" in q and q.lv == 3) + + let res_don = safe-slice(b_nb, nb_req) + safe-slice(b_th, th_req) + safe-slice(b_vd, vd_req) + + return res_chum + res_don +} + +#let tron_de_bankLevel(banks_matrix, info, show_lg: false, hienthi_bangdapan: true, theo_lv: false) = { + for (i, ma_de) in info.ds_ma_de.enumerate() { + let is_first = (i == 0) + let base_seed = int(ma_de) + + let rut_NLC = () + let rut_tf = () + let rut_TLN = () + let rut_TL = () + + for (b_idx, item) in banks_matrix.enumerate() { + let b = item.bank + let NLC_seed = base_seed * 999999 + b_idx * 999999 + 107 + let tf_seed = base_seed * 999999 + b_idx * 999999 + 233 + let TLN_seed = base_seed * 999999 + b_idx * 999999 + 357 + let TL_seed = base_seed * 999999 + b_idx * 999999 + 491 + + if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + } + + rut_NLC = xao-theo-tuy-chon(rut_NLC, base_seed + 991, theo_lv: theo_lv) + rut_tf = xao-theo-tuy-chon(rut_tf, base_seed + 997, theo_lv: theo_lv) + rut_TLN = xao-theo-tuy-chon(rut_TLN, base_seed + 1009, theo_lv: theo_lv) + rut_TL = xao-theo-tuy-chon(rut_TL, base_seed + 1013, theo_lv: theo_lv) + + let final_bank = rut_NLC + rut_tf + rut_TLN + rut_TL + + let fake_matrix = ( + NLC_loc: q => q.type == "NLC", + NLC_dem: rut_NLC.len(), + tf_loc: q => q.type == "TF", + tf_dem: rut_tf.len(), + TLN_loc: q => q.type == "TLN", + TLN_dem: rut_TLN.len(), + TL_loc: q => q.type == "TL", + TL_dem: rut_TL.len(), + ) + + render_test(ma_de, final_bank, fake_matrix, info, is_first: is_first, show_lg: show_lg, theo_lv: theo_lv) + + if i < info.ds_ma_de.len() - 1 { + pagebreak(weak: true) + } + } + + if hienthi_bangdapan { + pagebreak() + context { counter(page).update(1); set page(footer: none) } + align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] + v(-0.5em) + + context { + let results = query() + if results.len() > 0 { + let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() + if total_q > 0 { + table( + columns: (auto, ..info.ds_ma_de.map(_ => 1fr)), + align: center + horizon, + stroke: 0.5pt, + fill: (x, y) => if y == 0 { gray.lighten(80%) }, + [*Câu*], ..info.ds_ma_de.map(m => [*#m*]), + ..range(total_q).map(i => { + let row = ([#(i+1)],) + for entry in results { + let p1 = entry.value.part1 + let p2 = entry.value.part2 + let p3 = entry.value.part3 + let ans = if i < p1.len() { p1.at(i, default: "") } + else if i < p1.len() + p2.len() { p2.at(i - p1.len(), default: "") } + else { p3.at(i - p1.len() - p2.len(), default: "") } + row += ([#ans],) + } + row + }).flatten() + ) + } + } + } + + context { + let results = query() + if results.any(r => r.value.part4.len() > 0) { + in_dapan_TL(results) + } + } + + pagebreak() + context { counter(page).update(1); set page(footer: none) } + align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] + v(1em) + context { + let results = query() + let all_qrcode = tao-QRcode-key(results) + align(center)[ + #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ + #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ + #v(5pt) + #text(size: 10pt)[Số lượng mã đề: #results.len()] \ + #qr-code(all_qrcode, dark-color: black, light-color: white, quiet-zone: true) \ + #text(size: 9pt, fill: blue.darken(20%))[(Đáp án trắc nghiệm dành cho Unt)] + ] + ] + } + } +} + +#let tron_de_chiY( + banks_matrix, + info, + seed_goc: 2024, + show_lg: false, + hienthi_bangdapan: true, + tf_mode: "y_only", + nlc_mode: "full", + theo_lv: false, +) = { + let rut_NLC = () + let rut_tf = () + let rut_TLN = () + let rut_TL = () + + for (b_idx, item) in banks_matrix.enumerate() { + let b = item.bank + let NLC_seed = seed_goc * 999999 + b_idx * 999999 + 107 + let tf_seed = seed_goc * 999999 + b_idx * 999999 + 233 + let TLN_seed = seed_goc * 999999 + b_idx * 999999 + 357 + let TL_seed = seed_goc * 999999 + b_idx * 999999 + 491 + + if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + } + + rut_NLC = tron-mang(rut_NLC, seed_goc + 991) + rut_tf = tron-mang(rut_tf, seed_goc + 997) + rut_TLN = tron-mang(rut_TLN, seed_goc + 1009) + rut_TL = tron-mang(rut_TL, seed_goc + 1013) + + for (i, ma_de) in info.ds_ma_de.enumerate() { + let is_first = (i == 0) + let final_bank = rut_NLC + rut_tf + rut_TLN + rut_TL + + let fake_matrix = ( + NLC_loc: q => q.type == "NLC", + NLC_dem: rut_NLC.len(), + tf_loc: q => q.type == "TF", + tf_dem: rut_tf.len(), + TLN_loc: q => q.type == "TLN", + TLN_dem: rut_TLN.len(), + TL_loc: q => q.type == "TL", + TL_dem: rut_TL.len(), + ) + + render_test( + ma_de, + final_bank, + fake_matrix, + info, + is_first: is_first, + show_lg: show_lg, + tf_mode: "y_only", + nlc_mode: "none", + theo_lv: false, + ) + + if i < info.ds_ma_de.len() - 1 { + pagebreak(weak: true) + } + } + + if hienthi_bangdapan { + pagebreak() + context { counter(page).update(1); set page(footer: none) } + align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] + v(-0.5em) + + context { + let results = query() + if results.len() > 0 { + let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() + if total_q > 0 { + table( + columns: (auto, ..info.ds_ma_de.map(_ => 1fr)), + align: center + horizon, + stroke: 0.5pt, + fill: (x, y) => if y == 0 { gray.lighten(80%) }, + [*Câu*], ..info.ds_ma_de.map(m => [*#m*]), + ..range(total_q).map(i => { + let row = ([#(i+1)],) + for entry in results { + let p1 = entry.value.part1 + let p2 = entry.value.part2 + let p3 = entry.value.part3 + let ans = if i < p1.len() { p1.at(i, default: "") } + else if i < p1.len() + p2.len() { p2.at(i - p1.len(), default: "") } + else { p3.at(i - p1.len() - p2.len(), default: "") } + row += ([#ans],) + } + row + }).flatten() + ) + } + } + } + + context { + let results = query() + if results.any(r => r.value.part4.len() > 0) { + in_dapan_TL(results) + } + } + + pagebreak() + context { counter(page).update(1); set page(footer: none) } + align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] + v(1em) + context { + let results = query() + let all_qrcode = tao-QRcode-key(results) + align(center)[ + #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ + #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ + #v(5pt) + #text(size: 10pt)[Số lượng mã đề: #results.len()] \ + #qr-code(all_qrcode, dark-color: black, light-color: white, quiet-zone: true) \ + #text(size: 9pt, fill: blue.darken(20%))[(Đáp án trắc nghiệm dành cho Unt)] + ] + ] + } + } +} + +#let tron_de_cungNoiDung( + banks_matrix, + info, + seed_goc: 2024, + show_lg: false, + hienthi_bangdapan: true, + xao_cau: true, + xao_pa: true, + theo_lv: false, +) = { + let rut_NLC = () + let rut_tf = () + let rut_TLN = () + let rut_TL = () + + for (b_idx, item) in banks_matrix.enumerate() { + let b = item.bank + let NLC_seed = seed_goc * 999999 + b_idx * 999999 + 107 + let tf_seed = seed_goc * 999999 + b_idx * 999999 + 233 + let TLN_seed = seed_goc * 999999 + b_idx * 999999 + 357 + let TL_seed = seed_goc * 999999 + b_idx * 999999 + 491 + + if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + } + + rut_NLC = tron-mang(rut_NLC, seed_goc + 991) + rut_tf = tron-mang(rut_tf, seed_goc + 997) + rut_TLN = tron-mang(rut_TLN, seed_goc + 1009) + rut_TL = tron-mang(rut_TL, seed_goc + 1013) + + for (i, ma_de) in info.ds_ma_de.enumerate() { + let is_first = (i == 0) + let base_seed = int(ma_de) + + let final_NLC = if xao_cau { xao-theo-tuy-chon(rut_NLC, base_seed + 2001, theo_lv: theo_lv) } else { rut_NLC } + let final_tf = if xao_cau { xao-theo-tuy-chon(rut_tf, base_seed + 2011, theo_lv: theo_lv) } else { rut_tf } + let final_TLN = if xao_cau { xao-theo-tuy-chon(rut_TLN, base_seed + 2027, theo_lv: theo_lv) } else { rut_TLN } + let final_TL = if xao_cau { xao-theo-tuy-chon(rut_TL, base_seed + 2039, theo_lv: theo_lv) } else { rut_TL } + + let final_bank = final_NLC + final_tf + final_TLN + final_TL + + let fake_matrix = ( + NLC_loc: q => q.type == "NLC", + NLC_dem: final_NLC.len(), + tf_loc: q => q.type == "TF", + tf_dem: final_tf.len(), + TLN_loc: q => q.type == "TLN", + TLN_dem: final_TLN.len(), + TL_loc: q => q.type == "TL", + TL_dem: final_TL.len(), + ) + + render_test( + ma_de, + final_bank, + fake_matrix, + info, + is_first: is_first, + show_lg: show_lg, + theo_lv: theo_lv, + ) + + if i < info.ds_ma_de.len() - 1 { + pagebreak(weak: true) + } + } + + if hienthi_bangdapan { + pagebreak() + context { counter(page).update(1); set page(footer: none) } + align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] + v(-0.5em) + + context { + let results = query() + if results.len() > 0 { + let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() + if total_q > 0 { + table( + columns: (auto, ..info.ds_ma_de.map(_ => 1fr)), + align: center + horizon, + stroke: 0.5pt, + fill: (x, y) => if y == 0 { gray.lighten(80%) }, + [*Câu*], ..info.ds_ma_de.map(m => [*#m*]), + ..range(total_q).map(i => { + let row = ([#(i+1)],) + for entry in results { + let p1 = entry.value.part1 + let p2 = entry.value.part2 + let p3 = entry.value.part3 + let ans = if i < p1.len() { p1.at(i, default: "") } + else if i < p1.len() + p2.len() { p2.at(i - p1.len(), default: "") } + else { p3.at(i - p1.len() - p2.len(), default: "") } + row += ([#ans],) + } + row + }).flatten() + ) + } + } + } + + context { + let results = query() + if results.any(r => r.value.part4.len() > 0) { + in_dapan_TL(results) + } + } + + pagebreak() + context { counter(page).update(1); set page(footer: none) } + align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] + v(1em) + context { + let results = query() + let all_qrcode = tao-QRcode-key(results) + align(center)[ + #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ + #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ + #v(5pt) + #text(size: 10pt)[Số lượng mã đề: #results.len()] \ + #qr-code(all_qrcode, dark-color: black, light-color: white, quiet-zone: true) \ + #text(size: 9pt, fill: blue.darken(20%))[(Đáp án trắc nghiệm dành cho Unt)] + ] + ] + } + } +} + +// ========================================== +// 6. CÁC HÀM TRANG TRÍ TIÊU ĐỀ +// ========================================== +#let tdbai(title, bsize: 18pt, clorfont: rgb("#0309a7"), bground: rgb("#00ffff3b"), cle: center) = { + block( + width: 100%, fill: bground, radius: 8pt, stroke: 0.5pt + rgb("#c405ef"), inset: (x: 25pt, y: 8pt), + align(cle)[#text(fill: clorfont, size: bsize, weight: "bold", font: "Times New Roman", title)] + ) +} + +#let dang(title, STT: "1", kieu: "Dạng") = [ + #grid( + columns: (auto, 1fr), align: center + horizon, column-gutter: -2pt, + box(fill: rgb("#72f0b1a2"), radius: 8pt, inset: (x: 10pt, y: 10pt), stroke: 2pt + rgb("#72f0b1a2"))[ + #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #STT:]) + ], + box(fill: rgb("#6ff6e484"), width: 100%, radius: 8pt, inset: (x: 15pt, y: 10pt), stroke: 2pt + rgb("#6ff6e484"))[ + #text(weight: "bold", fill: rgb("#e90335f8"), size: 1.4em)[#title] + ] + ) + #v(0.5em) +] + +#let mau-cap1 = rgb("#1f02c3") +#let mau-cap2 = rgb("#0501f0") +#let mau-cap3 = rgb("#024905") + +#let tieude(noi-dung, cap: 1) = { + if cap == 1 { + block(width: 100%, below: 0.7em, inset: (x: 0pt, y: 8pt), fill: rgb("#f3b40659"), radius: 4pt)[ + #align(left)[#text(weight: "bold", size: 1.3em, fill: mau-cap2)[#noi-dung]] + #v(0.15em) + ] + } else if cap == 2 { + block(width: 100%, below: 0.5em, inset: (x: 0pt, y: 7pt), fill: rgb("#65e4eb36"), radius: 4pt)[ + #text(weight: "bold", size: 1.2em, fill: mau-cap2)[#noi-dung] + #v(0.1em) + ] + } else if cap == 3 { + block(width: 100%, below: 0.3em, inset: (x: 0pt, y: 8pt), fill: rgb("#9bf29525"), radius: 3pt)[ + #text(weight: "bold", size: 1.1em, fill: mau-cap3)[▸ #noi-dung] + ] + } else { + block(width: 100%, below: 0.3em, inset: (x: 0pt, y: 4pt))[ + #text(weight: "regular", size: 1.0em, fill: rgb("#424242"))[◦ #noi-dung] + ] + } + v(0.3em) +} + +#let chimuc(title, tsize: 16pt) = { + set par(first-line-indent: 0pt) + block(width: 100%)[ + #box(fill: rgb("#00ffff2e"), radius: (top-left: 0pt, top-right: 8pt, bottom-left: 0pt, bottom-right: 0pt), stroke: 0.5pt + rgb("#ee05ea"), inset: (x: 4pt, y: 8pt))[ + #text(fill: rgb("#003B5C"), size: tsize, weight: "bold", font: "Times New Roman", title) + ] + #v(-15pt) + #line(length: 100%, stroke: 2pt + rgb("#FF0066")) + ] +} + +#let luuy(title, body) = { + block(width: 100%, below: 0.1em, stroke: (paint: red, thickness: 1pt), inset: (x: 12pt, y: 10pt), radius: 4pt, fill: rgb("#99eee832"))[ + #text(weight: "bold", fill: blue.darken(40%))[#underline(title, offset: 3pt)] + #v(-0.3em) + #set text(fill: oklab(36.99%, -0.019, -0.229), style: "italic") + #body + ] + v(1em) +} + +#let ps(a, b) = text(size: 1.5em)[#math.display(math.frac([#a], [#b]))] + +// ========================================== +// 7. BÍ DANH TIẾNG ANH (API CHUẨN UNIVERSE) +// ========================================== +#let exercise = baitap_inline +#let make-exam-matrix = tron_de_bankLevel +#let make-exam-sync = tron_de_cungNoiDung +#let make-exam-sub-only = tron_de_chiY From 14603dd16d4aa08f969fb79de8212c4fe7699dcb Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:10:15 +0700 Subject: [PATCH 03/30] Create typst.toml --- packages/preview/v-exam/0.1.0/typst.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/preview/v-exam/0.1.0/typst.toml diff --git a/packages/preview/v-exam/0.1.0/typst.toml b/packages/preview/v-exam/0.1.0/typst.toml new file mode 100644 index 0000000000..ea50cc6f4c --- /dev/null +++ b/packages/preview/v-exam/0.1.0/typst.toml @@ -0,0 +1,11 @@ +[package] +name = "v-exam" +version = "0.1.0" +entrypoint = "lib.typ" +authors = ["Kieu Quang Vu (@KieuQuangVu-NCP)"] +license = "MIT" +description = "Bộ công cụ biên soạn bài tập và trộn đề thi trắc nghiệm, tự luận chuẩn Bộ GD&ĐT Việt Nam dành cho mọi môn học." +repository = "https://github.com/KieuQuangVu-NCP/v-exam" +keywords = ["exam", "test", "vietnam", "quiz", "education", "v-exam"] +categories = ["office", "layout"] +compiler = ">= 0.11.0" From d76ed183ca28c475b81194f9404fe4e164e92b44 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:11:20 +0700 Subject: [PATCH 04/30] Create t --- packages/preview/v-exam/0.1.0/gallery/t | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/preview/v-exam/0.1.0/gallery/t diff --git a/packages/preview/v-exam/0.1.0/gallery/t b/packages/preview/v-exam/0.1.0/gallery/t new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/preview/v-exam/0.1.0/gallery/t @@ -0,0 +1 @@ + From 946c09a5e20d8b53686f17e2055e17d1993d111b Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:11:48 +0700 Subject: [PATCH 05/30] Add files via upload --- .../v-exam/0.1.0/gallery/Picture-bangda.png | Bin 0 -> 25694 bytes .../v-exam/0.1.0/gallery/Picture-de.png | Bin 0 -> 148981 bytes .../v-exam/0.1.0/gallery/Picture-maQR.png | Bin 0 -> 24703 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/preview/v-exam/0.1.0/gallery/Picture-bangda.png create mode 100644 packages/preview/v-exam/0.1.0/gallery/Picture-de.png create mode 100644 packages/preview/v-exam/0.1.0/gallery/Picture-maQR.png diff --git a/packages/preview/v-exam/0.1.0/gallery/Picture-bangda.png b/packages/preview/v-exam/0.1.0/gallery/Picture-bangda.png new file mode 100644 index 0000000000000000000000000000000000000000..cf6dbebec924007204e93e24ec455e3bb4fe81f1 GIT binary patch literal 25694 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 literal 0 HcmV?d00001 diff --git a/packages/preview/v-exam/0.1.0/gallery/Picture-de.png b/packages/preview/v-exam/0.1.0/gallery/Picture-de.png new file mode 100644 index 0000000000000000000000000000000000000000..5743256389aa10899bbe31524bd342dbb0e33933 GIT binary patch literal 148981 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%0AHz7#qor*iAv# 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�hd-L6@J!Y`wM5@2 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

Qe=ho96lO%(dR~?kwMS*TF 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 literal 0 HcmV?d00001 diff --git a/packages/preview/v-exam/0.1.0/gallery/Picture-maQR.png b/packages/preview/v-exam/0.1.0/gallery/Picture-maQR.png new file mode 100644 index 0000000000000000000000000000000000000000..c2a44666973da12f5c53ec9a288cacae5e274f3a GIT binary patch literal 24703 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 Date: Mon, 28 Sep 2026 09:13:30 +0700 Subject: [PATCH 06/30] Delete packages/preview/v-exam/0.1.0/gallery/t --- packages/preview/v-exam/0.1.0/gallery/t | 1 - 1 file changed, 1 deletion(-) delete mode 100644 packages/preview/v-exam/0.1.0/gallery/t diff --git a/packages/preview/v-exam/0.1.0/gallery/t b/packages/preview/v-exam/0.1.0/gallery/t deleted file mode 100644 index 8b13789179..0000000000 --- a/packages/preview/v-exam/0.1.0/gallery/t +++ /dev/null @@ -1 +0,0 @@ - From a219fda42ecb6c3dd64ab6dc99d33e6dc3c876f8 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:18:06 +0700 Subject: [PATCH 07/30] Create README.md --- packages/preview/v-exam/0.1.0/README.md | 221 ++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 packages/preview/v-exam/0.1.0/README.md diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md new file mode 100644 index 0000000000..edb46d251b --- /dev/null +++ b/packages/preview/v-exam/0.1.0/README.md @@ -0,0 +1,221 @@ +# v-exam + +Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề thi trắc nghiệm / tự luận chuẩn định dạng Bộ Giáo dục & Đào tạo Việt Nam dành cho mọi môn học (Toán, Vật lý, Hóa học, Sinh học, Lịch sử, Địa lý, GDKT&PL, ...). + +--- + +## 🚀 Tính năng nổi bật + +- **Tự động trộn đề:** Trộn đảo phương án NLC, đảo ý $a, b, c, d$ của câu hỏi Đúng/Sai, hoán vị câu hỏi theo seed mã đề. +- **Tự động xuất bảng đáp án & mã QR:** Tạo bảng đáp án tổng hợp và mã QR cho phần mềm chấm thi tự động (như UNT, Chấm thi KC, ...). +- **Hỗ trợ câu hỏi chùm (Dữ kiện chung):** Tự động gom nhóm các câu hỏi con đi kèm đoạn văn cảnh/dữ kiện dùng chung mà không bị xáo rời rạc cho trường hợp câu hỏi chùm các môn. +- **Biên soạn bài tập nối tiếp (`exercise` / `baitap_inline`):** Hỗ trợ biên soạn tài liệu giảng dạy, bài tập ôn tập chuyên đề có kèm lời giải chi tiết. + +--- +## 🖼️ Mẫu kết quả (Gallery) + +

+ Đề thi mẫu
+ Bảng đáp án
+ Mã QRcode dùng cho máy chấm +

+ +## 📦 Hướng dẫn sử dụng + +### 1. Import thư viện + +```typst +#import "@preview/v-exam:0.1.0": * +``` + +### 2. Định dạng ngân hàng câu hỏi + +Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `dictionary`: + +```typst +#let data = ( +// Câu hỏi đơn trắc nghiệm nhiều lựa chọn. +( + type: "NLC", + hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn") dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp + lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + nd: [Nội dung lời dẫn], + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), + cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột + da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D + lg: [Lời giải cho câu hỏi], + ), +// Câu hỏi chùm trắc nghiệm nhiều lựa chọn. +( + type: "NLC", + hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp + lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + is_chum:true, + du_kien:[Nội dung dùng chung], + cau_hoi_con:( + // Câu hỏi con 1. + (nd: [Nội dung lời dẫn câu hỏi 1], + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), + cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột + da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D + lg: [Lời giải cho câu hỏi 1],), + // Câu hỏi con 2. + (nd: [Nội dung lời dẫn câu hỏi 2], + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), + cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột + da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D + lg: [Lời giải cho câu hỏi 2],) + ), + // Câu hỏi đúng sai + ( + type: "TF", + hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp + lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + nd: [Lời dẫn của của câu hỏi], + ytf: ( + [nội dung ý a], + [nội dung ý b], + [nội dung ý c], + [nội dung ý d], + ), + da: (1, 0, 1, 0), // 1 - đúng, 0 - sai + lg: ([Lời giải cho ý a], + [Lời giải cho ý b], + [Lời giải cho ý c], + [Lời giải cho ý d], + ), +//Câu hỏi trả lời ngắn đơn +( + type: "TLN", + hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp + lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + nd: [Lời dẫn của của câu hỏi], + da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," + lg:[Lời giải cho bài toán], + dong_ke: so_dong_ke, +), +//Câu hỏi trắc lời ngắn dạng chùm +// Câu hỏi chùm trắc nghiệm nhiều lựa chọn. +( + type: "TLN", + hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp + lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + is_chum:true, + du_kien:[Nội dung dùng chung], + cau_hoi_con:( + // Câu hỏi con 1. + (nd: [Nội dung lời dẫn câu hỏi 1], + da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," + lg:[Lời giải cho bài toán], + dong_ke: so_dong_ke,), + // Câu hỏi con 2. + (nd: [Nội dung lời dẫn câu hỏi 2], + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), + da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," + lg:[Lời giải cho bài toán], + dong_ke: so_dong_ke,), + ), +//Câu hỏi tự luận +( + type: "TL", + hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp + lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + nd: [Lời dẫn của của câu hỏi], + lg:[Lời giải cho bài toán], + dong_ke: so_dong_ke, +), +) +``` + +### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `baitap_inline`) +```typst +#import "file.typ" as b +// code tạo bài tập. +#exercise( + b.data, + cm: 1, + num_nlc: (1, 0, 0), + num_tf: (0, 1, 0), + num_tln: (0,1,2), + show_lg: true, + seed: 123, + theo_lv:true, + dong_ke:4 +) +``` + +### 4. Trộn đề thi +#### a) Trộn đề thi khác nhau(`make-exam-matrix` / `tron_de_bankLevel`) +Tạo các đề thi tư ngân hàng với các lấy ngẫu nhiên các câu hỏi từ bank để tạo bộ câu hỏi khác nhau cho mỗi đề\ +**- Import ngân hàng câu hỏi để trộn đề và tạo bank** +```typst +#import "file.typ" as b +#let matrix = ( + ( + bank: b.data, + NLC_dem: (1, 0, 0), + tf_dem: (0, 1, 0), + tln_dem: (0, 1, 0), + tl_dem: (0, 1, 0), + ), +) +``` +**- Tạo thông tin bài kiểm tra** +```typst +#let info = ( + so_gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], + truong: [TRƯỜNG THPT NGHĨA HÀNH], + ky_thi: [KIỂM TRA GIỮA KỲ I], + mon: [VẬT LÝ 12], + thoi_gian: [45 phút], + ds_ma_de: ("101", "102", "103", "104"), +) +``` +**- Thực hiện lên trộn đề:** +```typst +Cách 1: +#make-exam-matrix(matrix, info, show_lg: false, hienthi_bangdapan: true, theo_lv:true) + +Cách 2: +#tron_de_bankLevel(matrix, info, show_lg: false, hienthi_bangdapan: true, theo_lv:true) +``` +Giải thích: +- matrix: là nơi cấu hình cách lấy câu hỏi từ bank để đưa vào đề. +- info: nội dung hiển thị tiêu đề của của bài kiểm tra và các mã đề của đề +- show_lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. +- hienthi_bangdapan: có hai chức năng: (1) hiển thị bảng đáp án (true) cuối file để dùng trong chấm bài; (2) không hiển thị bảng đáp án (false) đảm bào đề tạo ra không có bản đáp án. +- theo_lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. + +#### b) chức năng trộn đề tạo các đề giống nhau (`make-exam-sync` / `tron_de_cungNoiDung`) +Cách thực hiện đuề giống với "Trộn đề thi khác nhau" chỉ khác ở mục thực hiện trộn đề khi gọi lệnh: +```typst +Cách 1: +#make-exam-sync(matrix, info, seed_goc: 2026, show_lg: false,theo_lv:false,xao_cau: true, xao_pa: true) + +Cách 2: +#tron_de_cungNoiDung(matrix, info, seed_goc: 2026, show_lg: false,theo_lv:false,xao_cau: true, xao_pa: true) +``` +Giải thích: +- seed_goc: 2026 dùng để ấn định một seed được chon để tạo đề gốc ban đầu sau đó căn cứ theo mã đề để xáo cho hợp lý +- show_lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. +- hienthi_bangdapan: có hai chức năng: (1) hiển thị bảng đáp án (true) cuối file để dùng trong chấm bài; (2) không hiển thị bảng đáp án (false) đảm bào đề tạo ra không có bản đáp án. +- theo_lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. +- xao_cau: cho phép cố định câu không đổi vị trí câu ở các đề (false), đảo vị trí ở các đề (true) +- xao_pa: cho phép cố định phương án ABCD hoặc ý abcd ở các đề (false), đảo vị trí phương án ở các đề (true) +#### c) chức năng trộn đề ý hoặc phương án(`make-exam-sub-only` / `tron_de_chiY`) +Cách thực hiện đuề giống với "Trộn đề cùng nội dung" chỉ khác ở mục thực hiện trộn đề khi gọi lệnh: +```typst +Cách 1: +#make-exam-sub-only(matrix_con, info_de, seed_goc: 2024, show_lg: false,tf_mode:"y_only",nlc_mode:"none",theo_lv:false) + +Cách 2: +#tron_de_chiY(matrix_con, info_de, seed_goc: 2024, show_lg: false,tf_mode:"y_only",nlc_mode:"none",theo_lv:false) +``` +Giải thích: +- tf_mode: có hai chế độ "y_only" đảo ý và "full" đảo ý và đảo câu. +- nlc_mode: có 3 chế độ: "y_only" đảo phương án; "full" đảo phương án và đảo câu; "none" không thay đổi. +--- + +## 📜 Giấy phép + +Phát hành theo giấy phép [MIT License](LICENSE). From cab7c6832dd6418a28db57dffb765d8397821e69 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:18:52 +0700 Subject: [PATCH 08/30] Create LICENSE --- packages/preview/v-exam/0.1.0/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/preview/v-exam/0.1.0/LICENSE diff --git a/packages/preview/v-exam/0.1.0/LICENSE b/packages/preview/v-exam/0.1.0/LICENSE new file mode 100644 index 0000000000..45c09ad119 --- /dev/null +++ b/packages/preview/v-exam/0.1.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 KieuQuangVu-NCP + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From fa7dd1cab91a29ebdb109042c5a8fbe395bd45c3 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:33:49 +0700 Subject: [PATCH 09/30] Update typst.toml --- packages/preview/v-exam/0.1.0/typst.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/preview/v-exam/0.1.0/typst.toml b/packages/preview/v-exam/0.1.0/typst.toml index ea50cc6f4c..e0a8c73e08 100644 --- a/packages/preview/v-exam/0.1.0/typst.toml +++ b/packages/preview/v-exam/0.1.0/typst.toml @@ -8,4 +8,4 @@ description = "Bộ công cụ biên soạn bài tập và trộn đề thi tr repository = "https://github.com/KieuQuangVu-NCP/v-exam" keywords = ["exam", "test", "vietnam", "quiz", "education", "v-exam"] categories = ["office", "layout"] -compiler = ">= 0.11.0" +compiler = "0.11.0" From 0ddbb6c8c114cb6c3cd8c8c7d663cef4b96bf504 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 09:52:49 +0700 Subject: [PATCH 10/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 252 +++++++++++++------------- 1 file changed, 126 insertions(+), 126 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index bacb9125a4..6d63a5b66d 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -88,8 +88,8 @@ return tron-mang(nhom1, seed + 11) + tron-mang(nhom2, seed + 22) + tron-mang(nhom3, seed + 33) + tron-mang(nhom_khac, seed + 44) } -#let xao-theo-tuy-chon(arr, seed, theo_lv: false) = { - if theo_lv { +#let xao-theo-tuy-chon(arr, seed, theo-lv: false) = { + if theo-lv { tron-mang-theo-lv(arr, seed) } else { tron-mang(arr, seed) @@ -163,8 +163,8 @@ // ========================================== // 4. BÀI TẬP INLINE / ÔN TẬP TÀI LIỆU // ========================================== -#let render_sub_sol(q, type_str, show_lg) = { - if not show_lg { return } +#let render_sub_sol(q, type_str, show-lg) = { + if not show-lg { return } v(-0.8em) block( width: 100%, @@ -214,22 +214,22 @@ bank_data, title: none, seed: 0, - num_nlc: none, - num_tf: none, - num_tln: none, - num_tl: none, - show_lg: false, - dong_ke: none, - co_NLC: none, - co_tf: none, - co_TLN: none, - co_TL: none, - theo_lv: false, + num-nlc: none, + num-tf: none, + num-tln: none, + num-tl: none, + show-lg: false, + dong-ke: none, + co-nlc: none, + co-tf: none, + co-tln: none, + co-tl: none, + theo-lv: false, ) = { - let cfg_nlc = if num_nlc != none { num_nlc } else { co_NLC } - let cfg_tf = if num_tf != none { num_tf } else { co_tf } - let cfg_tln = if num_tln != none { num_tln } else { co_TLN } - let cfg_tl = if num_tl != none { num_tl } else { co_TL } + let cfg_nlc = if num-nlc != none { num-nlc } else { co-nlc } + let cfg_tf = if num-tf != none { num-tf } else { co-tf } + let cfg_tln = if num-tln != none { num-tln } else { co-tln } + let cfg_tl = if num-tl != none { num-tl } else { co-tl } let actual_bank = if type(bank_data) == dictionary and "data" in bank_data { bank_data.data @@ -274,7 +274,7 @@ } if type(dem_config) == int { - let processing = if seed == none { loc_ques } else { xao-theo-tuy-chon(loc_ques, seed + sub_seed, theo_lv: theo_lv) } + let processing = if seed == none { loc_ques } else { xao-theo-tuy-chon(loc_ques, seed + sub_seed, theo-lv: theo-lv) } return processing.slice(0, calc.min(dem_config, processing.len())) } @@ -364,7 +364,7 @@ row-gutter: 0.5em, align: center + horizon, ..q.pa.enumerate().map(((i, v)) => { - let is_correct = show_lg and ("da" in q) and (i == q.da) + let is_correct = show-lg and ("da" in q) and (i == q.da) let label_text = [#h(1em)*#to-abc(i).*] let formatted_label = if is_correct { underline(text(fill: mausac.daT, weight: "bold")[#label_text]) } else { text(fill: mausac.cau_pa)[#label_text] } align(left)[#grid(columns:(auto,1fr), column-gutter:10pt, [#formatted_label], [#v])] @@ -379,7 +379,7 @@ align: if n_cols > 1 { left + horizon } else { left }, inset: (x: 1em), ..q.pa.enumerate().map(((i, v)) => { - let is_correct = show_lg and ("da" in q) and (i == q.da) + let is_correct = show-lg and ("da" in q) and (i == q.da) let label_text = [*#to-abc(i).*] let formatted_label = if is_correct { underline(text(fill: mausac.daT, weight: "bold")[#label_text]) } else { text(fill: mausac.cau_pa)[#label_text] } box[#grid(columns: (auto, 1fr), gutter: 2pt, align: left, formatted_label, v)] @@ -391,7 +391,7 @@ ) ] v(-0.7em) - render_sub_sol(q, "NLC", show_lg) + render_sub_sol(q, "NLC", show-lg) } } } @@ -432,7 +432,7 @@ ..q.ytf.enumerate().map(((i, sq)) => { let label_text = [#("a)", "b)", "c)", "d)").at(i)] let formatted_label = text(fill: mausac.cau_pa, weight: "bold")[#h(0.5em) #label_text] - let ans_str = if show_lg and ("da" in q) and type(q.da) == array and i < q.da.len() { + let ans_str = if show-lg and ("da" in q) and type(q.da) == array and i < q.da.len() { if q.da.at(i) == 1 { " [Đúng]" } else { " [Sai]" } } else { "" } [#formatted_label #sq #text(fill: mausac.daT, weight: "bold")[#ans_str]] @@ -443,7 +443,7 @@ ) ] v(-0.8em) - render_sub_sol(q, "TF", show_lg) + render_sub_sol(q, "TF", show-lg) } } } @@ -480,7 +480,7 @@ #v(-0.1em) #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd #v(0.1em) - #if not show_lg [ + #if not show-lg [ #grid( columns: (auto, auto), column-gutter: 8pt, @@ -489,9 +489,9 @@ [#(for i in range(4) { box(width: 1.2em, height: 1.2em, stroke: 0.4pt + gray.darken(80%), radius: 1pt); h(2pt) })] ) #v(-0.4em) - #let num_lines = if dong_ke == none or dong_ke == 0 { none + #let num_lines = if dong-ke == none or dong-ke == 0 { none } else if "dong_ke" in q and q.dong_ke != none { q.dong_ke - } else { dong_ke } + } else { dong-ke } #if num_lines != none and type(num_lines) == int and num_lines > 0 { v(0.3em) for i in range(num_lines) { @@ -505,7 +505,7 @@ ) ] v(-0.4em) - render_sub_sol(q, "TLN", show_lg) + render_sub_sol(q, "TLN", show-lg) } } } @@ -534,10 +534,10 @@ if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(1em)] ) #v(-0.8em) - #if not show_lg [ - #let num_lines = if dong_ke == none or dong_ke == 0 { none + #if not show-lg [ + #let num_lines = if dong-ke == none or dong-ke == 0 { none } else if "dong_ke" in q and q.dong_ke != none { q.dong_ke - } else { dong_ke } + } else { dong-ke } #if num_lines != none and type(num_lines) == int and num_lines > 0 { v(0.3em) for i in range(num_lines) { @@ -550,7 +550,7 @@ #v(0.4em) ] v(-0.8em) - render_sub_sol(q, "TL", show_lg) + render_sub_sol(q, "TL", show-lg) } } } @@ -565,35 +565,35 @@ q_bank, matrix, info, - is_first: false, - show_lg: false, - tf_mode: "full", - nlc_mode: "full", - theo_lv: false, + is-first: false, + show-lg: false, + tf-mode: "full", + nlc-mode: "full", + theo-lv: false, ) = { - if not is_first { + if not is-first { context { counter(page).update(1) } } let seed = int(ma_de) let raw_NLC = q_bank.filter(matrix.NLC_loc) - let xao_NLC = xao-theo-tuy-chon(raw_NLC, seed + 107, theo_lv: theo_lv) + let xao_NLC = xao-theo-tuy-chon(raw_NLC, seed + 107, theo-lv: theo-lv) let NLC_dem = calc.min(matrix.NLC_dem, xao_NLC.len()) let s_NLC = xao_NLC.slice(0, NLC_dem) let raw_tf = q_bank.filter(matrix.tf_loc) - let xao_tf = xao-theo-tuy-chon(raw_tf, seed + 233, theo_lv: theo_lv) + let xao_tf = xao-theo-tuy-chon(raw_tf, seed + 233, theo-lv: theo-lv) let tf_dem = calc.min(matrix.tf_dem, xao_tf.len()) let s_tf = xao_tf.slice(0, tf_dem) let raw_TLN = q_bank.filter(matrix.TLN_loc) - let xao_TLN = xao-theo-tuy-chon(raw_TLN, seed + 357, theo_lv: theo_lv) + let xao_TLN = xao-theo-tuy-chon(raw_TLN, seed + 357, theo-lv: theo-lv) let TLN_dem = calc.min(matrix.TLN_dem, xao_TLN.len()) let s_TLN = xao_TLN.slice(0, TLN_dem) let raw_TL = q_bank.filter(matrix.TL_loc) - let xao_TL = xao-theo-tuy-chon(raw_TL, seed + 491, theo_lv: theo_lv) + let xao_TL = xao-theo-tuy-chon(raw_TL, seed + 491, theo-lv: theo-lv) let TL_dem = calc.min(matrix.TL_dem, xao_TL.len()) let s_TL = xao_TL.slice(0, TL_dem) @@ -659,7 +659,7 @@ let ds_cau_can_ve = if is_item_chum { item.cau_hoi_con } else { (item,) } for q in ds_cau_can_ve { - let opt_indices = if seed == 0 or nlc_mode == "none" { range(4) } else { tron-mang(range(4), seed + c_idx * 73) } + let opt_indices = if seed == 0 or nlc-mode == "none" { range(4) } else { tron-mang(range(4), seed + c_idx * 73) } let new_opts = opt_indices.map(i => q.pa.at(i)) part1_ans.push(to-abc(opt_indices.position(i => i == q.da))) @@ -696,7 +696,7 @@ ) ] v(-0.8em) - if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "NLC", c_idx, seed, opt_indices: opt_indices) } + if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "NLC", c_idx, seed, opt_indices: opt_indices) } v(-0.2em) c_idx += 1 } @@ -707,8 +707,8 @@ set par(first-line-indent: 0pt) v(0.5em); text(mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #s_tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] for (idx, q) in s_tf.enumerate() { - let sub_indices = if tf_mode == "none" { range(4) } - else if tf_mode == "y_only" { + let sub_indices = if tf-mode == "none" { range(4) } + else if tf-mode == "y_only" { let content_str = repr(q.nd) + repr(q.ytf) let content_hash = calc.rem(content_str.len() * 265435761, 123456789) tron-mang(range(4), content_hash * 31 + int(ma_de) * 7919) @@ -728,7 +728,7 @@ ) ] v(-0.4em) - if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TF", idx + s_NLC.len(), seed, tf_indices: sub_indices) } + if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TF", idx + s_NLC.len(), seed, tf_indices: sub_indices) } v(-0.3em) } } @@ -766,7 +766,7 @@ columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), [ #text(fill: mausac.cau_pa)[*Câu #(c_idx + 1).* ]#q.nd - #if not show_lg [ + #if not show-lg [ #v(-0.4em) #pad(left: 0em)[ #grid(columns: (auto, auto), column-gutter: 10pt, align: (left + horizon, left + horizon), [*Trả lời:*], [#(for i in range(4) { box(width: 1.2em, height: 1.2em, stroke: 0.3pt); h(3pt) })]) @@ -777,7 +777,7 @@ ) ] v(-1em) - if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TLN", c_idx + s_NLC.len() + s_tf.len(), seed) } + if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TLN", c_idx + s_NLC.len() + s_tf.len(), seed) } v(-0.2em) c_idx += 1 } @@ -798,7 +798,7 @@ [ #text(fill: mausac.cau_pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], if has_img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) - #if show_lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TL", idx, seed) } + #if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TL", idx, seed) } #v(-0.3em) ] } @@ -816,7 +816,7 @@ )) ] } -#let in_dapan_TL(results) = { +#let in-dapan-tl(results) = { context { counter(page).update(1) set page(footer: none) @@ -851,7 +851,7 @@ }) } -#let rut_cauLevel(raw_bank, q_type, dem_config, seed) = { +#let rut-cau-level(raw_bank, q_type, dem_config, seed) = { let actual_bank = if type(raw_bank) == dictionary and "data" in raw_bank { raw_bank.data } else if type(raw_bank) == module { raw_bank.data } else { raw_bank } @@ -900,7 +900,7 @@ return res_chum + res_don } -#let tron_de_bankLevel(banks_matrix, info, show_lg: false, hienthi_bangdapan: true, theo_lv: false) = { +#let tron-de-bank-level(banks_matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: false) = { for (i, ma_de) in info.ds_ma_de.enumerate() { let is_first = (i == 0) let base_seed = int(ma_de) @@ -917,16 +917,16 @@ let TLN_seed = base_seed * 999999 + b_idx * 999999 + 357 let TL_seed = base_seed * 999999 + b_idx * 999999 + 491 - if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + if "NLC_dem" in item { rut_NLC += rut-cau-level(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut-cau-level(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut-cau-level(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut-cau-level(b, "TL", item.TL_dem, TL_seed) } } - rut_NLC = xao-theo-tuy-chon(rut_NLC, base_seed + 991, theo_lv: theo_lv) - rut_tf = xao-theo-tuy-chon(rut_tf, base_seed + 997, theo_lv: theo_lv) - rut_TLN = xao-theo-tuy-chon(rut_TLN, base_seed + 1009, theo_lv: theo_lv) - rut_TL = xao-theo-tuy-chon(rut_TL, base_seed + 1013, theo_lv: theo_lv) + rut_NLC = xao-theo-tuy-chon(rut_NLC, base_seed + 991, theo-lv: theo-lv) + rut_tf = xao-theo-tuy-chon(rut_tf, base_seed + 997, theo-lv: theo-lv) + rut_TLN = xao-theo-tuy-chon(rut_TLN, base_seed + 1009, theo-lv: theo-lv) + rut_TL = xao-theo-tuy-chon(rut_TL, base_seed + 1013, theo-lv: theo-lv) let final_bank = rut_NLC + rut_tf + rut_TLN + rut_TL @@ -941,14 +941,14 @@ TL_dem: rut_TL.len(), ) - render_test(ma_de, final_bank, fake_matrix, info, is_first: is_first, show_lg: show_lg, theo_lv: theo_lv) + render_test(ma_de, final_bank, fake_matrix, info, is-first: is_first, show-lg: show-lg, theo-lv: theo-lv) if i < info.ds_ma_de.len() - 1 { pagebreak(weak: true) } } - if hienthi_bangdapan { + if hienthi-bangdapan { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -986,7 +986,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in_dapan_TL(results) + in-dapan-tl(results) } } @@ -1010,15 +1010,15 @@ } } -#let tron_de_chiY( +#let tron-de-chi-y( banks_matrix, info, - seed_goc: 2024, - show_lg: false, - hienthi_bangdapan: true, - tf_mode: "y_only", - nlc_mode: "full", - theo_lv: false, + seed-goc: 2024, + show-lg: false, + hienthi-bangdapan: true, + tf-mode: "y_only", + nlc-mode: "full", + theo-lv: false, ) = { let rut_NLC = () let rut_tf = () @@ -1027,21 +1027,21 @@ for (b_idx, item) in banks_matrix.enumerate() { let b = item.bank - let NLC_seed = seed_goc * 999999 + b_idx * 999999 + 107 - let tf_seed = seed_goc * 999999 + b_idx * 999999 + 233 - let TLN_seed = seed_goc * 999999 + b_idx * 999999 + 357 - let TL_seed = seed_goc * 999999 + b_idx * 999999 + 491 - - if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + let NLC_seed = seed-goc * 999999 + b_idx * 999999 + 107 + let tf_seed = seed-goc * 999999 + b_idx * 999999 + 233 + let TLN_seed = seed-goc * 999999 + b_idx * 999999 + 357 + let TL_seed = seed-goc * 999999 + b_idx * 999999 + 491 + + if "NLC_dem" in item { rut_NLC += rut-cau-level(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut-cau-level(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut-cau-level(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut-cau-level(b, "TL", item.TL_dem, TL_seed) } } - rut_NLC = tron-mang(rut_NLC, seed_goc + 991) - rut_tf = tron-mang(rut_tf, seed_goc + 997) - rut_TLN = tron-mang(rut_TLN, seed_goc + 1009) - rut_TL = tron-mang(rut_TL, seed_goc + 1013) + rut_NLC = tron-mang(rut_NLC, seed-goc + 991) + rut_tf = tron-mang(rut_tf, seed-goc + 997) + rut_TLN = tron-mang(rut_TLN, seed-goc + 1009) + rut_TL = tron-mang(rut_TL, seed-goc + 1013) for (i, ma_de) in info.ds_ma_de.enumerate() { let is_first = (i == 0) @@ -1063,11 +1063,11 @@ final_bank, fake_matrix, info, - is_first: is_first, - show_lg: show_lg, - tf_mode: "y_only", - nlc_mode: "none", - theo_lv: false, + is-first: is_first, + show-lg: show-lg, + tf-mode: "y_only", + nlc-mode: "none", + theo-lv: false, ) if i < info.ds_ma_de.len() - 1 { @@ -1075,7 +1075,7 @@ } } - if hienthi_bangdapan { + if hienthi-bangdapan { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -1113,7 +1113,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in_dapan_TL(results) + in-dapan-tl(results) } } @@ -1137,15 +1137,15 @@ } } -#let tron_de_cungNoiDung( +#let tron-de-cung-noi-dung( banks_matrix, info, - seed_goc: 2024, - show_lg: false, - hienthi_bangdapan: true, - xao_cau: true, - xao_pa: true, - theo_lv: false, + seed-goc: 2024, + show-lg: false, + hienthi-bangdapan: true, + xao-cau: true, + xao-pa: true, + theo-lv: false, ) = { let rut_NLC = () let rut_tf = () @@ -1154,30 +1154,30 @@ for (b_idx, item) in banks_matrix.enumerate() { let b = item.bank - let NLC_seed = seed_goc * 999999 + b_idx * 999999 + 107 - let tf_seed = seed_goc * 999999 + b_idx * 999999 + 233 - let TLN_seed = seed_goc * 999999 + b_idx * 999999 + 357 - let TL_seed = seed_goc * 999999 + b_idx * 999999 + 491 - - if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + let NLC_seed = seed-goc * 999999 + b_idx * 999999 + 107 + let tf_seed = seed-goc * 999999 + b_idx * 999999 + 233 + let TLN_seed = seed-goc * 999999 + b_idx * 999999 + 357 + let TL_seed = seed-goc * 999999 + b_idx * 999999 + 491 + + if "NLC_dem" in item { rut_NLC += rut-cau-level(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut-cau-level(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut-cau-level(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut-cau-level(b, "TL", item.TL_dem, TL_seed) } } - rut_NLC = tron-mang(rut_NLC, seed_goc + 991) - rut_tf = tron-mang(rut_tf, seed_goc + 997) - rut_TLN = tron-mang(rut_TLN, seed_goc + 1009) - rut_TL = tron-mang(rut_TL, seed_goc + 1013) + rut_NLC = tron-mang(rut_NLC, seed-goc + 991) + rut_tf = tron-mang(rut_tf, seed-goc + 997) + rut_TLN = tron-mang(rut_TLN, seed-goc + 1009) + rut_TL = tron-mang(rut_TL, seed-goc + 1013) for (i, ma_de) in info.ds_ma_de.enumerate() { let is_first = (i == 0) let base_seed = int(ma_de) - let final_NLC = if xao_cau { xao-theo-tuy-chon(rut_NLC, base_seed + 2001, theo_lv: theo_lv) } else { rut_NLC } - let final_tf = if xao_cau { xao-theo-tuy-chon(rut_tf, base_seed + 2011, theo_lv: theo_lv) } else { rut_tf } - let final_TLN = if xao_cau { xao-theo-tuy-chon(rut_TLN, base_seed + 2027, theo_lv: theo_lv) } else { rut_TLN } - let final_TL = if xao_cau { xao-theo-tuy-chon(rut_TL, base_seed + 2039, theo_lv: theo_lv) } else { rut_TL } + let final_NLC = if xao-cau { xao-theo-tuy-chon(rut_NLC, base_seed + 2001, theo-lv: theo-lv) } else { rut_NLC } + let final_tf = if xao-cau { xao-theo-tuy-chon(rut_tf, base_seed + 2011, theo-lv: theo-lv) } else { rut_tf } + let final_TLN = if xao-cau { xao-theo-tuy-chon(rut_TLN, base_seed + 2027, theo-lv: theo-lv) } else { rut_TLN } + let final_TL = if xao-cau { xao-theo-tuy-chon(rut_TL, base_seed + 2039, theo-lv: theo-lv) } else { rut_TL } let final_bank = final_NLC + final_tf + final_TLN + final_TL @@ -1197,9 +1197,9 @@ final_bank, fake_matrix, info, - is_first: is_first, - show_lg: show_lg, - theo_lv: theo_lv, + is-first: is_first, + show-lg: show-lg, + theo-lv: theo-lv, ) if i < info.ds_ma_de.len() - 1 { @@ -1207,7 +1207,7 @@ } } - if hienthi_bangdapan { + if hienthi-bangdapan { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -1245,7 +1245,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in_dapan_TL(results) + in-dapan-tl(results) } } @@ -1279,11 +1279,11 @@ ) } -#let dang(title, STT: "1", kieu: "Dạng") = [ +#let dang(title, stt: "1", kieu: "Dạng") = [ #grid( columns: (auto, 1fr), align: center + horizon, column-gutter: -2pt, box(fill: rgb("#72f0b1a2"), radius: 8pt, inset: (x: 10pt, y: 10pt), stroke: 2pt + rgb("#72f0b1a2"))[ - #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #STT:]) + #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #stt:]) ], box(fill: rgb("#6ff6e484"), width: 100%, radius: 8pt, inset: (x: 15pt, y: 10pt), stroke: 2pt + rgb("#6ff6e484"))[ #text(weight: "bold", fill: rgb("#e90335f8"), size: 1.4em)[#title] @@ -1346,6 +1346,6 @@ // 7. BÍ DANH TIẾNG ANH (API CHUẨN UNIVERSE) // ========================================== #let exercise = baitap_inline -#let make-exam-matrix = tron_de_bankLevel -#let make-exam-sync = tron_de_cungNoiDung -#let make-exam-sub-only = tron_de_chiY +#let make-exam-matrix = tron-de-bank-level +#let make-exam-sync = tron-de-cung-noi-dung +#let make-exam-sub-only = tron-de-chi-y From f09f8cb77eaa3e708dd3fdb797b5ac771af4ac0f Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 10:30:02 +0700 Subject: [PATCH 11/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 85 +++++++++++++------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index edb46d251b..6f10a40786 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -1,4 +1,4 @@ -# v-exam +# v-exam: 0.1.0 Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề thi trắc nghiệm / tự luận chuẩn định dạng Bộ Giáo dục & Đào tạo Việt Nam dành cho mọi môn học (Toán, Vật lý, Hóa học, Sinh học, Lịch sử, Địa lý, GDKT&PL, ...). @@ -15,9 +15,9 @@ Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề ## 🖼️ Mẫu kết quả (Gallery)

- Đề thi mẫu
- Bảng đáp án
- Mã QRcode dùng cho máy chấm + Đề thi mẫu
+ Bảng đáp án
+ Mã QRcode dùng cho máy chấm

## 📦 Hướng dẫn sử dụng @@ -65,7 +65,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D lg: [Lời giải cho câu hỏi 2],) - ), + ),), // Câu hỏi đúng sai ( type: "TF", @@ -92,7 +92,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction nd: [Lời dẫn của của câu hỏi], da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," lg:[Lời giải cho bài toán], - dong_ke: so_dong_ke, + dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải ), //Câu hỏi trắc lời ngắn dạng chùm // Câu hỏi chùm trắc nghiệm nhiều lựa chọn. @@ -100,21 +100,24 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction type: "TLN", hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - is_chum:true, - du_kien:[Nội dung dùng chung], + is-chum:true, + du-kien:[Nội dung dùng chung], cau_hoi_con:( // Câu hỏi con 1. (nd: [Nội dung lời dẫn câu hỏi 1], da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," lg:[Lời giải cho bài toán], - dong_ke: so_dong_ke,), + dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải + ), // Câu hỏi con 2. (nd: [Nội dung lời dẫn câu hỏi 2], pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," lg:[Lời giải cho bài toán], - dong_ke: so_dong_ke,), + dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải +), ), +), //Câu hỏi tự luận ( type: "TL", @@ -122,25 +125,25 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng nd: [Lời dẫn của của câu hỏi], lg:[Lời giải cho bài toán], - dong_ke: so_dong_ke, + dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải ), ) ``` -### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `baitap_inline`) +### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `baitap-inline`) ```typst #import "file.typ" as b // code tạo bài tập. #exercise( b.data, cm: 1, - num_nlc: (1, 0, 0), - num_tf: (0, 1, 0), - num_tln: (0,1,2), - show_lg: true, + num-nlc: (1, 0, 0), + num-tf: (0, 1, 0), + num-tln: (0,1,2), + show-lg: true, seed: 123, - theo_lv:true, - dong_ke:4 + theo-lv:true, + dong-ke:4 ) ``` @@ -153,67 +156,67 @@ Tạo các đề thi tư ngân hàng với các lấy ngẫu nhiên các câu h #let matrix = ( ( bank: b.data, - NLC_dem: (1, 0, 0), - tf_dem: (0, 1, 0), - tln_dem: (0, 1, 0), - tl_dem: (0, 1, 0), + NLC-dem: (1, 0, 0), + tf-dem: (0, 1, 0), + tln-dem: (0, 1, 0), + tl-dem: (0, 1, 0), ), ) ``` **- Tạo thông tin bài kiểm tra** ```typst #let info = ( - so_gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], + so-gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], truong: [TRƯỜNG THPT NGHĨA HÀNH], - ky_thi: [KIỂM TRA GIỮA KỲ I], + ky-thi: [KIỂM TRA GIỮA KỲ I], mon: [VẬT LÝ 12], - thoi_gian: [45 phút], - ds_ma_de: ("101", "102", "103", "104"), + thoi-gian: [45 phút], + ds-ma-de: ("101", "102", "103", "104"), ) ``` **- Thực hiện lên trộn đề:** ```typst Cách 1: -#make-exam-matrix(matrix, info, show_lg: false, hienthi_bangdapan: true, theo_lv:true) +#make-exam-matrix(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv:true) Cách 2: -#tron_de_bankLevel(matrix, info, show_lg: false, hienthi_bangdapan: true, theo_lv:true) +#tron-de-bankLevel(matrix, info, show-g: false, hienthi-bangdapan: true, theo-lv:true) ``` Giải thích: - matrix: là nơi cấu hình cách lấy câu hỏi từ bank để đưa vào đề. - info: nội dung hiển thị tiêu đề của của bài kiểm tra và các mã đề của đề -- show_lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. +- show-lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. - hienthi_bangdapan: có hai chức năng: (1) hiển thị bảng đáp án (true) cuối file để dùng trong chấm bài; (2) không hiển thị bảng đáp án (false) đảm bào đề tạo ra không có bản đáp án. -- theo_lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. +- theo-lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. #### b) chức năng trộn đề tạo các đề giống nhau (`make-exam-sync` / `tron_de_cungNoiDung`) Cách thực hiện đuề giống với "Trộn đề thi khác nhau" chỉ khác ở mục thực hiện trộn đề khi gọi lệnh: ```typst Cách 1: -#make-exam-sync(matrix, info, seed_goc: 2026, show_lg: false,theo_lv:false,xao_cau: true, xao_pa: true) +#make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) Cách 2: -#tron_de_cungNoiDung(matrix, info, seed_goc: 2026, show_lg: false,theo_lv:false,xao_cau: true, xao_pa: true) +#tron-de-cungNoiDung(matrix, info, seed-goc: 2026, show_lg: false,theo-lv:false,xao-cau: true, xao-pa: true) ``` Giải thích: -- seed_goc: 2026 dùng để ấn định một seed được chon để tạo đề gốc ban đầu sau đó căn cứ theo mã đề để xáo cho hợp lý -- show_lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. +- seed-goc: 2026 dùng để ấn định một seed được chon để tạo đề gốc ban đầu sau đó căn cứ theo mã đề để xáo cho hợp lý +- show-lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. - hienthi_bangdapan: có hai chức năng: (1) hiển thị bảng đáp án (true) cuối file để dùng trong chấm bài; (2) không hiển thị bảng đáp án (false) đảm bào đề tạo ra không có bản đáp án. -- theo_lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. -- xao_cau: cho phép cố định câu không đổi vị trí câu ở các đề (false), đảo vị trí ở các đề (true) -- xao_pa: cho phép cố định phương án ABCD hoặc ý abcd ở các đề (false), đảo vị trí phương án ở các đề (true) +- theo-lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. +- xao-cau: cho phép cố định câu không đổi vị trí câu ở các đề (false), đảo vị trí ở các đề (true) +- xao-pa: cho phép cố định phương án ABCD hoặc ý abcd ở các đề (false), đảo vị trí phương án ở các đề (true) #### c) chức năng trộn đề ý hoặc phương án(`make-exam-sub-only` / `tron_de_chiY`) Cách thực hiện đuề giống với "Trộn đề cùng nội dung" chỉ khác ở mục thực hiện trộn đề khi gọi lệnh: ```typst Cách 1: -#make-exam-sub-only(matrix_con, info_de, seed_goc: 2024, show_lg: false,tf_mode:"y_only",nlc_mode:"none",theo_lv:false) +#make-exam-sub-only(matrix, info-de, seed-goc: 2024, show-lg: false,tf-mode:"y-only",nlc-mode:"none",theo-lv:false) Cách 2: -#tron_de_chiY(matrix_con, info_de, seed_goc: 2024, show_lg: false,tf_mode:"y_only",nlc_mode:"none",theo_lv:false) +#tron-de-chiY(matrix, info, seed-goc: 2024, show-lg: false,tf-mode:"y-only",nlc-mode:"none",theo-lv:false) ``` Giải thích: -- tf_mode: có hai chế độ "y_only" đảo ý và "full" đảo ý và đảo câu. -- nlc_mode: có 3 chế độ: "y_only" đảo phương án; "full" đảo phương án và đảo câu; "none" không thay đổi. +- tf-mode: có hai chế độ "y-only" đảo ý và "full" đảo ý và đảo câu. +- nlc-mode: có 3 chế độ: "y-only" đảo phương án; "full" đảo phương án và đảo câu; "none" không thay đổi. --- ## 📜 Giấy phép From b2e6eb07802be8fc530aec421259bd6541be9804 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 10:30:49 +0700 Subject: [PATCH 12/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 6f10a40786..e4f6b6f85c 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -196,7 +196,7 @@ Cách 1: #make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) Cách 2: -#tron-de-cungNoiDung(matrix, info, seed-goc: 2026, show_lg: false,theo-lv:false,xao-cau: true, xao-pa: true) +#tron-de-cungNoiDung(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) ``` Giải thích: - seed-goc: 2026 dùng để ấn định một seed được chon để tạo đề gốc ban đầu sau đó căn cứ theo mã đề để xáo cho hợp lý From ed0b91d793fd910ee46bda3e25ffbdf7e730f06f Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 10:51:57 +0700 Subject: [PATCH 13/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index e4f6b6f85c..c25885c1a8 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -50,8 +50,8 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction type: "NLC", hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - is_chum:true, - du_kien:[Nội dung dùng chung], + is-chum:true, + du-kien:[Nội dung dùng chung], cau_hoi_con:( // Câu hỏi con 1. (nd: [Nội dung lời dẫn câu hỏi 1], From bf38331ac7548022e6124a3034c03a67f6f5345a Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 10:53:08 +0700 Subject: [PATCH 14/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index c25885c1a8..9df73430cb 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -52,7 +52,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng is-chum:true, du-kien:[Nội dung dùng chung], - cau_hoi_con:( + cau-hoi-con:( // Câu hỏi con 1. (nd: [Nội dung lời dẫn câu hỏi 1], pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), @@ -102,7 +102,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng is-chum:true, du-kien:[Nội dung dùng chung], - cau_hoi_con:( + cau-hoi-con:( // Câu hỏi con 1. (nd: [Nội dung lời dẫn câu hỏi 1], da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," @@ -148,7 +148,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction ``` ### 4. Trộn đề thi -#### a) Trộn đề thi khác nhau(`make-exam-matrix` / `tron_de_bankLevel`) +#### a) Trộn đề thi khác nhau(`make-exam-matrix` / `tron-de-bankLevel`) Tạo các đề thi tư ngân hàng với các lấy ngẫu nhiên các câu hỏi từ bank để tạo bộ câu hỏi khác nhau cho mỗi đề\ **- Import ngân hàng câu hỏi để trộn đề và tạo bank** ```typst From b8b7a1dbddccd8725165903d326c2221d7442415 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 11:01:25 +0700 Subject: [PATCH 15/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 154 +++++++++++++------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 6d63a5b66d..b798c59a26 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -220,16 +220,16 @@ num-tl: none, show-lg: false, dong-ke: none, - co-nlc: none, + co-NLC: none, co-tf: none, - co-tln: none, - co-tl: none, + co-TLN: none, + co-TL: none, theo-lv: false, ) = { - let cfg_nlc = if num-nlc != none { num-nlc } else { co-nlc } + let cfg_nlc = if num-nlc != none { num-nlc } else { co-NLC } let cfg_tf = if num-tf != none { num-tf } else { co-tf } - let cfg_tln = if num-tln != none { num-tln } else { co-tln } - let cfg_tl = if num-tl != none { num-tl } else { co-tl } + let cfg_tln = if num-tln != none { num-tln } else { co-TLN } + let cfg_tl = if num-tl != none { num-tl } else { co-TL } let actual_bank = if type(bank_data) == dictionary and "data" in bank_data { bank_data.data @@ -241,23 +241,23 @@ let std_bank = actual_bank.map(q => { if "cau_hoi_con" in q and type(q.cau_hoi_con) == array and q.cau_hoi_con.len() > 0 { - let is_c = q.at("is_chum", default: q.cau_hoi_con.len() > 1) - let dk = q.at("du_kien", default: none) + let is_c = q.at("is-chum", default: q.cau_hoi_con.len() > 1) + let dk = q.at("du-kien", default: none) let q_type = q.at("type", default: q.cau_hoi_con.at(0).at("type", default: "NLC")) let q_lv = q.at("lv", default: 1) ( type: q_type, lv: q_lv, - is_chum: is_c, - du_kien: dk, + is-chum: is_c, + du-kien: dk, cau_hoi_con: q.cau_hoi_con ) } else { ( type: q.at("type", default: "NLC"), lv: q.at("lv", default: 1), - is_chum: false, - du_kien: none, + is-chum: false, + du-kien: none, cau_hoi_con: (q,) ) } @@ -324,14 +324,14 @@ } let c_idx = 0 for item in ds_NLC { - if item.du_kien != none and item.du_kien != [] { + if item.du-kien != none and item.du-kien != [] { let n_sub = item.cau_hoi_con.len() let start_c = c_idx + 1 let end_c = c_idx + n_sub block(width: 100%, breakable: false)[ #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ #text(fill: mausac.cau_pa, weight: "bold")[Dữ kiện dùng cho từ Câu #start_c đến Câu #end_c:] \ - #v(0.1em) #item.du_kien + #v(0.1em) #item.du-kien ] ] } @@ -403,14 +403,14 @@ if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } let c_idx = 0 for item in ds_TF { - if item.du_kien != none and item.du_kien != [] { + if item.du-kien != none and item.du-kien != [] { let n_sub = item.cau_hoi_con.len() let start_c = c_idx + 1 let end_c = c_idx + n_sub block(width: 100%, breakable: false)[ #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ #text(fill: mausac.cau_pa, weight: "bold")[Dữ kiện dùng cho Câu #start_c đến Câu #end_c:] \ - #v(0.1em) #item.du_kien + #v(0.1em) #item.du-kien ] ] } @@ -455,14 +455,14 @@ if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } let c_idx = 0 for item in ds_TLN { - if item.du_kien != none and item.du_kien != [] { + if item.du-kien != none and item.du-kien != [] { let n_sub = item.cau_hoi_con.len() let start_c = c_idx + 1 let end_c = c_idx + n_sub block(width: 100%, breakable: false)[ #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ #text(fill: mausac.cau_pa, weight: "bold", style: "italic")[Dữ kiện dùng cho Câu #start_c đến Câu #end_c:] \ - #v(0.1em) #text(style: "italic")[#item.du_kien] + #v(0.1em) #text(style: "italic")[#item.du-kien] ] ] } @@ -490,7 +490,7 @@ ) #v(-0.4em) #let num_lines = if dong-ke == none or dong-ke == 0 { none - } else if "dong_ke" in q and q.dong_ke != none { q.dong_ke + } else if "dong-ke" in q and q.dong-ke != none { q.dong-ke } else { dong-ke } #if num_lines != none and type(num_lines) == int and num_lines > 0 { v(0.3em) @@ -536,7 +536,7 @@ #v(-0.8em) #if not show-lg [ #let num_lines = if dong-ke == none or dong-ke == 0 { none - } else if "dong_ke" in q and q.dong_ke != none { q.dong_ke + } else if "dong-ke" in q and q.dong-ke != none { q.dong-ke } else { dong-ke } #if num_lines != none and type(num_lines) == int and num_lines > 0 { v(0.3em) @@ -611,15 +611,15 @@ columns: (1.2fr, 1fr), gutter: 10pt, align(center)[ - #text(size: 11pt)[#info.so_gd] \ + #text(size: 11pt)[#info.so-gd] \ #text(size: 11pt)[#strong(info.truong)] \ #v(-0.5em) #line(length: 40%, stroke: 0.5pt) ], align(center)[ - #text(size: 11pt)[#strong(info.ky_thi)] \ + #text(size: 11pt)[#strong(info.ky-thi)] \ #text(size: 11pt)[Môn: #strong[#info.mon]] \ - #text(size: 10pt)[Thời gian: #emph[#info.thoi_gian]] + #text(size: 10pt)[Thời gian: #emph[#info.thoi-gian]] ] ) grid(columns: (1fr, auto), @@ -634,7 +634,7 @@ if s_NLC.len() > 0 { let tong_so_cau = s_NLC.fold(0, (acc, q) => { - if "is_chum" in q and q.is_chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } + if "is-chum" in q and q.is-chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) v(-0.1em) @@ -642,7 +642,7 @@ let c_idx = 0 for item in s_NLC { - let is_item_chum = "is_chum" in item and item.is_chum == true and "cau_hoi_con" in item + let is_item_chum = "is-chum" in item and item.is-chum == true and "cau_hoi_con" in item if is_item_chum { let n_sub = item.cau_hoi_con.len() let start_num = c_idx + 1 @@ -651,7 +651,7 @@ block(width: 100%, breakable: false)[ #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ #text(fill: mausac.cau_pa)[*Dữ kiện dùng cho từ Câu #start_num đến Câu #end_num:*] \ - #v(0.1em) #item.du_kien + #v(0.1em) #item.du-kien ] ] } @@ -708,7 +708,7 @@ v(0.5em); text(mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #s_tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] for (idx, q) in s_tf.enumerate() { let sub_indices = if tf-mode == "none" { range(4) } - else if tf-mode == "y_only" { + else if tf-mode == "y-only" { let content_str = repr(q.nd) + repr(q.ytf) let content_hash = calc.rem(content_str.len() * 265435761, 123456789) tron-mang(range(4), content_hash * 31 + int(ma_de) * 7919) @@ -735,13 +735,13 @@ if s_TLN.len() > 0 { let tong_so_cau = s_TLN.fold(0, (acc, q) => { - if "is_chum" in q and q.is_chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } + if "is-chum" in q and q.is-chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) v(0.5em); text(fill: mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong_so_cau.*] let c_idx = 0 for item in s_TLN { - let is_item_chum = "is_chum" in item and item.is_chum == true and "cau_hoi_con" in item + let is_item_chum = "is-chum" in item and item.is-chum == true and "cau_hoi_con" in item let ds_cau_can_ve = if is_item_chum { item.cau_hoi_con } else { (item,) } if is_item_chum { @@ -752,7 +752,7 @@ block(width: 100%, breakable: false)[ #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ #text(fill: mausac.cau_pa)[*Dữ kiện dùng cho từ Câu #start_num đến Câu #end_num:*] \ - #v(0.1em) #item.du_kien + #v(0.1em) #item.du-kien ] ] } @@ -816,7 +816,7 @@ )) ] } -#let in-dapan-tl(results) = { +#let in_dapan_TL(results) = { context { counter(page).update(1) set page(footer: none) @@ -851,15 +851,15 @@ }) } -#let rut-cau-level(raw_bank, q_type, dem_config, seed) = { +#let rut_cauLevel(raw_bank, q_type, dem_config, seed) = { let actual_bank = if type(raw_bank) == dictionary and "data" in raw_bank { raw_bank.data } else if type(raw_bank) == module { raw_bank.data } else { raw_bank } let loc_ques = actual_bank.filter(q => q.type == q_type) if loc_ques.len() == 0 { return () } - let bank_chum = loc_ques.filter(q => "is_chum" in q and q.is_chum == true) - let bank_don = loc_ques.filter(q => not ("is_chum" in q and q.is_chum == true)) + let bank_chum = loc_ques.filter(q => "is-chum" in q and q.is-chum == true) + let bank_don = loc_ques.filter(q => not ("is-chum" in q and q.is-chum == true)) let safe-slice(arr, req_count) = { if req_count <= 0 or arr.len() == 0 { return () } @@ -900,9 +900,9 @@ return res_chum + res_don } -#let tron-de-bank-level(banks_matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: false) = { - for (i, ma_de) in info.ds_ma_de.enumerate() { - let is_first = (i == 0) +#let tron-de-bankLevel(banks_matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: false) = { + for (i, ma_de) in info.ds-ma-de.enumerate() { + let is-first = (i == 0) let base_seed = int(ma_de) let rut_NLC = () @@ -917,10 +917,10 @@ let TLN_seed = base_seed * 999999 + b_idx * 999999 + 357 let TL_seed = base_seed * 999999 + b_idx * 999999 + 491 - if "NLC_dem" in item { rut_NLC += rut-cau-level(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut-cau-level(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut-cau-level(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut-cau-level(b, "TL", item.TL_dem, TL_seed) } + if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } } rut_NLC = xao-theo-tuy-chon(rut_NLC, base_seed + 991, theo-lv: theo-lv) @@ -941,9 +941,9 @@ TL_dem: rut_TL.len(), ) - render_test(ma_de, final_bank, fake_matrix, info, is-first: is_first, show-lg: show-lg, theo-lv: theo-lv) + render_test(ma_de, final_bank, fake_matrix, info, is-first: is-first, show-lg: show-lg, theo-lv: theo-lv) - if i < info.ds_ma_de.len() - 1 { + if i < info.ds-ma-de.len() - 1 { pagebreak(weak: true) } } @@ -960,11 +960,11 @@ let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() if total_q > 0 { table( - columns: (auto, ..info.ds_ma_de.map(_ => 1fr)), + columns: (auto, ..info.ds-ma-de.map(_ => 1fr)), align: center + horizon, stroke: 0.5pt, fill: (x, y) => if y == 0 { gray.lighten(80%) }, - [*Câu*], ..info.ds_ma_de.map(m => [*#m*]), + [*Câu*], ..info.ds-ma-de.map(m => [*#m*]), ..range(total_q).map(i => { let row = ([#(i+1)],) for entry in results { @@ -986,7 +986,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dapan-tl(results) + in_dapan_TL(results) } } @@ -1010,13 +1010,13 @@ } } -#let tron-de-chi-y( +#let tron-de-chiY( banks_matrix, info, seed-goc: 2024, show-lg: false, hienthi-bangdapan: true, - tf-mode: "y_only", + tf-mode: "y-only", nlc-mode: "full", theo-lv: false, ) = { @@ -1032,10 +1032,10 @@ let TLN_seed = seed-goc * 999999 + b_idx * 999999 + 357 let TL_seed = seed-goc * 999999 + b_idx * 999999 + 491 - if "NLC_dem" in item { rut_NLC += rut-cau-level(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut-cau-level(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut-cau-level(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut-cau-level(b, "TL", item.TL_dem, TL_seed) } + if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } } rut_NLC = tron-mang(rut_NLC, seed-goc + 991) @@ -1043,8 +1043,8 @@ rut_TLN = tron-mang(rut_TLN, seed-goc + 1009) rut_TL = tron-mang(rut_TL, seed-goc + 1013) - for (i, ma_de) in info.ds_ma_de.enumerate() { - let is_first = (i == 0) + for (i, ma_de) in info.ds-ma-de.enumerate() { + let is-first = (i == 0) let final_bank = rut_NLC + rut_tf + rut_TLN + rut_TL let fake_matrix = ( @@ -1063,14 +1063,14 @@ final_bank, fake_matrix, info, - is-first: is_first, + is-first: is-first, show-lg: show-lg, - tf-mode: "y_only", + tf-mode: "y-only", nlc-mode: "none", theo-lv: false, ) - if i < info.ds_ma_de.len() - 1 { + if i < info.ds-ma-de.len() - 1 { pagebreak(weak: true) } } @@ -1087,11 +1087,11 @@ let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() if total_q > 0 { table( - columns: (auto, ..info.ds_ma_de.map(_ => 1fr)), + columns: (auto, ..info.ds-ma-de.map(_ => 1fr)), align: center + horizon, stroke: 0.5pt, fill: (x, y) => if y == 0 { gray.lighten(80%) }, - [*Câu*], ..info.ds_ma_de.map(m => [*#m*]), + [*Câu*], ..info.ds-ma-de.map(m => [*#m*]), ..range(total_q).map(i => { let row = ([#(i+1)],) for entry in results { @@ -1113,7 +1113,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dapan-tl(results) + in_dapan_TL(results) } } @@ -1137,7 +1137,7 @@ } } -#let tron-de-cung-noi-dung( +#let tron-de-cungNoiDung( banks_matrix, info, seed-goc: 2024, @@ -1159,10 +1159,10 @@ let TLN_seed = seed-goc * 999999 + b_idx * 999999 + 357 let TL_seed = seed-goc * 999999 + b_idx * 999999 + 491 - if "NLC_dem" in item { rut_NLC += rut-cau-level(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut-cau-level(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut-cau-level(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut-cau-level(b, "TL", item.TL_dem, TL_seed) } + if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } + if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } + if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } + if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } } rut_NLC = tron-mang(rut_NLC, seed-goc + 991) @@ -1170,8 +1170,8 @@ rut_TLN = tron-mang(rut_TLN, seed-goc + 1009) rut_TL = tron-mang(rut_TL, seed-goc + 1013) - for (i, ma_de) in info.ds_ma_de.enumerate() { - let is_first = (i == 0) + for (i, ma_de) in info.ds-ma-de.enumerate() { + let is-first = (i == 0) let base_seed = int(ma_de) let final_NLC = if xao-cau { xao-theo-tuy-chon(rut_NLC, base_seed + 2001, theo-lv: theo-lv) } else { rut_NLC } @@ -1197,12 +1197,12 @@ final_bank, fake_matrix, info, - is-first: is_first, + is-first: is-first, show-lg: show-lg, theo-lv: theo-lv, ) - if i < info.ds_ma_de.len() - 1 { + if i < info.ds-ma-de.len() - 1 { pagebreak(weak: true) } } @@ -1219,11 +1219,11 @@ let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() if total_q > 0 { table( - columns: (auto, ..info.ds_ma_de.map(_ => 1fr)), + columns: (auto, ..info.ds-ma-de.map(_ => 1fr)), align: center + horizon, stroke: 0.5pt, fill: (x, y) => if y == 0 { gray.lighten(80%) }, - [*Câu*], ..info.ds_ma_de.map(m => [*#m*]), + [*Câu*], ..info.ds-ma-de.map(m => [*#m*]), ..range(total_q).map(i => { let row = ([#(i+1)],) for entry in results { @@ -1245,7 +1245,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dapan-tl(results) + in_dapan_TL(results) } } @@ -1279,11 +1279,11 @@ ) } -#let dang(title, stt: "1", kieu: "Dạng") = [ +#let dang(title, STT: "1", kieu: "Dạng") = [ #grid( columns: (auto, 1fr), align: center + horizon, column-gutter: -2pt, box(fill: rgb("#72f0b1a2"), radius: 8pt, inset: (x: 10pt, y: 10pt), stroke: 2pt + rgb("#72f0b1a2"))[ - #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #stt:]) + #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #STT:]) ], box(fill: rgb("#6ff6e484"), width: 100%, radius: 8pt, inset: (x: 15pt, y: 10pt), stroke: 2pt + rgb("#6ff6e484"))[ #text(weight: "bold", fill: rgb("#e90335f8"), size: 1.4em)[#title] @@ -1346,6 +1346,6 @@ // 7. BÍ DANH TIẾNG ANH (API CHUẨN UNIVERSE) // ========================================== #let exercise = baitap_inline -#let make-exam-matrix = tron-de-bank-level -#let make-exam-sync = tron-de-cung-noi-dung -#let make-exam-sub-only = tron-de-chi-y +#let make-exam-matrix = tron-de-bankLevel +#let make-exam-sync = tron-de-cungNoiDung +#let make-exam-sub-only = tron-de-chiY From c5f6b18a3dff708a0fb66e9737ad1030f629a67f Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 12:18:21 +0700 Subject: [PATCH 16/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 908 +++++++++++++------------- 1 file changed, 454 insertions(+), 454 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index b798c59a26..5d5fc612b8 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -29,7 +29,7 @@ #let mausac = ( lg : rgb("#a8f6f13c"), duong: rgb("#0057b8"), - cau_pa: rgb("#1505f2"), + cau-pa: rgb("#1505f2"), daT: rgb("#f3072a") ) @@ -80,12 +80,12 @@ let nhom1 = arr.filter(q => get-lv(q) == 1) let nhom2 = arr.filter(q => get-lv(q) == 2) let nhom3 = arr.filter(q => get-lv(q) == 3) - let nhom_khac = arr.filter(q => { + let nhom-khac = arr.filter(q => { let lv = get-lv(q) lv != 1 and lv != 2 and lv != 3 }) - return tron-mang(nhom1, seed + 11) + tron-mang(nhom2, seed + 22) + tron-mang(nhom3, seed + 33) + tron-mang(nhom_khac, seed + 44) + return tron-mang(nhom1, seed + 11) + tron-mang(nhom2, seed + 22) + tron-mang(nhom3, seed + 33) + tron-mang(nhom-khac, seed + 44) } #let xao-theo-tuy-chon(arr, seed, theo-lv: false) = { @@ -100,18 +100,18 @@ // 3. HÀM TẠO QR & HIỂN THỊ LỜI GIẢI // ========================================== #let tao-QRcode-key(results) = { - let all_content = "" + let all-content = "" for entry in results { - let ma_de = str(entry.value.seed) + let ma-de = str(entry.value.seed) let part1 = entry.value.part1.join("") let part2 = entry.value.part2.join("") let part3 = entry.value.part3.map(str).join("|") - all_content += ma_de + "\n" + part1 + "\n" + part2 + "\n" + part3 + "\n" + all-content += ma-de + "\n" + part1 + "\n" + part2 + "\n" + part3 + "\n" } - return all_content + return all-content } -#let hienthi-lg(q, q_type, idx, seed, opt_indices: none, tf_indices: none) = { +#let hienthi-lg(q, q-type, idx, seed, opt-indices: none, tf-indices: none) = { toan-setup({ v(-0.4em) block( @@ -122,34 +122,34 @@ stroke: (left: 2pt + mausac.duong) )[ #v(0.2em) - #if q_type == "NLC" { - let correct_idx = if opt_indices != none { opt_indices.position(i => i == q.da) } else { q.da } - text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #to-abc(correct_idx)*\ ] + #if q-type == "NLC" { + let correct-idx = if opt-indices != none { opt-indices.position(i => i == q.da) } else { q.da } + text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #to-abc(correct-idx)*\ ] text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[*Lời giải:*] - } else if q_type == "TF" or q_type == "tf" { - let correct_ans = if tf_indices != none { to-ds(tf_indices.map(i => q.da.at(i))) } else { to-ds(q.da) } - text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #correct_ans*\ ] + } else if q-type == "TF" or q-type == "tf" { + let correct-ans = if tf-indices != none { to-ds(tf-indices.map(i => q.da.at(i))) } else { to-ds(q.da) } + text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #correct-ans*\ ] text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[ *Lời giải:*] - } else if q_type == "TLN" { + } else if q-type == "TLN" { text(fill: blue.darken(100%), size: 11pt)[*Kết quả: #q.da*] text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[\ *Lời giải:*] - } else if q_type == "TL" { + } else if q-type == "TL" { text(fill: red.darken(0%), weight: "bold", font: "UTM A&S Graceland", size: 16pt)[*Lời giải:*] } - #if (q_type == "TF" or q_type == "tf") and type(q.lg) == array { - let indices = if tf_indices != none { tf_indices } else { range(q.lg.len()) } + #if (q-type == "TF" or q-type == "tf") and type(q.lg) == array { + let indices = if tf-indices != none { tf-indices } else { range(q.lg.len()) } let labels = ("a)", "b)", "c)", "d)") list( marker: none, spacing: 0.7em, - ..indices.enumerate().map(((new_i, orig_i)) => { - let is_true = q.da.at(orig_i) == 1 - let status_str = if is_true { "Đúng" } else { "Sai" } - let lg_content = if orig_i < q.lg.len() { q.lg.at(orig_i) } else { [] } + ..indices.enumerate().map(((new-i, orig-i)) => { + let is-true = q.da.at(orig-i) == 1 + let status-str = if is-true { "Đúng" } else { "Sai" } + let lg-content = if orig-i < q.lg.len() { q.lg.at(orig-i) } else { [] } - [#text(fill: mausac.cau_pa, weight: "bold")[#labels.at(new_i) - #status_str:] #text(fill: blue.darken(100%), style: "italic")[#lg_content]] + [#text(fill: mausac.cau-pa, weight: "bold")[#labels.at(new-i) - #status-str:] #text(fill: blue.darken(100%), style: "italic")[#lg-content]] }) ) } else { @@ -163,7 +163,7 @@ // ========================================== // 4. BÀI TẬP INLINE / ÔN TẬP TÀI LIỆU // ========================================== -#let render_sub_sol(q, type_str, show-lg) = { +#let render-sub-sol(q, type-str, show-lg) = { if not show-lg { return } v(-0.8em) block( @@ -175,11 +175,11 @@ breakable: true )[ #set par(leading: 0.65em) - #if type_str == "NLC" [ + #if type-str == "NLC" [ #text(fill: mausac.duong, weight: "bold")[► Lời giải: \ ] #if "lg" in q and q.lg != none and q.lg != [] [ #q.lg ] else [ Chưa có lời giải.] ] - #if type_str == "TF" [ + #if type-str == "TF" [ #text(fill: mausac.duong, weight: "bold")[► Đáp án:] #text(fill: mausac.daT, weight: "bold")[#to-ds(q.da)] \ #if "lg" in q and q.lg != none and q.lg != [] [ #if type(q.lg) == array [ @@ -187,10 +187,10 @@ #list( marker: none, spacing: 0.7em, - ..q.lg.enumerate().map(((i, lg_item)) => { - let is_true = q.da.at(i) == 1 - let status_str = if is_true { "Đúng" } else { "Sai" } - [#text(fill: mausac.cau_pa, weight: "bold")[#labels.at(i) #status_str]\ #lg_item] + ..q.lg.enumerate().map(((i, lg-item)) => { + let is-true = q.da.at(i) == 1 + let status-str = if is-true { "Đúng" } else { "Sai" } + [#text(fill: mausac.cau-pa, weight: "bold")[#labels.at(i) #status-str]\ #lg-item] }) ) ] else [ @@ -198,20 +198,20 @@ ] ] else [ Chưa có lời giải.] ] - #if type_str == "TLN" [ + #if type-str == "TLN" [ #text(fill: mausac.duong, weight: "bold")[► Kết quả:] #text(fill: mausac.daT, weight: "bold")[#q.da] \ #if "lg" in q and q.lg != none and q.lg != [] [ #v(0.01em)#q.lg #v(0.2em)] else [ Chưa có lời giải.] ] - #if type_str == "TL" [ + #if type-str == "TL" [ #text(fill: mausac.duong, weight: "bold")[► Lời giải chi tiết:] \ #if "lg" in q and q.lg != none and q.lg != [] [ #q.lg ] else [ Chưa có lời giải.] ] ] } -#let baitap_inline( +#let baitap-inline( cm: 1, - bank_data, + bank-data, title: none, seed: 0, num-nlc: none, @@ -226,31 +226,31 @@ co-TL: none, theo-lv: false, ) = { - let cfg_nlc = if num-nlc != none { num-nlc } else { co-NLC } - let cfg_tf = if num-tf != none { num-tf } else { co-tf } - let cfg_tln = if num-tln != none { num-tln } else { co-TLN } - let cfg_tl = if num-tl != none { num-tl } else { co-TL } - - let actual_bank = if type(bank_data) == dictionary and "data" in bank_data { - bank_data.data - } else if type(bank_data) == module { - bank_data.data + let cfg-nlc = if num-nlc != none { num-nlc } else { co-NLC } + let cfg-tf = if num-tf != none { num-tf } else { co-tf } + let cfg-tln = if num-tln != none { num-tln } else { co-TLN } + let cfg-tl = if num-tl != none { num-tl } else { co-TL } + + let actual-bank = if type(bank-data) == dictionary and "data" in bank-data { + bank-data.data + } else if type(bank-data) == module { + bank-data.data } else { - bank_data + bank-data } - let std_bank = actual_bank.map(q => { - if "cau_hoi_con" in q and type(q.cau_hoi_con) == array and q.cau_hoi_con.len() > 0 { - let is_c = q.at("is-chum", default: q.cau_hoi_con.len() > 1) + let std-bank = actual-bank.map(q => { + if "cau-hoi-con" in q and type(q.cau-hoi-con) == array and q.cau-hoi-con.len() > 0 { + let is-c = q.at("is-chum", default: q.cau-hoi-con.len() > 1) let dk = q.at("du-kien", default: none) - let q_type = q.at("type", default: q.cau_hoi_con.at(0).at("type", default: "NLC")) - let q_lv = q.at("lv", default: 1) + let q-type = q.at("type", default: q.cau-hoi-con.at(0).at("type", default: "NLC")) + let q-lv = q.at("lv", default: 1) ( - type: q_type, - lv: q_lv, - is-chum: is_c, + type: q-type, + lv: q-lv, + is-chum: is-c, du-kien: dk, - cau_hoi_con: q.cau_hoi_con + cau-hoi-con: q.cau-hoi-con ) } else { ( @@ -258,55 +258,55 @@ lv: q.at("lv", default: 1), is-chum: false, du-kien: none, - cau_hoi_con: (q,) + cau-hoi-con: (q,) ) } }) - let rut_cau(q_type, dem_config, sub_seed) = { - let loc_ques = std_bank.filter(q => q.type == q_type) - if loc_ques.len() == 0 or dem_config == none or dem_config == 0 { return () } + let rut-cau(q-type, dem-config, sub-seed) = { + let loc-ques = std-bank.filter(q => q.type == q-type) + if loc-ques.len() == 0 or dem-config == none or dem-config == 0 { return () } - let get_q_lv(item) = { + let get-q-lv(item) = { if "lv" in item { item.lv } - else if item.cau_hoi_con.len() > 0 and "lv" in item.cau_hoi_con.at(0) { item.cau_hoi_con.at(0).lv } + else if item.cau-hoi-con.len() > 0 and "lv" in item.cau-hoi-con.at(0) { item.cau-hoi-con.at(0).lv } else { 1 } } - if type(dem_config) == int { - let processing = if seed == none { loc_ques } else { xao-theo-tuy-chon(loc_ques, seed + sub_seed, theo-lv: theo-lv) } - return processing.slice(0, calc.min(dem_config, processing.len())) + if type(dem-config) == int { + let processing = if seed == none { loc-ques } else { xao-theo-tuy-chon(loc-ques, seed + sub-seed, theo-lv: theo-lv) } + return processing.slice(0, calc.min(dem-config, processing.len())) } - if type(dem_config) == array { - let nb_req = dem_config.at(0, default: 0) - let th_req = dem_config.at(1, default: 0) - let vd_req = dem_config.at(2, default: 0) + if type(dem-config) == array { + let nb-req = dem-config.at(0, default: 0) + let th-req = dem-config.at(1, default: 0) + let vd-req = dem-config.at(2, default: 0) - let b_nb = loc_ques.filter(q => get_q_lv(q) == 1) - let b_th = loc_ques.filter(q => get_q_lv(q) == 2) - let b_vd = loc_ques.filter(q => get_q_lv(q) == 3) + let b-nb = loc-ques.filter(q => get-q-lv(q) == 1) + let b-th = loc-ques.filter(q => get-q-lv(q) == 2) + let b-vd = loc-ques.filter(q => get-q-lv(q) == 3) if seed != none { - b_nb = tron-mang(b_nb, seed + sub_seed + 11) - b_th = tron-mang(b_th, seed + sub_seed + 22) - b_vd = tron-mang(b_vd, seed + sub_seed + 33) + b-nb = tron-mang(b-nb, seed + sub-seed + 11) + b-th = tron-mang(b-th, seed + sub-seed + 22) + b-vd = tron-mang(b-vd, seed + sub-seed + 33) } - let res_nb = b_nb.slice(0, calc.min(nb_req, b_nb.len())) - let res_th = b_th.slice(0, calc.min(th_req, b_th.len())) - let res_vd = b_vd.slice(0, calc.min(vd_req, b_vd.len())) + let res-nb = b-nb.slice(0, calc.min(nb-req, b-nb.len())) + let res-th = b-th.slice(0, calc.min(th-req, b-th.len())) + let res-vd = b-vd.slice(0, calc.min(vd-req, b-vd.len())) - return res_nb + res_th + res_vd + return res-nb + res-th + res-vd } - return loc_ques + return loc-ques } - let ds_NLC = rut_cau("NLC", cfg_nlc, 107) - let ds_TF = rut_cau("TF", cfg_tf, 233) - let ds_TLN = rut_cau("TLN", cfg_tln, 357) - let ds_TL = rut_cau("TL", cfg_tl, 491) + let ds-NLC = rut-cau("NLC", cfg-nlc, 107) + let ds-TF = rut-cau("TF", cfg-tf, 233) + let ds-TLN = rut-cau("TLN", cfg-tln, 357) + let ds-TL = rut-cau("TL", cfg-tl, 491) toan-setup({ if title != none and title != "" { @@ -316,169 +316,169 @@ } // PHẦN I: NLC - if ds_NLC.len() > 0 { + if ds-NLC.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) if cm == 1 { - text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẮC NGHIỆM NHIỀU LỰA CHỌN] + text(fill: mausac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẮC NGHIỆM NHIỀU LỰA CHỌN] } - let c_idx = 0 - for item in ds_NLC { + let c-idx = 0 + for item in ds-NLC { if item.du-kien != none and item.du-kien != [] { - let n_sub = item.cau_hoi_con.len() - let start_c = c_idx + 1 - let end_c = c_idx + n_sub + let n-sub = item.cau-hoi-con.len() + let start-c = c-idx + 1 + let end-c = c-idx + n-sub block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau_pa, weight: "bold")[Dữ kiện dùng cho từ Câu #start_c đến Câu #end_c:] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau-pa, weight: "bold")[Dữ kiện dùng cho từ Câu #start-c đến Câu #end-c:] \ #v(0.1em) #item.du-kien ] ] } - for q in item.cau_hoi_con { - c_idx += 1 + for q in item.cau-hoi-con { + c-idx += 1 v(-0.4em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 3pt, row-gutter: 8pt, align: (left + top, center + top), [ #v(-0.4em) - #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd \ + #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd \ #v(-0.3em) - #let is_img_option = q.pa.any(opt => { + #let is-img-option = q.pa.any(opt => { let r = repr(opt) r.contains("image(") or r.contains("cetz") or r.contains("canvas") }) - #if is_img_option [ - #let n_cols = if "cot" in q { q.cot } else { 4 } + #if is-img-option [ + #let n-cols = if "cot" in q { q.cot } else { 4 } #grid( - columns: (1fr,) * n_cols, + columns: (1fr,) * n-cols, column-gutter: 0.8em, row-gutter: 0.5em, align: center + horizon, ..q.pa.enumerate().map(((i, v)) => { - let is_correct = show-lg and ("da" in q) and (i == q.da) - let label_text = [#h(1em)*#to-abc(i).*] - let formatted_label = if is_correct { underline(text(fill: mausac.daT, weight: "bold")[#label_text]) } else { text(fill: mausac.cau_pa)[#label_text] } - align(left)[#grid(columns:(auto,1fr), column-gutter:10pt, [#formatted_label], [#v])] + let is-correct = show-lg and ("da" in q) and (i == q.da) + let label-text = [#h(1em)*#to-abc(i).*] + let formatted-label = if is-correct { underline(text(fill: mausac.daT, weight: "bold")[#label-text]) } else { text(fill: mausac.cau-pa)[#label-text] } + align(left)[#grid(columns:(auto,1fr), column-gutter:10pt, [#formatted-label], [#v])] }) ) ] else [ - #let n_cols = if "cot" in q { q.cot } else { 4 } + #let n-cols = if "cot" in q { q.cot } else { 4 } #grid( - columns: (1fr,) * n_cols, + columns: (1fr,) * n-cols, row-gutter: 0.95em, column-gutter: 0.1em, - align: if n_cols > 1 { left + horizon } else { left }, + align: if n-cols > 1 { left + horizon } else { left }, inset: (x: 1em), ..q.pa.enumerate().map(((i, v)) => { - let is_correct = show-lg and ("da" in q) and (i == q.da) - let label_text = [*#to-abc(i).*] - let formatted_label = if is_correct { underline(text(fill: mausac.daT, weight: "bold")[#label_text]) } else { text(fill: mausac.cau_pa)[#label_text] } - box[#grid(columns: (auto, 1fr), gutter: 2pt, align: left, formatted_label, v)] + let is-correct = show-lg and ("da" in q) and (i == q.da) + let label-text = [*#to-abc(i).*] + let formatted-label = if is-correct { underline(text(fill: mausac.daT, weight: "bold")[#label-text]) } else { text(fill: mausac.cau-pa)[#label-text] } + box[#grid(columns: (auto, 1fr), gutter: 2pt, align: left, formatted-label, v)] }) ) #v(0.5em) ] ], - if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } ] + if has-img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } ] ) ] v(-0.7em) - render_sub_sol(q, "NLC", show-lg) + render-sub-sol(q, "NLC", show-lg) } } } // PHẦN II: TF - if ds_TF.len() > 0 { + if ds-TF.len() > 0 { set par(first-line-indent: 0pt) v(-0.1em) - if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } - let c_idx = 0 - for item in ds_TF { + if cm == 1 { text(fill: mausac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } + let c-idx = 0 + for item in ds-TF { if item.du-kien != none and item.du-kien != [] { - let n_sub = item.cau_hoi_con.len() - let start_c = c_idx + 1 - let end_c = c_idx + n_sub + let n-sub = item.cau-hoi-con.len() + let start-c = c-idx + 1 + let end-c = c-idx + n-sub block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau_pa, weight: "bold")[Dữ kiện dùng cho Câu #start_c đến Câu #end_c:] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau-pa, weight: "bold")[Dữ kiện dùng cho Câu #start-c đến Câu #end-c:] \ #v(0.1em) #item.du-kien ] ] } - for q in item.cau_hoi_con { - c_idx += 1 + for q in item.cau-hoi-con { + c-idx += 1 v(-0.6em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + top), [ #v(0.2em) - #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd \ + #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd \ #list( marker: none, spacing: 0.7em, ..q.ytf.enumerate().map(((i, sq)) => { - let label_text = [#("a)", "b)", "c)", "d)").at(i)] - let formatted_label = text(fill: mausac.cau_pa, weight: "bold")[#h(0.5em) #label_text] - let ans_str = if show-lg and ("da" in q) and type(q.da) == array and i < q.da.len() { + let label-text = [#("a)", "b)", "c)", "d)").at(i)] + let formatted-label = text(fill: mausac.cau-pa, weight: "bold")[#h(0.5em) #label-text] + let ans-str = if show-lg and ("da" in q) and type(q.da) == array and i < q.da.len() { if q.da.at(i) == 1 { " [Đúng]" } else { " [Sai]" } } else { "" } - [#formatted_label #sq #text(fill: mausac.daT, weight: "bold")[#ans_str]] + [#formatted-label #sq #text(fill: mausac.daT, weight: "bold")[#ans-str]] }) ) ], - if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } ] + if has-img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } ] ) ] v(-0.8em) - render_sub_sol(q, "TF", show-lg) + render-sub-sol(q, "TF", show-lg) } } } // PHẦN III: TLN - if ds_TLN.len() > 0 { + if ds-TLN.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) - if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } - let c_idx = 0 - for item in ds_TLN { + if cm == 1 { text(fill: mausac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } + let c-idx = 0 + for item in ds-TLN { if item.du-kien != none and item.du-kien != [] { - let n_sub = item.cau_hoi_con.len() - let start_c = c_idx + 1 - let end_c = c_idx + n_sub + let n-sub = item.cau-hoi-con.len() + let start-c = c-idx + 1 + let end-c = c-idx + n-sub block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau_pa, weight: "bold", style: "italic")[Dữ kiện dùng cho Câu #start_c đến Câu #end_c:] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau-pa, weight: "bold", style: "italic")[Dữ kiện dùng cho Câu #start-c đến Câu #end-c:] \ #v(0.1em) #text(style: "italic")[#item.du-kien] ] ] } - for q in item.cau_hoi_con { - c_idx += 1 + for q in item.cau-hoi-con { + c-idx += 1 v(-0.8em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, row-gutter: 10pt, align: (left + top, center + horizon), [ #v(-0.1em) - #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd + #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd #v(0.1em) #if not show-lg [ #grid( @@ -489,58 +489,58 @@ [#(for i in range(4) { box(width: 1.2em, height: 1.2em, stroke: 0.4pt + gray.darken(80%), radius: 1pt); h(2pt) })] ) #v(-0.4em) - #let num_lines = if dong-ke == none or dong-ke == 0 { none + #let num-lines = if dong-ke == none or dong-ke == 0 { none } else if "dong-ke" in q and q.dong-ke != none { q.dong-ke } else { dong-ke } - #if num_lines != none and type(num_lines) == int and num_lines > 0 { + #if num-lines != none and type(num-lines) == int and num-lines > 0 { v(0.3em) - for i in range(num_lines) { + for i in range(num-lines) { v(0.4em) line(length: 100%, stroke: (dash: "dotted", thickness: 0.75pt, paint: gray.darken(80%))) } } ] ], - if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(0.2em)] + if has-img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(0.2em)] ) ] v(-0.4em) - render_sub_sol(q, "TLN", show-lg) + render-sub-sol(q, "TLN", show-lg) } } } // PHẦN IV: TL - if ds_TL.len() > 0 { + if ds-TL.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) - if cm == 1 { text(fill: mausac.cau_pa, weight: "bold", size: 11pt)[► BÀI TẬP TỰ LUẬN] } - let c_idx = 0 - for item in ds_TL { - for q in item.cau_hoi_con { - c_idx += 1 + if cm == 1 { text(fill: mausac.cau-pa, weight: "bold", size: 11pt)[► BÀI TẬP TỰ LUẬN] } + let c-idx = 0 + for item in ds-TL { + for q in item.cau-hoi-con { + c-idx += 1 v(-0.4em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + top), [ #v(-0.4em) - #text(fill: mausac.cau_pa, weight: "bold")[Câu #c_idx.] #q.nd + #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd #v(0.5em) ], - if has_img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(1em)] + if has-img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(1em)] ) #v(-0.8em) #if not show-lg [ - #let num_lines = if dong-ke == none or dong-ke == 0 { none + #let num-lines = if dong-ke == none or dong-ke == 0 { none } else if "dong-ke" in q and q.dong-ke != none { q.dong-ke } else { dong-ke } - #if num_lines != none and type(num_lines) == int and num_lines > 0 { + #if num-lines != none and type(num-lines) == int and num-lines > 0 { v(0.3em) - for i in range(num_lines) { + for i in range(num-lines) { v(0.15em) line(length: 100%, stroke: (dash: "dotted", thickness: 0.75pt, paint: gray.darken(80%))) v(0.35em) @@ -550,7 +550,7 @@ #v(0.4em) ] v(-0.8em) - render_sub_sol(q, "TL", show-lg) + render-sub-sol(q, "TL", show-lg) } } } @@ -560,9 +560,9 @@ // ========================================== // 5. TRỘN ĐỀ THI // ========================================== -#let render_test( - ma_de, - q_bank, +#let render-test( + ma-de, + q-bank, matrix, info, is-first: false, @@ -575,36 +575,36 @@ context { counter(page).update(1) } } - let seed = int(ma_de) + let seed = int(ma-de) - let raw_NLC = q_bank.filter(matrix.NLC_loc) - let xao_NLC = xao-theo-tuy-chon(raw_NLC, seed + 107, theo-lv: theo-lv) - let NLC_dem = calc.min(matrix.NLC_dem, xao_NLC.len()) - let s_NLC = xao_NLC.slice(0, NLC_dem) + let raw-NLC = q-bank.filter(matrix.NLC-loc) + let xao-NLC = xao-theo-tuy-chon(raw-NLC, seed + 107, theo-lv: theo-lv) + let NLC-dem = calc.min(matrix.NLC-dem, xao-NLC.len()) + let s-NLC = xao-NLC.slice(0, NLC-dem) - let raw_tf = q_bank.filter(matrix.tf_loc) - let xao_tf = xao-theo-tuy-chon(raw_tf, seed + 233, theo-lv: theo-lv) - let tf_dem = calc.min(matrix.tf_dem, xao_tf.len()) - let s_tf = xao_tf.slice(0, tf_dem) + let raw-tf = q-bank.filter(matrix.tf-loc) + let xao-tf = xao-theo-tuy-chon(raw-tf, seed + 233, theo-lv: theo-lv) + let tf-dem = calc.min(matrix.tf-dem, xao-tf.len()) + let s-tf = xao-tf.slice(0, tf-dem) - let raw_TLN = q_bank.filter(matrix.TLN_loc) - let xao_TLN = xao-theo-tuy-chon(raw_TLN, seed + 357, theo-lv: theo-lv) - let TLN_dem = calc.min(matrix.TLN_dem, xao_TLN.len()) - let s_TLN = xao_TLN.slice(0, TLN_dem) + let raw-TLN = q-bank.filter(matrix.TLN-loc) + let xao-TLN = xao-theo-tuy-chon(raw-TLN, seed + 357, theo-lv: theo-lv) + let TLN-dem = calc.min(matrix.TLN-dem, xao-TLN.len()) + let s-TLN = xao-TLN.slice(0, TLN-dem) - let raw_TL = q_bank.filter(matrix.TL_loc) - let xao_TL = xao-theo-tuy-chon(raw_TL, seed + 491, theo-lv: theo-lv) - let TL_dem = calc.min(matrix.TL_dem, xao_TL.len()) - let s_TL = xao_TL.slice(0, TL_dem) + let raw-TL = q-bank.filter(matrix.TL-loc) + let xao-TL = xao-theo-tuy-chon(raw-TL, seed + 491, theo-lv: theo-lv) + let TL-dem = calc.min(matrix.TL-dem, xao-TL.len()) + let s-TL = xao-TL.slice(0, TL-dem) - let part1_ans = () - let part2_ans = () - let part3_ans = () - let part4_ans = () + let part1-ans = () + let part2-ans = () + let part3-ans = () + let part4-ans = () toan-setup({ set page(paper: "a4", margin: 1.2cm, footer: context [ - #set text(size: 9pt); *#h(1fr) Trang #counter(page).display() - Mã đề #ma_de* + #set text(size: 9pt); *#h(1fr) Trang #counter(page).display() - Mã đề #ma-de* ]) grid( @@ -628,144 +628,144 @@ Lớp: ................ Số báo danh: ....................... Phòng thi: ............], - box(stroke: 0.8pt + black, inset: (x: 6pt, y: 6pt))[#strong[Mã đề: #ma_de]] + box(stroke: 0.8pt + black, inset: (x: 6pt, y: 6pt))[#strong[Mã đề: #ma-de]] ) line(length: 100%, stroke: 0.5pt) - if s_NLC.len() > 0 { - let tong_so_cau = s_NLC.fold(0, (acc, q) => { - if "is-chum" in q and q.is-chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } + if s-NLC.len() > 0 { + let tong-so-cau = s-NLC.fold(0, (acc, q) => { + if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) v(-0.1em) - text(fill: mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong_so_cau.* #emph[*Mỗi câu thí sinh chỉ được chọn một phương án.*]#v(0.2em)] + text(fill: mausac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.* #emph[*Mỗi câu thí sinh chỉ được chọn một phương án.*]#v(0.2em)] - let c_idx = 0 - for item in s_NLC { - let is_item_chum = "is-chum" in item and item.is-chum == true and "cau_hoi_con" in item - if is_item_chum { - let n_sub = item.cau_hoi_con.len() - let start_num = c_idx + 1 - let end_num = c_idx + n_sub + let c-idx = 0 + for item in s-NLC { + let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item + if is-item-chum { + let n-sub = item.cau-hoi-con.len() + let start-num = c-idx + 1 + let end-num = c-idx + n-sub v(0.2em) block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau_pa)[*Dữ kiện dùng cho từ Câu #start_num đến Câu #end_num:*] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau-pa)[*Dữ kiện dùng cho từ Câu #start-num đến Câu #end-num:*] \ #v(0.1em) #item.du-kien ] ] } - let ds_cau_can_ve = if is_item_chum { item.cau_hoi_con } else { (item,) } + let ds-cau-can-ve = if is-item-chum { item.cau-hoi-con } else { (item,) } - for q in ds_cau_can_ve { - let opt_indices = if seed == 0 or nlc-mode == "none" { range(4) } else { tron-mang(range(4), seed + c_idx * 73) } - let new_opts = opt_indices.map(i => q.pa.at(i)) - part1_ans.push(to-abc(opt_indices.position(i => i == q.da))) + for q in ds-cau-can-ve { + let opt-indices = if seed == 0 or nlc-mode == "none" { range(4) } else { tron-mang(range(4), seed + c-idx * 73) } + let new-opts = opt-indices.map(i => q.pa.at(i)) + part1-ans.push(to-abc(opt-indices.position(i => i == q.da))) v(-0.2em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), [ #v(-0.3em) - #text(fill: mausac.cau_pa)[*Câu #(c_idx + 1).*] #q.nd \ + #text(fill: mausac.cau-pa)[*Câu #(c-idx + 1).*] #q.nd \ #v(-0.3em) - #let is_img_option = new_opts.any(opt => { + #let is-img-option = new-opts.any(opt => { let r = repr(opt) r.contains("image(") or r.contains("cetz") or r.contains("canvas") }) - #if is_img_option [ + #if is-img-option [ #grid( columns: (1fr, 1fr, 1fr, 1fr), column-gutter: 0.8em, row-gutter: 0.5em, align: center + horizon, - ..new_opts.enumerate().map(((i, v)) => [#align(center)[#text(fill: mausac.cau_pa)[*#to-abc(i).*]) #v]]) + ..new-opts.enumerate().map(((i, v)) => [#align(center)[#text(fill: mausac.cau-pa)[*#to-abc(i).*]) #v]]) ) ] else [ - #let n_cols = if "cot" in q { q.cot } else { 4 } + #let n-cols = if "cot" in q { q.cot } else { 4 } #grid( - columns: (1fr,) * n_cols, row-gutter: 0.6em, column-gutter: 1.2em, align: left + horizon, - ..new_opts.enumerate().map(((i, v)) => [#text(fill: mausac.cau_pa)[#h(1em)*#to-abc(i).*] #v]) + columns: (1fr,) * n-cols, row-gutter: 0.6em, column-gutter: 1.2em, align: left + horizon, + ..new-opts.enumerate().map(((i, v)) => [#text(fill: mausac.cau-pa)[#h(1em)*#to-abc(i).*] #v]) ) ] ], - if has_img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + if has-img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) ] v(-0.8em) - if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "NLC", c_idx, seed, opt_indices: opt_indices) } + if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "NLC", c-idx, seed, opt-indices: opt-indices) } v(-0.2em) - c_idx += 1 + c-idx += 1 } } } - if s_tf.len() > 0 { + if s-tf.len() > 0 { set par(first-line-indent: 0pt) - v(0.5em); text(mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #s_tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] - for (idx, q) in s_tf.enumerate() { - let sub_indices = if tf-mode == "none" { range(4) } + v(0.5em); text(mausac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #s-tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] + for (idx, q) in s-tf.enumerate() { + let sub-indices = if tf-mode == "none" { range(4) } else if tf-mode == "y-only" { - let content_str = repr(q.nd) + repr(q.ytf) - let content_hash = calc.rem(content_str.len() * 265435761, 123456789) - tron-mang(range(4), content_hash * 31 + int(ma_de) * 7919) - } else { tron-mang(range(4), seed + idx * 109 + int(ma_de) * 10000) } - let new_subs = sub_indices.map(i => q.ytf.at(i)) - part2_ans.push(to-ds(sub_indices.map(i => q.da.at(i)))) + let content-str = repr(q.nd) + repr(q.ytf) + let content-hash = calc.rem(content-str.len() * 265435761, 123456789) + tron-mang(range(4), content-hash * 31 + int(ma-de) * 7919) + } else { tron-mang(range(4), seed + idx * 109 + int(ma-de) * 10000) } + let new-subs = sub-indices.map(i => q.ytf.at(i)) + part2-ans.push(to-ds(sub-indices.map(i => q.da.at(i)))) v(-0.3em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), [ - #text(fill: mausac.cau_pa)[*Câu #(idx + 1).* ]#q.nd \ - #list(marker: none, spacing: 0.7em, ..new_subs.enumerate().map(((i, sq)) => [#h(0.5em) #text(fill: mausac.cau_pa)[#strong[#("a)", "b)", "c)", "d)").at(i)]] #sq])) + #text(fill: mausac.cau-pa)[*Câu #(idx + 1).* ]#q.nd \ + #list(marker: none, spacing: 0.7em, ..new-subs.enumerate().map(((i, sq)) => [#h(0.5em) #text(fill: mausac.cau-pa)[#strong[#("a)", "b)", "c)", "d)").at(i)]] #sq])) ], - if has_img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + if has-img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) ] v(-0.4em) - if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TF", idx + s_NLC.len(), seed, tf_indices: sub_indices) } + if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TF", idx + s-NLC.len(), seed, tf-indices: sub-indices) } v(-0.3em) } } - if s_TLN.len() > 0 { - let tong_so_cau = s_TLN.fold(0, (acc, q) => { - if "is-chum" in q and q.is-chum == true and "cau_hoi_con" in q { acc + q.cau_hoi_con.len() } else { acc + 1 } + if s-TLN.len() > 0 { + let tong-so-cau = s-TLN.fold(0, (acc, q) => { + if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) - v(0.5em); text(fill: mausac.cau_pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong_so_cau.*] - let c_idx = 0 - for item in s_TLN { - let is_item_chum = "is-chum" in item and item.is-chum == true and "cau_hoi_con" in item - let ds_cau_can_ve = if is_item_chum { item.cau_hoi_con } else { (item,) } - - if is_item_chum { - let n_sub = item.cau_hoi_con.len() - let start_num = c_idx + 1 - let end_num = c_idx + n_sub + v(0.5em); text(fill: mausac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.*] + let c-idx = 0 + for item in s-TLN { + let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item + let ds-cau-can-ve = if is-item-chum { item.cau-hoi-con } else { (item,) } + + if is-item-chum { + let n-sub = item.cau-hoi-con.len() + let start-num = c-idx + 1 + let end-num = c-idx + n-sub v(0.2em) block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau_pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau_pa)[*Dữ kiện dùng cho từ Câu #start_num đến Câu #end_num:*] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mausac.cau-pa)[*Dữ kiện dùng cho từ Câu #start-num đến Câu #end-num:*] \ #v(0.1em) #item.du-kien ] ] } - for q in ds_cau_can_ve { - part3_ans.push(q.da) + for q in ds-cau-can-ve { + part3-ans.push(q.da) v(-0.5em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), [ - #text(fill: mausac.cau_pa)[*Câu #(c_idx + 1).* ]#q.nd + #text(fill: mausac.cau-pa)[*Câu #(c-idx + 1).* ]#q.nd #if not show-lg [ #v(-0.4em) #pad(left: 0em)[ @@ -773,30 +773,30 @@ ] ] ], - if has_img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + if has-img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) ] v(-1em) - if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TLN", c_idx + s_NLC.len() + s_tf.len(), seed) } + if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TLN", c-idx + s-NLC.len() + s-tf.len(), seed) } v(-0.2em) - c_idx += 1 + c-idx += 1 } } } - if s_TL.len() > 0 { + if s-TL.len() > 0 { set par(first-line-indent: 0pt) - v(0.3em); text(mausac.cau_pa)[*► TỰ LUẬN (#s_TL.len() câu)*] + v(0.3em); text(mausac.cau-pa)[*► TỰ LUẬN (#s-TL.len() câu)*] v(-0.3em) - for (idx, q) in s_TL.enumerate() { - part4_ans.push((nd: q.nd, lg: q.lg)) + for (idx, q) in s-TL.enumerate() { + part4-ans.push((nd: q.nd, lg: q.lg)) v(-0.3em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ - #let has_img = "hv" in q and q.hv != none and q.hv != "" + #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( - columns: if has_img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + top), - [ #text(fill: mausac.cau_pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], - if has_img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] + columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + top), + [ #text(fill: mausac.cau-pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], + if has-img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) #if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TL", idx, seed) } #v(-0.3em) @@ -808,15 +808,15 @@ }) [#metadata(( - seed: ma_de, - part1: part1_ans, - part2: part2_ans, - part3: part3_ans, - part4: part4_ans - )) ] + seed: ma-de, + part1: part1-ans, + part2: part2-ans, + part3: part3-ans, + part4: part4-ans + )) ] } -#let in_dapan_TL(results) = { +#let in-dapan-TL(results) = { context { counter(page).update(1) set page(footer: none) @@ -825,23 +825,23 @@ align(center)[#text(20pt, weight: "bold")[HƯỚNG DẪN CHẤM TỰ LUẬN]] v(-0.2em) for entry in results { - let ma_de = str(entry.value.seed) - let lg_TL = entry.value.part4 - if lg_TL.len() > 0 { + let ma-de = str(entry.value.seed) + let lg-TL = entry.value.part4 + if lg-TL.len() > 0 { align(left)[ #block(fill: gray.lighten(80%), inset: 5pt, radius: 4pt)[ - #text(14pt, weight: "bold")[Mã đề: #ma_de] + #text(14pt, weight: "bold")[Mã đề: #ma-de] ] #v(-0.51em) ] - for (idx, ans) in lg_TL.enumerate() { + for (idx, ans) in lg-TL.enumerate() { align(left)[ #text(12pt)[*Câu #(idx + 1). * #ans.nd] #v(-0.5em) #text(11pt, fill: blue.darken(40%))[*Lời giải:* ] #v(-0.5em) #block(inset: 12pt, fill: yellow.lighten(95%), radius: 4pt, width: 100%)[ - #text(fill: mausac.cau_pa, style: "italic")[#ans.lg] + #text(fill: mausac.cau-pa, style: "italic")[#ans.lg] ] #v(-0.5em) ] @@ -851,97 +851,97 @@ }) } -#let rut_cauLevel(raw_bank, q_type, dem_config, seed) = { - let actual_bank = if type(raw_bank) == dictionary and "data" in raw_bank { raw_bank.data } - else if type(raw_bank) == module { raw_bank.data } else { raw_bank } +#let rut-cauLevel(raw-bank, q-type, dem-config, seed) = { + let actual-bank = if type(raw-bank) == dictionary and "data" in raw-bank { raw-bank.data } + else if type(raw-bank) == module { raw-bank.data } else { raw-bank } - let loc_ques = actual_bank.filter(q => q.type == q_type) - if loc_ques.len() == 0 { return () } + let loc-ques = actual-bank.filter(q => q.type == q-type) + if loc-ques.len() == 0 { return () } - let bank_chum = loc_ques.filter(q => "is-chum" in q and q.is-chum == true) - let bank_don = loc_ques.filter(q => not ("is-chum" in q and q.is-chum == true)) + let bank-chum = loc-ques.filter(q => "is-chum" in q and q.is-chum == true) + let bank-don = loc-ques.filter(q => not ("is-chum" in q and q.is-chum == true)) - let safe-slice(arr, req_count) = { - if req_count <= 0 or arr.len() == 0 { return () } - let take = calc.min(req_count, arr.len()) + let safe-slice(arr, req-count) = { + if req-count <= 0 or arr.len() == 0 { return () } + let take = calc.min(req-count, arr.len()) return arr.slice(0, take) } - let xao_chum = tron-mang(bank_chum, seed) - let xao_don = tron-mang(bank_don, seed + 101) - - let nb_req = 0 - let th_req = 0 - let vd_req = 0 - let chum_req = 0 - - if type(dem_config) == array { - nb_req = dem_config.at(0, default: 0) - th_req = dem_config.at(1, default: 0) - vd_req = dem_config.at(2, default: 0) - } else if type(dem_config) == dictionary { - let don_arr = dem_config.at("don", default: (0, 0, 0)) - nb_req = don_arr.at(0, default: 0) - th_req = don_arr.at(1, default: 0) - vd_req = don_arr.at(2, default: 0) - chum_req = dem_config.at("chum", default: 0) - } else if type(dem_config) == int { - nb_req = dem_config + let xao-chum = tron-mang(bank-chum, seed) + let xao-don = tron-mang(bank-don, seed + 101) + + let nb-req = 0 + let th-req = 0 + let vd-req = 0 + let chum-req = 0 + + if type(dem-config) == array { + nb-req = dem-config.at(0, default: 0) + th-req = dem-config.at(1, default: 0) + vd-req = dem-config.at(2, default: 0) + } else if type(dem-config) == dictionary { + let don-arr = dem-config.at("don", default: (0, 0, 0)) + nb-req = don-arr.at(0, default: 0) + th-req = don-arr.at(1, default: 0) + vd-req = don-arr.at(2, default: 0) + chum-req = dem-config.at("chum", default: 0) + } else if type(dem-config) == int { + nb-req = dem-config } - let res_chum = safe-slice(xao_chum, chum_req) + let res-chum = safe-slice(xao-chum, chum-req) - let b_nb = xao_don.filter(q => ("lv" in q and q.lv == 1) or not ("lv" in q)) - let b_th = xao_don.filter(q => "lv" in q and q.lv == 2) - let b_vd = xao_don.filter(q => "lv" in q and q.lv == 3) + let b-nb = xao-don.filter(q => ("lv" in q and q.lv == 1) or not ("lv" in q)) + let b-th = xao-don.filter(q => "lv" in q and q.lv == 2) + let b-vd = xao-don.filter(q => "lv" in q and q.lv == 3) - let res_don = safe-slice(b_nb, nb_req) + safe-slice(b_th, th_req) + safe-slice(b_vd, vd_req) + let res-don = safe-slice(b-nb, nb-req) + safe-slice(b-th, th-req) + safe-slice(b-vd, vd-req) - return res_chum + res_don + return res-chum + res-don } -#let tron-de-bankLevel(banks_matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: false) = { - for (i, ma_de) in info.ds-ma-de.enumerate() { +#let tron-de-bankLevel(banks-matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: false) = { + for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) - let base_seed = int(ma_de) + let base-seed = int(ma-de) - let rut_NLC = () - let rut_tf = () - let rut_TLN = () - let rut_TL = () + let rut-NLC = () + let rut-tf = () + let rut-TLN = () + let rut-TL = () - for (b_idx, item) in banks_matrix.enumerate() { + for (b-idx, item) in banks-matrix.enumerate() { let b = item.bank - let NLC_seed = base_seed * 999999 + b_idx * 999999 + 107 - let tf_seed = base_seed * 999999 + b_idx * 999999 + 233 - let TLN_seed = base_seed * 999999 + b_idx * 999999 + 357 - let TL_seed = base_seed * 999999 + b_idx * 999999 + 491 - - if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + let NLC-seed = base-seed * 999999 + b-idx * 999999 + 107 + let tf-seed = base-seed * 999999 + b-idx * 999999 + 233 + let TLN-seed = base-seed * 999999 + b-idx * 999999 + 357 + let TL-seed = base-seed * 999999 + b-idx * 999999 + 491 + + if "NLC-dem" in item { rut-NLC += rut-cauLevel(b, "NLC", item.NLC-dem, NLC-seed) } + if "tf-dem" in item { rut-tf += rut-cauLevel(b, "TF", item.tf-dem, tf-seed) } + if "TLN-dem" in item { rut-TLN += rut-cauLevel(b, "TLN", item.TLN-dem, TLN-seed) } + if "TL-dem" in item { rut-TL += rut-cauLevel(b, "TL", item.TL-dem, TL-seed) } } - rut_NLC = xao-theo-tuy-chon(rut_NLC, base_seed + 991, theo-lv: theo-lv) - rut_tf = xao-theo-tuy-chon(rut_tf, base_seed + 997, theo-lv: theo-lv) - rut_TLN = xao-theo-tuy-chon(rut_TLN, base_seed + 1009, theo-lv: theo-lv) - rut_TL = xao-theo-tuy-chon(rut_TL, base_seed + 1013, theo-lv: theo-lv) + rut-NLC = xao-theo-tuy-chon(rut-NLC, base-seed + 991, theo-lv: theo-lv) + rut-tf = xao-theo-tuy-chon(rut-tf, base-seed + 997, theo-lv: theo-lv) + rut-TLN = xao-theo-tuy-chon(rut-TLN, base-seed + 1009, theo-lv: theo-lv) + rut-TL = xao-theo-tuy-chon(rut-TL, base-seed + 1013, theo-lv: theo-lv) - let final_bank = rut_NLC + rut_tf + rut_TLN + rut_TL + let final-bank = rut-NLC + rut-tf + rut-TLN + rut-TL - let fake_matrix = ( - NLC_loc: q => q.type == "NLC", - NLC_dem: rut_NLC.len(), - tf_loc: q => q.type == "TF", - tf_dem: rut_tf.len(), - TLN_loc: q => q.type == "TLN", - TLN_dem: rut_TLN.len(), - TL_loc: q => q.type == "TL", - TL_dem: rut_TL.len(), + let fake-matrix = ( + NLC-loc: q => q.type == "NLC", + NLC-dem: rut-NLC.len(), + tf-loc: q => q.type == "TF", + tf-dem: rut-tf.len(), + TLN-loc: q => q.type == "TLN", + TLN-dem: rut-TLN.len(), + TL-loc: q => q.type == "TL", + TL-dem: rut-TL.len(), ) - render_test(ma_de, final_bank, fake_matrix, info, is-first: is-first, show-lg: show-lg, theo-lv: theo-lv) + render-test(ma-de, final-bank, fake-matrix, info, is-first: is-first, show-lg: show-lg, theo-lv: theo-lv) if i < info.ds-ma-de.len() - 1 { pagebreak(weak: true) @@ -955,17 +955,17 @@ v(-0.5em) context { - let results = query() + let results = query() if results.len() > 0 { - let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() - if total_q > 0 { + let total-q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() + if total-q > 0 { table( columns: (auto, ..info.ds-ma-de.map(_ => 1fr)), align: center + horizon, stroke: 0.5pt, fill: (x, y) => if y == 0 { gray.lighten(80%) }, [*Câu*], ..info.ds-ma-de.map(m => [*#m*]), - ..range(total_q).map(i => { + ..range(total-q).map(i => { let row = ([#(i+1)],) for entry in results { let p1 = entry.value.part1 @@ -984,9 +984,9 @@ } context { - let results = query() + let results = query() if results.any(r => r.value.part4.len() > 0) { - in_dapan_TL(results) + in-dapan-TL(results) } } @@ -995,14 +995,14 @@ align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { - let results = query() - let all_qrcode = tao-QRcode-key(results) + let results = query() + let all-qrcode = tao-QRcode-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ #v(5pt) #text(size: 10pt)[Số lượng mã đề: #results.len()] \ - #qr-code(all_qrcode, dark-color: black, light-color: white, quiet-zone: true) \ + #qr-code(all-qrcode, dark-color: black, light-color: white, quiet-zone: true) \ #text(size: 9pt, fill: blue.darken(20%))[(Đáp án trắc nghiệm dành cho Unt)] ] ] @@ -1011,7 +1011,7 @@ } #let tron-de-chiY( - banks_matrix, + banks-matrix, info, seed-goc: 2024, show-lg: false, @@ -1020,48 +1020,48 @@ nlc-mode: "full", theo-lv: false, ) = { - let rut_NLC = () - let rut_tf = () - let rut_TLN = () - let rut_TL = () + let rut-NLC = () + let rut-tf = () + let rut-TLN = () + let rut-TL = () - for (b_idx, item) in banks_matrix.enumerate() { + for (b-idx, item) in banks-matrix.enumerate() { let b = item.bank - let NLC_seed = seed-goc * 999999 + b_idx * 999999 + 107 - let tf_seed = seed-goc * 999999 + b_idx * 999999 + 233 - let TLN_seed = seed-goc * 999999 + b_idx * 999999 + 357 - let TL_seed = seed-goc * 999999 + b_idx * 999999 + 491 - - if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + let NLC-seed = seed-goc * 999999 + b-idx * 999999 + 107 + let tf-seed = seed-goc * 999999 + b-idx * 999999 + 233 + let TLN-seed = seed-goc * 999999 + b-idx * 999999 + 357 + let TL-seed = seed-goc * 999999 + b-idx * 999999 + 491 + + if "NLC-dem" in item { rut-NLC += rut-cauLevel(b, "NLC", item.NLC-dem, NLC-seed) } + if "tf-dem" in item { rut-tf += rut-cauLevel(b, "TF", item.tf-dem, tf-seed) } + if "TLN-dem" in item { rut-TLN += rut-cauLevel(b, "TLN", item.TLN-dem, TLN-seed) } + if "TL-dem" in item { rut-TL += rut-cauLevel(b, "TL", item.TL-dem, TL-seed) } } - rut_NLC = tron-mang(rut_NLC, seed-goc + 991) - rut_tf = tron-mang(rut_tf, seed-goc + 997) - rut_TLN = tron-mang(rut_TLN, seed-goc + 1009) - rut_TL = tron-mang(rut_TL, seed-goc + 1013) + rut-NLC = tron-mang(rut-NLC, seed-goc + 991) + rut-tf = tron-mang(rut-tf, seed-goc + 997) + rut-TLN = tron-mang(rut-TLN, seed-goc + 1009) + rut-TL = tron-mang(rut-TL, seed-goc + 1013) - for (i, ma_de) in info.ds-ma-de.enumerate() { + for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) - let final_bank = rut_NLC + rut_tf + rut_TLN + rut_TL - - let fake_matrix = ( - NLC_loc: q => q.type == "NLC", - NLC_dem: rut_NLC.len(), - tf_loc: q => q.type == "TF", - tf_dem: rut_tf.len(), - TLN_loc: q => q.type == "TLN", - TLN_dem: rut_TLN.len(), - TL_loc: q => q.type == "TL", - TL_dem: rut_TL.len(), + let final-bank = rut-NLC + rut-tf + rut-TLN + rut-TL + + let fake-matrix = ( + NLC-loc: q => q.type == "NLC", + NLC-dem: rut-NLC.len(), + tf-loc: q => q.type == "TF", + tf-dem: rut-tf.len(), + TLN-loc: q => q.type == "TLN", + TLN-dem: rut-TLN.len(), + TL-loc: q => q.type == "TL", + TL-dem: rut-TL.len(), ) - render_test( - ma_de, - final_bank, - fake_matrix, + render-test( + ma-de, + final-bank, + fake-matrix, info, is-first: is-first, show-lg: show-lg, @@ -1082,17 +1082,17 @@ v(-0.5em) context { - let results = query() + let results = query() if results.len() > 0 { - let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() - if total_q > 0 { + let total-q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() + if total-q > 0 { table( columns: (auto, ..info.ds-ma-de.map(_ => 1fr)), align: center + horizon, stroke: 0.5pt, fill: (x, y) => if y == 0 { gray.lighten(80%) }, [*Câu*], ..info.ds-ma-de.map(m => [*#m*]), - ..range(total_q).map(i => { + ..range(total-q).map(i => { let row = ([#(i+1)],) for entry in results { let p1 = entry.value.part1 @@ -1111,9 +1111,9 @@ } context { - let results = query() + let results = query() if results.any(r => r.value.part4.len() > 0) { - in_dapan_TL(results) + in-dapan-TL(results) } } @@ -1122,14 +1122,14 @@ align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { - let results = query() - let all_qrcode = tao-QRcode-key(results) + let results = query() + let all-qrcode = tao-QRcode-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ #v(5pt) #text(size: 10pt)[Số lượng mã đề: #results.len()] \ - #qr-code(all_qrcode, dark-color: black, light-color: white, quiet-zone: true) \ + #qr-code(all-qrcode, dark-color: black, light-color: white, quiet-zone: true) \ #text(size: 9pt, fill: blue.darken(20%))[(Đáp án trắc nghiệm dành cho Unt)] ] ] @@ -1138,7 +1138,7 @@ } #let tron-de-cungNoiDung( - banks_matrix, + banks-matrix, info, seed-goc: 2024, show-lg: false, @@ -1147,55 +1147,55 @@ xao-pa: true, theo-lv: false, ) = { - let rut_NLC = () - let rut_tf = () - let rut_TLN = () - let rut_TL = () + let rut-NLC = () + let rut-tf = () + let rut-TLN = () + let rut-TL = () - for (b_idx, item) in banks_matrix.enumerate() { + for (b-idx, item) in banks-matrix.enumerate() { let b = item.bank - let NLC_seed = seed-goc * 999999 + b_idx * 999999 + 107 - let tf_seed = seed-goc * 999999 + b_idx * 999999 + 233 - let TLN_seed = seed-goc * 999999 + b_idx * 999999 + 357 - let TL_seed = seed-goc * 999999 + b_idx * 999999 + 491 - - if "NLC_dem" in item { rut_NLC += rut_cauLevel(b, "NLC", item.NLC_dem, NLC_seed) } - if "tf_dem" in item { rut_tf += rut_cauLevel(b, "TF", item.tf_dem, tf_seed) } - if "TLN_dem" in item { rut_TLN += rut_cauLevel(b, "TLN", item.TLN_dem, TLN_seed) } - if "TL_dem" in item { rut_TL += rut_cauLevel(b, "TL", item.TL_dem, TL_seed) } + let NLC-seed = seed-goc * 999999 + b-idx * 999999 + 107 + let tf-seed = seed-goc * 999999 + b-idx * 999999 + 233 + let TLN-seed = seed-goc * 999999 + b-idx * 999999 + 357 + let TL-seed = seed-goc * 999999 + b-idx * 999999 + 491 + + if "NLC-dem" in item { rut-NLC += rut-cauLevel(b, "NLC", item.NLC-dem, NLC-seed) } + if "tf-dem" in item { rut-tf += rut-cauLevel(b, "TF", item.tf-dem, tf-seed) } + if "TLN-dem" in item { rut-TLN += rut-cauLevel(b, "TLN", item.TLN-dem, TLN-seed) } + if "TL-dem" in item { rut-TL += rut-cauLevel(b, "TL", item.TL-dem, TL-seed) } } - rut_NLC = tron-mang(rut_NLC, seed-goc + 991) - rut_tf = tron-mang(rut_tf, seed-goc + 997) - rut_TLN = tron-mang(rut_TLN, seed-goc + 1009) - rut_TL = tron-mang(rut_TL, seed-goc + 1013) + rut-NLC = tron-mang(rut-NLC, seed-goc + 991) + rut-tf = tron-mang(rut-tf, seed-goc + 997) + rut-TLN = tron-mang(rut-TLN, seed-goc + 1009) + rut-TL = tron-mang(rut-TL, seed-goc + 1013) - for (i, ma_de) in info.ds-ma-de.enumerate() { + for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) - let base_seed = int(ma_de) - - let final_NLC = if xao-cau { xao-theo-tuy-chon(rut_NLC, base_seed + 2001, theo-lv: theo-lv) } else { rut_NLC } - let final_tf = if xao-cau { xao-theo-tuy-chon(rut_tf, base_seed + 2011, theo-lv: theo-lv) } else { rut_tf } - let final_TLN = if xao-cau { xao-theo-tuy-chon(rut_TLN, base_seed + 2027, theo-lv: theo-lv) } else { rut_TLN } - let final_TL = if xao-cau { xao-theo-tuy-chon(rut_TL, base_seed + 2039, theo-lv: theo-lv) } else { rut_TL } - - let final_bank = final_NLC + final_tf + final_TLN + final_TL - - let fake_matrix = ( - NLC_loc: q => q.type == "NLC", - NLC_dem: final_NLC.len(), - tf_loc: q => q.type == "TF", - tf_dem: final_tf.len(), - TLN_loc: q => q.type == "TLN", - TLN_dem: final_TLN.len(), - TL_loc: q => q.type == "TL", - TL_dem: final_TL.len(), + let base-seed = int(ma-de) + + let final-NLC = if xao-cau { xao-theo-tuy-chon(rut-NLC, base-seed + 2001, theo-lv: theo-lv) } else { rut-NLC } + let final-tf = if xao-cau { xao-theo-tuy-chon(rut-tf, base-seed + 2011, theo-lv: theo-lv) } else { rut-tf } + let final-TLN = if xao-cau { xao-theo-tuy-chon(rut-TLN, base-seed + 2027, theo-lv: theo-lv) } else { rut-TLN } + let final-TL = if xao-cau { xao-theo-tuy-chon(rut-TL, base-seed + 2039, theo-lv: theo-lv) } else { rut-TL } + + let final-bank = final-NLC + final-tf + final-TLN + final-TL + + let fake-matrix = ( + NLC-loc: q => q.type == "NLC", + NLC-dem: final-NLC.len(), + tf-loc: q => q.type == "TF", + tf-dem: final-tf.len(), + TLN-loc: q => q.type == "TLN", + TLN-dem: final-TLN.len(), + TL-loc: q => q.type == "TL", + TL-dem: final-TL.len(), ) - render_test( - ma_de, - final_bank, - fake_matrix, + render-test( + ma-de, + final-bank, + fake-matrix, info, is-first: is-first, show-lg: show-lg, @@ -1214,17 +1214,17 @@ v(-0.5em) context { - let results = query() + let results = query() if results.len() > 0 { - let total_q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() - if total_q > 0 { + let total-q = results.at(0).value.part1.len() + results.at(0).value.part2.len() + results.at(0).value.part3.len() + if total-q > 0 { table( columns: (auto, ..info.ds-ma-de.map(_ => 1fr)), align: center + horizon, stroke: 0.5pt, fill: (x, y) => if y == 0 { gray.lighten(80%) }, [*Câu*], ..info.ds-ma-de.map(m => [*#m*]), - ..range(total_q).map(i => { + ..range(total-q).map(i => { let row = ([#(i+1)],) for entry in results { let p1 = entry.value.part1 @@ -1243,9 +1243,9 @@ } context { - let results = query() + let results = query() if results.any(r => r.value.part4.len() > 0) { - in_dapan_TL(results) + in-dapan-TL(results) } } @@ -1254,14 +1254,14 @@ align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { - let results = query() - let all_qrcode = tao-QRcode-key(results) + let results = query() + let all-qrcode = tao-QRcode-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ #v(5pt) #text(size: 10pt)[Số lượng mã đề: #results.len()] \ - #qr-code(all_qrcode, dark-color: black, light-color: white, quiet-zone: true) \ + #qr-code(all-qrcode, dark-color: black, light-color: white, quiet-zone: true) \ #text(size: 9pt, fill: blue.darken(20%))[(Đáp án trắc nghiệm dành cho Unt)] ] ] @@ -1345,7 +1345,7 @@ // ========================================== // 7. BÍ DANH TIẾNG ANH (API CHUẨN UNIVERSE) // ========================================== -#let exercise = baitap_inline +#let exercise = baitap-inline #let make-exam-matrix = tron-de-bankLevel #let make-exam-sync = tron-de-cungNoiDung #let make-exam-sub-only = tron-de-chiY From 6699c15d54c4f01d8529f7477564bef2f2d7d4bc Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 12:51:54 +0700 Subject: [PATCH 17/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 9df73430cb..990d8df0ea 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -15,9 +15,9 @@ Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề ## 🖼️ Mẫu kết quả (Gallery)

- Đề thi mẫu
- Bảng đáp án
- Mã QRcode dùng cho máy chấm + Đề thi mẫu
+ Bảng đáp án
+ Mã QRcode dùng cho máy chấm

## 📦 Hướng dẫn sử dụng From 619a3023dc21736cd9e5a161d78da621c43e4896 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 12:53:31 +0700 Subject: [PATCH 18/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 990d8df0ea..add6cfab82 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -65,7 +65,8 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D lg: [Lời giải cho câu hỏi 2],) - ),), + ), +), // Câu hỏi đúng sai ( type: "TF", @@ -84,6 +85,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction [Lời giải cho ý c], [Lời giải cho ý d], ), +), //Câu hỏi trả lời ngắn đơn ( type: "TLN", From 7ef688ac0db459569866e49bc2940c08c43b4be2 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 12:55:50 +0700 Subject: [PATCH 19/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index add6cfab82..4a897189e8 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -1,16 +1,11 @@ # v-exam: 0.1.0 - Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề thi trắc nghiệm / tự luận chuẩn định dạng Bộ Giáo dục & Đào tạo Việt Nam dành cho mọi môn học (Toán, Vật lý, Hóa học, Sinh học, Lịch sử, Địa lý, GDKT&PL, ...). - --- - ## 🚀 Tính năng nổi bật - - **Tự động trộn đề:** Trộn đảo phương án NLC, đảo ý $a, b, c, d$ của câu hỏi Đúng/Sai, hoán vị câu hỏi theo seed mã đề. - **Tự động xuất bảng đáp án & mã QR:** Tạo bảng đáp án tổng hợp và mã QR cho phần mềm chấm thi tự động (như UNT, Chấm thi KC, ...). - **Hỗ trợ câu hỏi chùm (Dữ kiện chung):** Tự động gom nhóm các câu hỏi con đi kèm đoạn văn cảnh/dữ kiện dùng chung mà không bị xáo rời rạc cho trường hợp câu hỏi chùm các môn. - **Biên soạn bài tập nối tiếp (`exercise` / `baitap_inline`):** Hỗ trợ biên soạn tài liệu giảng dạy, bài tập ôn tập chuyên đề có kèm lời giải chi tiết. - --- ## 🖼️ Mẫu kết quả (Gallery) @@ -19,15 +14,11 @@ Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề Bảng đáp án
Mã QRcode dùng cho máy chấm

- ## 📦 Hướng dẫn sử dụng - ### 1. Import thư viện - ```typst #import "@preview/v-exam:0.1.0": * ``` - ### 2. Định dạng ngân hàng câu hỏi Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `dictionary`: @@ -131,7 +122,6 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction ), ) ``` - ### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `baitap-inline`) ```typst #import "file.typ" as b @@ -148,7 +138,6 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction dong-ke:4 ) ``` - ### 4. Trộn đề thi #### a) Trộn đề thi khác nhau(`make-exam-matrix` / `tron-de-bankLevel`) Tạo các đề thi tư ngân hàng với các lấy ngẫu nhiên các câu hỏi từ bank để tạo bộ câu hỏi khác nhau cho mỗi đề\ @@ -180,7 +169,6 @@ Tạo các đề thi tư ngân hàng với các lấy ngẫu nhiên các câu h ```typst Cách 1: #make-exam-matrix(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv:true) - Cách 2: #tron-de-bankLevel(matrix, info, show-g: false, hienthi-bangdapan: true, theo-lv:true) ``` @@ -196,7 +184,6 @@ Cách thực hiện đuề giống với "Trộn đề thi khác nhau" chỉ kh ```typst Cách 1: #make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) - Cách 2: #tron-de-cungNoiDung(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) ``` @@ -212,7 +199,6 @@ Cách thực hiện đuề giống với "Trộn đề cùng nội dung" chỉ k ```typst Cách 1: #make-exam-sub-only(matrix, info-de, seed-goc: 2024, show-lg: false,tf-mode:"y-only",nlc-mode:"none",theo-lv:false) - Cách 2: #tron-de-chiY(matrix, info, seed-goc: 2024, show-lg: false,tf-mode:"y-only",nlc-mode:"none",theo-lv:false) ``` @@ -220,7 +206,5 @@ Giải thích: - tf-mode: có hai chế độ "y-only" đảo ý và "full" đảo ý và đảo câu. - nlc-mode: có 3 chế độ: "y-only" đảo phương án; "full" đảo phương án và đảo câu; "none" không thay đổi. --- - ## 📜 Giấy phép - Phát hành theo giấy phép [MIT License](LICENSE). From b00a0e59a4b3e05da7c7f9573e303add0b63f1ad Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 13:06:28 +0700 Subject: [PATCH 20/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 267 ++++++++++++------------ 1 file changed, 135 insertions(+), 132 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 4a897189e8..56c05e3844 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -1,12 +1,18 @@ # v-exam: 0.1.0 + Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề thi trắc nghiệm / tự luận chuẩn định dạng Bộ Giáo dục & Đào tạo Việt Nam dành cho mọi môn học (Toán, Vật lý, Hóa học, Sinh học, Lịch sử, Địa lý, GDKT&PL, ...). + --- + ## 🚀 Tính năng nổi bật + - **Tự động trộn đề:** Trộn đảo phương án NLC, đảo ý $a, b, c, d$ của câu hỏi Đúng/Sai, hoán vị câu hỏi theo seed mã đề. - **Tự động xuất bảng đáp án & mã QR:** Tạo bảng đáp án tổng hợp và mã QR cho phần mềm chấm thi tự động (như UNT, Chấm thi KC, ...). - **Hỗ trợ câu hỏi chùm (Dữ kiện chung):** Tự động gom nhóm các câu hỏi con đi kèm đoạn văn cảnh/dữ kiện dùng chung mà không bị xáo rời rạc cho trường hợp câu hỏi chùm các môn. -- **Biên soạn bài tập nối tiếp (`exercise` / `baitap_inline`):** Hỗ trợ biên soạn tài liệu giảng dạy, bài tập ôn tập chuyên đề có kèm lời giải chi tiết. +- **Biên soạn bài tập nối tiếp (`exercise` / `baitap-inline`):** Hỗ trợ biên soạn tài liệu giảng dạy, bài tập ôn tập chuyên đề có kèm lời giải chi tiết. + --- + ## 🖼️ Mẫu kết quả (Gallery)

@@ -14,56 +20,64 @@ Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề Bảng đáp án
Mã QRcode dùng cho máy chấm

+ +--- + ## 📦 Hướng dẫn sử dụng + ### 1. Import thư viện + ```typst #import "@preview/v-exam:0.1.0": * ``` + ### 2. Định dạng ngân hàng câu hỏi Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `dictionary`: ```typst #let data = ( -// Câu hỏi đơn trắc nghiệm nhiều lựa chọn. -( + // Câu hỏi đơn trắc nghiệm nhiều lựa chọn + ( type: "NLC", - hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn") dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp - lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng + hv: none, // none: không có hình vẽ; hoặc image("đường dẫn"), canvas({}) + lv: 1, // lv: 1 - Nhận biết, 2 - Thông hiểu, 3 - Vận dụng nd: [Nội dung lời dẫn], - pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), - cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột - da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án D]), + cot: 4, // cot: 1, 2 hoặc 4 + da: 0, // da: 0 - A, 1 - B, 2 - C, 3 - D lg: [Lời giải cho câu hỏi], ), -// Câu hỏi chùm trắc nghiệm nhiều lựa chọn. -( + // Câu hỏi chùm trắc nghiệm nhiều lựa chọn + ( type: "NLC", - hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp - lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - is-chum:true, - du-kien:[Nội dung dùng chung], - cau-hoi-con:( - // Câu hỏi con 1. - (nd: [Nội dung lời dẫn câu hỏi 1], - pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), - cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột - da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D - lg: [Lời giải cho câu hỏi 1],), - // Câu hỏi con 2. - (nd: [Nội dung lời dẫn câu hỏi 2], - pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), - cot: 4,//cot: 1 - bố trí 1 cột, cot: 2 - bố trí 2 cột, cot: 4 - bố trí 4 cột - da: 0, //da: 0 - đáp án đúng A, da: 1 - đáp án đúng B, da: 2 - đáp án đúng C, da: 3 - đáp án đúng D - lg: [Lời giải cho câu hỏi 2],) + hv: none, + lv: 1, + is-chum: true, + du-kien: [Nội dung dùng chung], + cau-hoi-con: ( + ( + nd: [Nội dung lời dẫn câu hỏi 1], + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án D]), + cot: 4, + da: 0, + lg: [Lời giải cho câu hỏi 1], + ), + ( + nd: [Nội dung lời dẫn câu hỏi 2], + pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án D]), + cot: 4, + da: 0, + lg: [Lời giải cho câu hỏi 2], + ), + ), ), -), // Câu hỏi đúng sai ( type: "TF", - hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp - lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - nd: [Lời dẫn của của câu hỏi], + hv: none, + lv: 2, + nd: [Lời dẫn của câu hỏi], ytf: ( [nội dung ý a], [nội dung ý b], @@ -71,140 +85,129 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction [nội dung ý d], ), da: (1, 0, 1, 0), // 1 - đúng, 0 - sai - lg: ([Lời giải cho ý a], - [Lời giải cho ý b], - [Lời giải cho ý c], - [Lời giải cho ý d], + lg: ( + [Lời giải cho ý a], + [Lời giải cho ý b], + [Lời giải cho ý c], + [Lời giải cho ý d], + ), ), -), -//Câu hỏi trả lời ngắn đơn -( + // Câu hỏi trả lời ngắn đơn + ( type: "TLN", - hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp - lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - nd: [Lời dẫn của của câu hỏi], - da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," - lg:[Lời giải cho bài toán], - dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải -), -//Câu hỏi trắc lời ngắn dạng chùm -// Câu hỏi chùm trắc nghiệm nhiều lựa chọn. -( + hv: none, + lv: 2, + nd: [Lời dẫn của câu hỏi], + da: "1.25", + lg: [Lời giải cho bài toán], + dong_ke: 3, + ), + // Câu hỏi trả lời ngắn dạng chùm + ( type: "TLN", - hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp - lv: 1, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - is-chum:true, - du-kien:[Nội dung dùng chung], - cau-hoi-con:( - // Câu hỏi con 1. - (nd: [Nội dung lời dẫn câu hỏi 1], - da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," - lg:[Lời giải cho bài toán], - dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải + hv: none, + lv: 1, + is_chum: true, + du_kien: [Nội dung dùng chung], + cau_hoi_con: ( + ( + nd: [Nội dung lời dẫn câu hỏi 1], + da: "12", + lg: [Lời giải 1], + dong_ke: 2, + ), + ( + nd: [Nội dung lời dẫn câu hỏi 2], + da: "5", + lg: [Lời giải 2], + dong_ke: 2, + ), ), - // Câu hỏi con 2. - (nd: [Nội dung lời dẫn câu hỏi 2], - pa: ([Phương án A], [Phương án B], [Phương án C], [Phương án]), - da:so,// Số nhập có thể là số thực chứa phần thập phân hoặc không (tối đa 4 kí tự) đối với thập phân thì viết dấu "." thay cho "," - lg:[Lời giải cho bài toán], - dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải -), ), -), -//Câu hỏi tự luận -( + // Câu hỏi tự luận + ( type: "TL", - hv:none,//none: không có hình vẽ; nếu có hình vẽ có thể dùng image("đường dẫn) dùng cho trường hợp import hình có sẳn hoặc canvas({}) để vẽ trực tiếp - lv: 2, //lv: 1 - Nhận biết, lv: 2 - Thông hiểu, lv: 3 - Vận dụng - nd: [Lời dẫn của của câu hỏi], - lg:[Lời giải cho bài toán], - dong-ke: so,//nhập số dòng kẻ cần tạo để ghi lời giải -), + hv: none, + lv: 2, + nd: [Lời dẫn của câu hỏi], + lg: [Lời giải cho bài toán], + dong_ke: 5, + ), ) ``` + ### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `baitap-inline`) + ```typst -#import "file.typ" as b -// code tạo bài tập. +#import "@preview/v-exam:0.1.0": exercise, baitap-inline + #exercise( - b.data, + data, cm: 1, num-nlc: (1, 0, 0), num-tf: (0, 1, 0), - num-tln: (0,1,2), + num-tln: (0, 1, 2), show-lg: true, seed: 123, - theo-lv:true, - dong-ke:4 + theo-lv: true, + dong-ke: 4, ) ``` + ### 4. Trộn đề thi -#### a) Trộn đề thi khác nhau(`make-exam-matrix` / `tron-de-bankLevel`) -Tạo các đề thi tư ngân hàng với các lấy ngẫu nhiên các câu hỏi từ bank để tạo bộ câu hỏi khác nhau cho mỗi đề\ -**- Import ngân hàng câu hỏi để trộn đề và tạo bank** + +#### a) Trộn đề thi từ ngân hàng (`make-exam-matrix` / `tron-de-bank-level`) + +Tạo các đề thi bằng cách rút ngẫu nhiên câu hỏi từ ngân hàng đề: + ```typst -#import "file.typ" as b #let matrix = ( ( - bank: b.data, - NLC-dem: (1, 0, 0), - tf-dem: (0, 1, 0), - tln-dem: (0, 1, 0), - tl-dem: (0, 1, 0), + bank: data, + NLC_dem: (1, 0, 0), + tf_dem: (0, 1, 0), + TLN_dem: (0, 1, 0), + TL_dem: (0, 1, 0), ), ) -``` -**- Tạo thông tin bài kiểm tra** -```typst + #let info = ( - so-gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], + so_gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], truong: [TRƯỜNG THPT NGHĨA HÀNH], - ky-thi: [KIỂM TRA GIỮA KỲ I], + ky_thi: [KIỂM TRA GIỮA KỲ I], mon: [VẬT LÝ 12], - thoi-gian: [45 phút], - ds-ma-de: ("101", "102", "103", "104"), + thoi_gian: [45 phút], + ds_ma_de: ("101", "102", "103", "104"), ) + +// Gọi lệnh tạo đề: +#make-exam-matrix(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: true) +// Hoặc alias tiếng Việt: +#tron-de-bank-level(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: true) ``` -**- Thực hiện lên trộn đề:** -```typst -Cách 1: -#make-exam-matrix(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv:true) -Cách 2: -#tron-de-bankLevel(matrix, info, show-g: false, hienthi-bangdapan: true, theo-lv:true) -``` -Giải thích: -- matrix: là nơi cấu hình cách lấy câu hỏi từ bank để đưa vào đề. -- info: nội dung hiển thị tiêu đề của của bài kiểm tra và các mã đề của đề -- show-lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. -- hienthi_bangdapan: có hai chức năng: (1) hiển thị bảng đáp án (true) cuối file để dùng trong chấm bài; (2) không hiển thị bảng đáp án (false) đảm bào đề tạo ra không có bản đáp án. -- theo-lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. - -#### b) chức năng trộn đề tạo các đề giống nhau (`make-exam-sync` / `tron_de_cungNoiDung`) -Cách thực hiện đuề giống với "Trộn đề thi khác nhau" chỉ khác ở mục thực hiện trộn đề khi gọi lệnh: + +#### b) Trộn đề cùng nội dung (`make-exam-sync` / `tron-de-cung-noi-dung`) + +Cùng một bộ câu hỏi nhưng xáo trộn vị trí câu và phương án giữa các mã đề: + ```typst -Cách 1: -#make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) -Cách 2: -#tron-de-cungNoiDung(matrix, info, seed-goc: 2026, show-lg: false,theo-lv:false,xao-cau: true, xao-pa: true) +#make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false, theo-lv: false, xao-cau: true, xao-pa: true) +// Hoặc alias tiếng Việt: +#tron-de-cung-noi-dung(matrix, info, seed-goc: 2026, show-lg: false, theo-lv: false, xao-cau: true, xao-pa: true) ``` -Giải thích: -- seed-goc: 2026 dùng để ấn định một seed được chon để tạo đề gốc ban đầu sau đó căn cứ theo mã đề để xáo cho hợp lý -- show-lg: có hai chức năng: (1) hiện lời giải cho đề (true) để giáo viên cung cấp cho học sinh hoặc hướng dẫn giảng dạy; (2) Ẩn lời giải (false) dùng trong việc tạo đề dúng cho kiểm tra. -- hienthi_bangdapan: có hai chức năng: (1) hiển thị bảng đáp án (true) cuối file để dùng trong chấm bài; (2) không hiển thị bảng đáp án (false) đảm bào đề tạo ra không có bản đáp án. -- theo-lv: có chức năng: (1) xếp câu hỏi thức mức độ từ NB -> TH -> VD khi dùng chức năng true; (2) xếp câu hỏi ngẫu nhiên để tạo đề khi dùng chức năng false. -- xao-cau: cho phép cố định câu không đổi vị trí câu ở các đề (false), đảo vị trí ở các đề (true) -- xao-pa: cho phép cố định phương án ABCD hoặc ý abcd ở các đề (false), đảo vị trí phương án ở các đề (true) -#### c) chức năng trộn đề ý hoặc phương án(`make-exam-sub-only` / `tron_de_chiY`) -Cách thực hiện đuề giống với "Trộn đề cùng nội dung" chỉ khác ở mục thực hiện trộn đề khi gọi lệnh: + +#### c) Trộn đề chỉ đảo ý/phương án (`make-exam-sub-only` / `tron-de-chi-y`) + +Cố định thứ tự câu hỏi, chỉ hoán vị phương án hoặc các ý $a, b, c, d$: + ```typst -Cách 1: -#make-exam-sub-only(matrix, info-de, seed-goc: 2024, show-lg: false,tf-mode:"y-only",nlc-mode:"none",theo-lv:false) -Cách 2: -#tron-de-chiY(matrix, info, seed-goc: 2024, show-lg: false,tf-mode:"y-only",nlc-mode:"none",theo-lv:false) +#make-exam-sub-only(matrix, info, seed-goc: 2024, show-lg: false, tf-mode: "y-only", nlc-mode: "none", theo-lv: false) +// Hoặc alias tiếng Việt: +#tron-de-chi-y(matrix, info, seed-goc: 2024, show-lg: false, tf-mode: "y-only", nlc-mode: "none", theo-lv: false) ``` -Giải thích: -- tf-mode: có hai chế độ "y-only" đảo ý và "full" đảo ý và đảo câu. -- nlc-mode: có 3 chế độ: "y-only" đảo phương án; "full" đảo phương án và đảo câu; "none" không thay đổi. + --- + ## 📜 Giấy phép + Phát hành theo giấy phép [MIT License](LICENSE). From 553a89611ba99d6781723534672fe4798994f753 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 13:17:18 +0700 Subject: [PATCH 21/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 86 +++++++++++++-------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 5d5fc612b8..2d064b843b 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -99,7 +99,7 @@ // ========================================== // 3. HÀM TẠO QR & HIỂN THỊ LỜI GIẢI // ========================================== -#let tao-QRcode-key(results) = { +#let tao-QR-code-key(results) = { let all-content = "" for entry in results { let ma-de = str(entry.value.seed) @@ -111,7 +111,7 @@ return all-content } -#let hienthi-lg(q, q-type, idx, seed, opt-indices: none, tf-indices: none) = { +#let hien-thi-lg(q, q-type, idx, seed, opt-indices: none, tf-indices: none) = { toan-setup({ v(-0.4em) block( @@ -209,7 +209,7 @@ ] } -#let baitap-inline( +#let bai-tap-in-line( cm: 1, bank-data, title: none, @@ -696,7 +696,7 @@ ) ] v(-0.8em) - if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "NLC", c-idx, seed, opt-indices: opt-indices) } + if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "NLC", c-idx, seed, opt-indices: opt-indices) } v(-0.2em) c-idx += 1 } @@ -728,7 +728,7 @@ ) ] v(-0.4em) - if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TF", idx + s-NLC.len(), seed, tf-indices: sub-indices) } + if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TF", idx + s-NLC.len(), seed, tf-indices: sub-indices) } v(-0.3em) } } @@ -777,7 +777,7 @@ ) ] v(-1em) - if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TLN", c-idx + s-NLC.len() + s-tf.len(), seed) } + if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TLN", c-idx + s-NLC.len() + s-tf.len(), seed) } v(-0.2em) c-idx += 1 } @@ -798,7 +798,7 @@ [ #text(fill: mausac.cau-pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], if has-img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) - #if show-lg and "lg" in q and q.lg != [] { hienthi-lg(q, "TL", idx, seed) } + #if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TL", idx, seed) } #v(-0.3em) ] } @@ -816,7 +816,7 @@ )) ] } -#let in-dapan-TL(results) = { +#let in-dap-an-TL(results) = { context { counter(page).update(1) set page(footer: none) @@ -851,7 +851,7 @@ }) } -#let rut-cauLevel(raw-bank, q-type, dem-config, seed) = { +#let rut-cau-Level(raw-bank, q-type, dem-config, seed) = { let actual-bank = if type(raw-bank) == dictionary and "data" in raw-bank { raw-bank.data } else if type(raw-bank) == module { raw-bank.data } else { raw-bank } @@ -900,7 +900,7 @@ return res-chum + res-don } -#let tron-de-bankLevel(banks-matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: false) = { +#let tron-de-bank-Level(banks-matrix, info, show-lg: false, hien-thi-bang-da-pan: true, theo-lv: false) = { for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) let base-seed = int(ma-de) @@ -917,10 +917,10 @@ let TLN-seed = base-seed * 999999 + b-idx * 999999 + 357 let TL-seed = base-seed * 999999 + b-idx * 999999 + 491 - if "NLC-dem" in item { rut-NLC += rut-cauLevel(b, "NLC", item.NLC-dem, NLC-seed) } - if "tf-dem" in item { rut-tf += rut-cauLevel(b, "TF", item.tf-dem, tf-seed) } - if "TLN-dem" in item { rut-TLN += rut-cauLevel(b, "TLN", item.TLN-dem, TLN-seed) } - if "TL-dem" in item { rut-TL += rut-cauLevel(b, "TL", item.TL-dem, TL-seed) } + if "NLC-dem" in item { rut-NLC += rut-cau-Level(b, "NLC", item.NLC-dem, NLC-seed) } + if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } + if "TLN-dem" in item { rut-TLN += rut-cau-Level(b, "TLN", item.TLN-dem, TLN-seed) } + if "TL-dem" in item { rut-TL += rut-cau-Level(b, "TL", item.TL-dem, TL-seed) } } rut-NLC = xao-theo-tuy-chon(rut-NLC, base-seed + 991, theo-lv: theo-lv) @@ -948,7 +948,7 @@ } } - if hienthi-bangdapan { + if hien-thi-bang-da-pan { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -986,7 +986,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dapan-TL(results) + in-dap-an-TL(results) } } @@ -996,7 +996,7 @@ v(1em) context { let results = query() - let all-qrcode = tao-QRcode-key(results) + let all-qrcode = tao-QR-code-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ @@ -1010,12 +1010,12 @@ } } -#let tron-de-chiY( +#let tron-de-chi-Y( banks-matrix, info, seed-goc: 2024, show-lg: false, - hienthi-bangdapan: true, + hien-thi-bang-da-pan: true, tf-mode: "y-only", nlc-mode: "full", theo-lv: false, @@ -1032,10 +1032,10 @@ let TLN-seed = seed-goc * 999999 + b-idx * 999999 + 357 let TL-seed = seed-goc * 999999 + b-idx * 999999 + 491 - if "NLC-dem" in item { rut-NLC += rut-cauLevel(b, "NLC", item.NLC-dem, NLC-seed) } - if "tf-dem" in item { rut-tf += rut-cauLevel(b, "TF", item.tf-dem, tf-seed) } - if "TLN-dem" in item { rut-TLN += rut-cauLevel(b, "TLN", item.TLN-dem, TLN-seed) } - if "TL-dem" in item { rut-TL += rut-cauLevel(b, "TL", item.TL-dem, TL-seed) } + if "NLC-dem" in item { rut-NLC += rut-cau-Level(b, "NLC", item.NLC-dem, NLC-seed) } + if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } + if "TLN-dem" in item { rut-TLN += rut-cau-Level(b, "TLN", item.TLN-dem, TLN-seed) } + if "TL-dem" in item { rut-TL += rut-cau-Level(b, "TL", item.TL-dem, TL-seed) } } rut-NLC = tron-mang(rut-NLC, seed-goc + 991) @@ -1075,7 +1075,7 @@ } } - if hienthi-bangdapan { + if hien-thi-bang-da-pan { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -1113,7 +1113,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dapan-TL(results) + in-dap-an-TL(results) } } @@ -1123,7 +1123,7 @@ v(1em) context { let results = query() - let all-qrcode = tao-QRcode-key(results) + let all-qrcode = tao-QR-code-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ @@ -1137,12 +1137,12 @@ } } -#let tron-de-cungNoiDung( +#let tron-de-cung-Noi-Dung( banks-matrix, info, seed-goc: 2024, show-lg: false, - hienthi-bangdapan: true, + hien-thi-bang-da-pan: true, xao-cau: true, xao-pa: true, theo-lv: false, @@ -1159,10 +1159,10 @@ let TLN-seed = seed-goc * 999999 + b-idx * 999999 + 357 let TL-seed = seed-goc * 999999 + b-idx * 999999 + 491 - if "NLC-dem" in item { rut-NLC += rut-cauLevel(b, "NLC", item.NLC-dem, NLC-seed) } - if "tf-dem" in item { rut-tf += rut-cauLevel(b, "TF", item.tf-dem, tf-seed) } - if "TLN-dem" in item { rut-TLN += rut-cauLevel(b, "TLN", item.TLN-dem, TLN-seed) } - if "TL-dem" in item { rut-TL += rut-cauLevel(b, "TL", item.TL-dem, TL-seed) } + if "NLC-dem" in item { rut-NLC += rut-cau-Level(b, "NLC", item.NLC-dem, NLC-seed) } + if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } + if "TLN-dem" in item { rut-TLN += rut-cau-Level(b, "TLN", item.TLN-dem, TLN-seed) } + if "TL-dem" in item { rut-TL += rut-cau-Level(b, "TL", item.TL-dem, TL-seed) } } rut-NLC = tron-mang(rut-NLC, seed-goc + 991) @@ -1207,7 +1207,7 @@ } } - if hienthi-bangdapan { + if hien-thi-bang-da-pan { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -1245,7 +1245,7 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dapan-TL(results) + in-dap-an-TL(results) } } @@ -1255,7 +1255,7 @@ v(1em) context { let results = query() - let all-qrcode = tao-QRcode-key(results) + let all-qrcode = tao-QR-code-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ @@ -1272,7 +1272,7 @@ // ========================================== // 6. CÁC HÀM TRANG TRÍ TIÊU ĐỀ // ========================================== -#let tdbai(title, bsize: 18pt, clorfont: rgb("#0309a7"), bground: rgb("#00ffff3b"), cle: center) = { +#let td-bai(title, bsize: 18pt, clorfont: rgb("#0309a7"), bground: rgb("#00ffff3b"), cle: center) = { block( width: 100%, fill: bground, radius: 8pt, stroke: 0.5pt + rgb("#c405ef"), inset: (x: 25pt, y: 8pt), align(cle)[#text(fill: clorfont, size: bsize, weight: "bold", font: "Times New Roman", title)] @@ -1296,7 +1296,7 @@ #let mau-cap2 = rgb("#0501f0") #let mau-cap3 = rgb("#024905") -#let tieude(noi-dung, cap: 1) = { +#let tieu-de(noi-dung, cap: 1) = { if cap == 1 { block(width: 100%, below: 0.7em, inset: (x: 0pt, y: 8pt), fill: rgb("#f3b40659"), radius: 4pt)[ #align(left)[#text(weight: "bold", size: 1.3em, fill: mau-cap2)[#noi-dung]] @@ -1319,7 +1319,7 @@ v(0.3em) } -#let chimuc(title, tsize: 16pt) = { +#let chi-muc(title, tsize: 16pt) = { set par(first-line-indent: 0pt) block(width: 100%)[ #box(fill: rgb("#00ffff2e"), radius: (top-left: 0pt, top-right: 8pt, bottom-left: 0pt, bottom-right: 0pt), stroke: 0.5pt + rgb("#ee05ea"), inset: (x: 4pt, y: 8pt))[ @@ -1330,7 +1330,7 @@ ] } -#let luuy(title, body) = { +#let luu-y(title, body) = { block(width: 100%, below: 0.1em, stroke: (paint: red, thickness: 1pt), inset: (x: 12pt, y: 10pt), radius: 4pt, fill: rgb("#99eee832"))[ #text(weight: "bold", fill: blue.darken(40%))[#underline(title, offset: 3pt)] #v(-0.3em) @@ -1345,7 +1345,7 @@ // ========================================== // 7. BÍ DANH TIẾNG ANH (API CHUẨN UNIVERSE) // ========================================== -#let exercise = baitap-inline -#let make-exam-matrix = tron-de-bankLevel -#let make-exam-sync = tron-de-cungNoiDung -#let make-exam-sub-only = tron-de-chiY +#let exercise = bai-tap-in-line +#let make-exam-matrix = tron-de-bank-Level +#let make-exam-sync = tron-de-cung-Noi-Dung +#let make-exam-sub-only = tron-de-chi-Y From 24073d4335f0b59409febc6cb950fff9cc50d586 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 13:24:56 +0700 Subject: [PATCH 22/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 56c05e3844..8d7de8d6db 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -9,7 +9,7 @@ Bộ công cụ biên soạn bài tập, tài liệu ôn tập và trộn đề - **Tự động trộn đề:** Trộn đảo phương án NLC, đảo ý $a, b, c, d$ của câu hỏi Đúng/Sai, hoán vị câu hỏi theo seed mã đề. - **Tự động xuất bảng đáp án & mã QR:** Tạo bảng đáp án tổng hợp và mã QR cho phần mềm chấm thi tự động (như UNT, Chấm thi KC, ...). - **Hỗ trợ câu hỏi chùm (Dữ kiện chung):** Tự động gom nhóm các câu hỏi con đi kèm đoạn văn cảnh/dữ kiện dùng chung mà không bị xáo rời rạc cho trường hợp câu hỏi chùm các môn. -- **Biên soạn bài tập nối tiếp (`exercise` / `baitap-inline`):** Hỗ trợ biên soạn tài liệu giảng dạy, bài tập ôn tập chuyên đề có kèm lời giải chi tiết. +- **Biên soạn bài tập nối tiếp (`exercise` / `bai-tap-in-line`):** Hỗ trợ biên soạn tài liệu giảng dạy, bài tập ôn tập chuyên đề có kèm lời giải chi tiết. --- @@ -136,10 +136,10 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction ) ``` -### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `baitap-inline`) +### 3. Biên soạn bài tập / Tài liệu ôn tập (`exercise` / `bai-tap-in-line`) ```typst -#import "@preview/v-exam:0.1.0": exercise, baitap-inline +#import "@preview/v-exam:0.1.0": exercise, bai-tap-in-line #exercise( data, @@ -164,26 +164,26 @@ Tạo các đề thi bằng cách rút ngẫu nhiên câu hỏi từ ngân hàng #let matrix = ( ( bank: data, - NLC_dem: (1, 0, 0), - tf_dem: (0, 1, 0), - TLN_dem: (0, 1, 0), - TL_dem: (0, 1, 0), + NLC-dem: (1, 0, 0), + tf-dem: (0, 1, 0), + TLN-dem: (0, 1, 0), + TL-dem: (0, 1, 0), ), ) #let info = ( - so_gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], + so-gd: [SỞ GD VÀ ĐT QUẢNG NGÃI], truong: [TRƯỜNG THPT NGHĨA HÀNH], - ky_thi: [KIỂM TRA GIỮA KỲ I], + ky-thi: [KIỂM TRA GIỮA KỲ I], mon: [VẬT LÝ 12], - thoi_gian: [45 phút], - ds_ma_de: ("101", "102", "103", "104"), + thoi-gian: [45 phút], + ds-ma-de: ("101", "102", "103", "104"), ) // Gọi lệnh tạo đề: -#make-exam-matrix(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: true) +#make-exam-matrix(matrix, info, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: true) // Hoặc alias tiếng Việt: -#tron-de-bank-level(matrix, info, show-lg: false, hienthi-bangdapan: true, theo-lv: true) +#tron-de-bank-level(matrix, info, show-lg: false, hienthi-bang-dap-an: true, theo-lv: true) ``` #### b) Trộn đề cùng nội dung (`make-exam-sync` / `tron-de-cung-noi-dung`) @@ -191,9 +191,9 @@ Tạo các đề thi bằng cách rút ngẫu nhiên câu hỏi từ ngân hàng Cùng một bộ câu hỏi nhưng xáo trộn vị trí câu và phương án giữa các mã đề: ```typst -#make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false, theo-lv: false, xao-cau: true, xao-pa: true) +#make-exam-sync(matrix, info, seed-goc: 2026, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: false, xao-cau: true, xao-pa: true) // Hoặc alias tiếng Việt: -#tron-de-cung-noi-dung(matrix, info, seed-goc: 2026, show-lg: false, theo-lv: false, xao-cau: true, xao-pa: true) +#tron-de-cung-noi-dung(matrix, info, seed-goc: 2026, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: false, xao-cau: true, xao-pa: true) ``` #### c) Trộn đề chỉ đảo ý/phương án (`make-exam-sub-only` / `tron-de-chi-y`) @@ -201,9 +201,9 @@ Cùng một bộ câu hỏi nhưng xáo trộn vị trí câu và phương án g Cố định thứ tự câu hỏi, chỉ hoán vị phương án hoặc các ý $a, b, c, d$: ```typst -#make-exam-sub-only(matrix, info, seed-goc: 2024, show-lg: false, tf-mode: "y-only", nlc-mode: "none", theo-lv: false) +#make-exam-sub-only(matrix, info, seed-goc: 2024, show-lg: false, hien-thi-bang-dap-an: true, tf-mode: "y-only", nlc-mode: "none", theo-lv: false) // Hoặc alias tiếng Việt: -#tron-de-chi-y(matrix, info, seed-goc: 2024, show-lg: false, tf-mode: "y-only", nlc-mode: "none", theo-lv: false) +#tron-de-chi-y(matrix, info, seed-goc: 2024, show-lg: false, hien-thi-bang-dap-an: true, tf-mode: "y-only", nlc-mode: "none", theo-lv: false) ``` --- From 6def4cbda8077fa15eab6bafa4b0311ed5c9739e Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 13:26:43 +0700 Subject: [PATCH 23/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 8d7de8d6db..fc41e7f2e2 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -161,9 +161,10 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction Tạo các đề thi bằng cách rút ngẫu nhiên câu hỏi từ ngân hàng đề: ```typst +#import "file.typ" as b #let matrix = ( ( - bank: data, + bank: b.data, NLC-dem: (1, 0, 0), tf-dem: (0, 1, 0), TLN-dem: (0, 1, 0), From 546a6c1ccfe6d3b83eca30392fa4741e6fcc6071 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 13:27:25 +0700 Subject: [PATCH 24/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index fc41e7f2e2..0a5c43eb81 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -140,9 +140,9 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction ```typst #import "@preview/v-exam:0.1.0": exercise, bai-tap-in-line - +#import "file.typ" as b #exercise( - data, + b.data, cm: 1, num-nlc: (1, 0, 0), num-tf: (0, 1, 0), From 33098cf476673941bf893036a9f4eb3012ef92a8 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 14:15:10 +0700 Subject: [PATCH 25/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 130 +++++++++++++------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 2d064b843b..457d2341e1 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -26,7 +26,7 @@ body } -#let mausac = ( +#let mau-sac = ( lg : rgb("#a8f6f13c"), duong: rgb("#0057b8"), cau-pa: rgb("#1505f2"), @@ -100,7 +100,7 @@ // 3. HÀM TẠO QR & HIỂN THỊ LỜI GIẢI // ========================================== #let tao-QR-code-key(results) = { - let all-content = "" + let all_content = "" for entry in results { let ma-de = str(entry.value.seed) let part1 = entry.value.part1.join("") @@ -117,24 +117,24 @@ block( width: 100%, inset: (y: 0.5em, x: 0.5em, left: 8pt, right: 8pt), - fill: mausac.lg, + fill: mau-sac.lg, radius: (right: 4pt), - stroke: (left: 2pt + mausac.duong) + stroke: (left: 2pt + mau-sac.duong) )[ #v(0.2em) #if q-type == "NLC" { let correct-idx = if opt-indices != none { opt-indices.position(i => i == q.da) } else { q.da } text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #to-abc(correct-idx)*\ ] - text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[*Lời giải:*] + text(fill: red.darken(0%), size: 15pt)[*Lời giải:*] } else if q-type == "TF" or q-type == "tf" { let correct-ans = if tf-indices != none { to-ds(tf-indices.map(i => q.da.at(i))) } else { to-ds(q.da) } text(fill: blue.darken(100%), size: 11pt)[*Đáp án: #correct-ans*\ ] - text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[ *Lời giải:*] + text(fill: red.darken(0%), size: 15pt)[ *Lời giải:*] } else if q-type == "TLN" { text(fill: blue.darken(100%), size: 11pt)[*Kết quả: #q.da*] - text(fill: red.darken(0%), size: 15pt, font: "UTM A&S Graceland")[\ *Lời giải:*] + text(fill: red.darken(0%), size: 15pt)[\ *Lời giải:*] } else if q-type == "TL" { - text(fill: red.darken(0%), weight: "bold", font: "UTM A&S Graceland", size: 16pt)[*Lời giải:*] + text(fill: red.darken(0%), weight: "bold", size: 16pt)[*Lời giải:*] } #if (q-type == "TF" or q-type == "tf") and type(q.lg) == array { @@ -149,7 +149,7 @@ let status-str = if is-true { "Đúng" } else { "Sai" } let lg-content = if orig-i < q.lg.len() { q.lg.at(orig-i) } else { [] } - [#text(fill: mausac.cau-pa, weight: "bold")[#labels.at(new-i) - #status-str:] #text(fill: blue.darken(100%), style: "italic")[#lg-content]] + [#text(fill: mau-sac.cau-pa, weight: "bold")[#labels.at(new-i) - #status-str:] #text(fill: blue.darken(100%), style: "italic")[#lg-content]] }) ) } else { @@ -168,19 +168,19 @@ v(-0.8em) block( width: 100%, - stroke: (left: 2.5pt + mausac.duong), - fill: mausac.lg, + stroke: (left: 2.5pt + mau-sac.duong), + fill: mau-sac.lg, inset: (x: 10pt, y: 8pt), radius: (right: 4pt), breakable: true )[ #set par(leading: 0.65em) #if type-str == "NLC" [ - #text(fill: mausac.duong, weight: "bold")[► Lời giải: \ ] + #text(fill: mau-sac.duong, weight: "bold")[► Lời giải: \ ] #if "lg" in q and q.lg != none and q.lg != [] [ #q.lg ] else [ Chưa có lời giải.] ] #if type-str == "TF" [ - #text(fill: mausac.duong, weight: "bold")[► Đáp án:] #text(fill: mausac.daT, weight: "bold")[#to-ds(q.da)] \ + #text(fill: mau-sac.duong, weight: "bold")[► Đáp án:] #text(fill: mau-sac.daT, weight: "bold")[#to-ds(q.da)] \ #if "lg" in q and q.lg != none and q.lg != [] [ #if type(q.lg) == array [ #let labels = ("a)", "b)", "c)", "d)") @@ -190,7 +190,7 @@ ..q.lg.enumerate().map(((i, lg-item)) => { let is-true = q.da.at(i) == 1 let status-str = if is-true { "Đúng" } else { "Sai" } - [#text(fill: mausac.cau-pa, weight: "bold")[#labels.at(i) #status-str]\ #lg-item] + [#text(fill: mau-sac.cau-pa, weight: "bold")[#labels.at(i) #status-str]\ #lg-item] }) ) ] else [ @@ -199,11 +199,11 @@ ] else [ Chưa có lời giải.] ] #if type-str == "TLN" [ - #text(fill: mausac.duong, weight: "bold")[► Kết quả:] #text(fill: mausac.daT, weight: "bold")[#q.da] \ + #text(fill: mau-sac.duong, weight: "bold")[► Kết quả:] #text(fill: mau-sac.daT, weight: "bold")[#q.da] \ #if "lg" in q and q.lg != none and q.lg != [] [ #v(0.01em)#q.lg #v(0.2em)] else [ Chưa có lời giải.] ] #if type-str == "TL" [ - #text(fill: mausac.duong, weight: "bold")[► Lời giải chi tiết:] \ + #text(fill: mau-sac.duong, weight: "bold")[► Lời giải chi tiết:] \ #if "lg" in q and q.lg != none and q.lg != [] [ #q.lg ] else [ Chưa có lời giải.] ] ] @@ -220,16 +220,16 @@ num-tl: none, show-lg: false, dong-ke: none, - co-NLC: none, - co-tf: none, - co-TLN: none, - co-TL: none, + co_NLC: none, + co_tf: none, + co_TLN: none, + co_TL: none, theo-lv: false, ) = { - let cfg-nlc = if num-nlc != none { num-nlc } else { co-NLC } - let cfg-tf = if num-tf != none { num-tf } else { co-tf } - let cfg-tln = if num-tln != none { num-tln } else { co-TLN } - let cfg-tl = if num-tl != none { num-tl } else { co-TL } + let cfg-nlc = if num-nlc != none { num-nlc } else { co_NLC } + let cfg-tf = if num-tf != none { num-tf } else { co_tf } + let cfg-tln = if num-tln != none { num-tln } else { co_TLN } + let cfg-tl = if num-tl != none { num-tl } else { co_TL } let actual-bank = if type(bank-data) == dictionary and "data" in bank-data { bank-data.data @@ -311,7 +311,7 @@ toan-setup({ if title != none and title != "" { v(0.5em) - align(center)[#text(fill: mausac.duong, weight: "bold", size: 13pt)[#title]] + align(center)[#text(fill: mau-sac.duong, weight: "bold", size: 13pt)[#title]] v(0.3em) } @@ -320,7 +320,7 @@ set par(first-line-indent: 0pt) v(-0.5em) if cm == 1 { - text(fill: mausac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẮC NGHIỆM NHIỀU LỰA CHỌN] + text(fill: mau-sac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẮC NGHIỆM NHIỀU LỰA CHỌN] } let c-idx = 0 for item in ds-NLC { @@ -329,8 +329,8 @@ let start-c = c-idx + 1 let end-c = c-idx + n-sub block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau-pa, weight: "bold")[Dữ kiện dùng cho từ Câu #start-c đến Câu #end-c:] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mau-sac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mau-sac.cau-pa, weight: "bold")[Dữ kiện dùng cho từ Câu #start-c đến Câu #end-c:] \ #v(0.1em) #item.du-kien ] ] @@ -348,7 +348,7 @@ align: (left + top, center + top), [ #v(-0.4em) - #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd \ + #text(fill: mau-sac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd \ #v(-0.3em) #let is-img-option = q.pa.any(opt => { @@ -366,7 +366,7 @@ ..q.pa.enumerate().map(((i, v)) => { let is-correct = show-lg and ("da" in q) and (i == q.da) let label-text = [#h(1em)*#to-abc(i).*] - let formatted-label = if is-correct { underline(text(fill: mausac.daT, weight: "bold")[#label-text]) } else { text(fill: mausac.cau-pa)[#label-text] } + let formatted-label = if is-correct { underline(text(fill: mau-sac.daT, weight: "bold")[#label-text]) } else { text(fill: mau-sac.cau-pa)[#label-text] } align(left)[#grid(columns:(auto,1fr), column-gutter:10pt, [#formatted-label], [#v])] }) ) @@ -381,7 +381,7 @@ ..q.pa.enumerate().map(((i, v)) => { let is-correct = show-lg and ("da" in q) and (i == q.da) let label-text = [*#to-abc(i).*] - let formatted-label = if is-correct { underline(text(fill: mausac.daT, weight: "bold")[#label-text]) } else { text(fill: mausac.cau-pa)[#label-text] } + let formatted-label = if is-correct { underline(text(fill: mau-sac.daT, weight: "bold")[#label-text]) } else { text(fill: mau-sac.cau-pa)[#label-text] } box[#grid(columns: (auto, 1fr), gutter: 2pt, align: left, formatted-label, v)] }) ) #v(0.5em) @@ -400,7 +400,7 @@ if ds-TF.len() > 0 { set par(first-line-indent: 0pt) v(-0.1em) - if cm == 1 { text(fill: mausac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } + if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } let c-idx = 0 for item in ds-TF { if item.du-kien != none and item.du-kien != [] { @@ -408,8 +408,8 @@ let start-c = c-idx + 1 let end-c = c-idx + n-sub block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau-pa, weight: "bold")[Dữ kiện dùng cho Câu #start-c đến Câu #end-c:] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mau-sac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mau-sac.cau-pa, weight: "bold")[Dữ kiện dùng cho Câu #start-c đến Câu #end-c:] \ #v(0.1em) #item.du-kien ] ] @@ -425,17 +425,17 @@ align: (left + top, center + top), [ #v(0.2em) - #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd \ + #text(fill: mau-sac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd \ #list( marker: none, spacing: 0.7em, ..q.ytf.enumerate().map(((i, sq)) => { let label-text = [#("a)", "b)", "c)", "d)").at(i)] - let formatted-label = text(fill: mausac.cau-pa, weight: "bold")[#h(0.5em) #label-text] + let formatted-label = text(fill: mau-sac.cau-pa, weight: "bold")[#h(0.5em) #label-text] let ans-str = if show-lg and ("da" in q) and type(q.da) == array and i < q.da.len() { if q.da.at(i) == 1 { " [Đúng]" } else { " [Sai]" } } else { "" } - [#formatted-label #sq #text(fill: mausac.daT, weight: "bold")[#ans-str]] + [#formatted-label #sq #text(fill: mau-sac.daT, weight: "bold")[#ans-str]] }) ) ], @@ -452,7 +452,7 @@ if ds-TLN.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) - if cm == 1 { text(fill: mausac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } + if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } let c-idx = 0 for item in ds-TLN { if item.du-kien != none and item.du-kien != [] { @@ -460,8 +460,8 @@ let start-c = c-idx + 1 let end-c = c-idx + n-sub block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau-pa, weight: "bold", style: "italic")[Dữ kiện dùng cho Câu #start-c đến Câu #end-c:] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mau-sac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mau-sac.cau-pa, weight: "bold", style: "italic")[Dữ kiện dùng cho Câu #start-c đến Câu #end-c:] \ #v(0.1em) #text(style: "italic")[#item.du-kien] ] ] @@ -478,7 +478,7 @@ align: (left + top, center + horizon), [ #v(-0.1em) - #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd + #text(fill: mau-sac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd #v(0.1em) #if not show-lg [ #grid( @@ -514,7 +514,7 @@ if ds-TL.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) - if cm == 1 { text(fill: mausac.cau-pa, weight: "bold", size: 11pt)[► BÀI TẬP TỰ LUẬN] } + if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 11pt)[► BÀI TẬP TỰ LUẬN] } let c-idx = 0 for item in ds-TL { for q in item.cau-hoi-con { @@ -528,7 +528,7 @@ align: (left + top, center + top), [ #v(-0.4em) - #text(fill: mausac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd + #text(fill: mau-sac.cau-pa, weight: "bold")[Câu #c-idx.] #q.nd #v(0.5em) ], if has-img [ #if type(q.hv) == content { q.hv } else { image(q.hv, width: 4.5cm) } #v(1em)] @@ -638,7 +638,7 @@ }) set par(first-line-indent: 0pt) v(-0.1em) - text(fill: mausac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.* #emph[*Mỗi câu thí sinh chỉ được chọn một phương án.*]#v(0.2em)] + text(fill: mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.* #emph[*Mỗi câu thí sinh chỉ được chọn một phương án.*]#v(0.2em)] let c-idx = 0 for item in s-NLC { @@ -649,8 +649,8 @@ let end-num = c-idx + n-sub v(0.2em) block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau-pa)[*Dữ kiện dùng cho từ Câu #start-num đến Câu #end-num:*] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mau-sac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mau-sac.cau-pa)[*Dữ kiện dùng cho từ Câu #start-num đến Câu #end-num:*] \ #v(0.1em) #item.du-kien ] ] @@ -672,7 +672,7 @@ align: (left + top, center + horizon), [ #v(-0.3em) - #text(fill: mausac.cau-pa)[*Câu #(c-idx + 1).*] #q.nd \ + #text(fill: mau-sac.cau-pa)[*Câu #(c-idx + 1).*] #q.nd \ #v(-0.3em) #let is-img-option = new-opts.any(opt => { let r = repr(opt) @@ -682,13 +682,13 @@ #grid( columns: (1fr, 1fr, 1fr, 1fr), column-gutter: 0.8em, row-gutter: 0.5em, align: center + horizon, - ..new-opts.enumerate().map(((i, v)) => [#align(center)[#text(fill: mausac.cau-pa)[*#to-abc(i).*]) #v]]) + ..new-opts.enumerate().map(((i, v)) => [#align(center)[#text(fill: mau-sac.cau-pa)[*#to-abc(i).*]) #v]]) ) ] else [ #let n-cols = if "cot" in q { q.cot } else { 4 } #grid( columns: (1fr,) * n-cols, row-gutter: 0.6em, column-gutter: 1.2em, align: left + horizon, - ..new-opts.enumerate().map(((i, v)) => [#text(fill: mausac.cau-pa)[#h(1em)*#to-abc(i).*] #v]) + ..new-opts.enumerate().map(((i, v)) => [#text(fill: mau-sac.cau-pa)[#h(1em)*#to-abc(i).*] #v]) ) ] ], @@ -705,7 +705,7 @@ if s-tf.len() > 0 { set par(first-line-indent: 0pt) - v(0.5em); text(mausac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #s-tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] + v(0.5em); text(mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #s-tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] for (idx, q) in s-tf.enumerate() { let sub-indices = if tf-mode == "none" { range(4) } else if tf-mode == "y-only" { @@ -721,8 +721,8 @@ #grid( columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), [ - #text(fill: mausac.cau-pa)[*Câu #(idx + 1).* ]#q.nd \ - #list(marker: none, spacing: 0.7em, ..new-subs.enumerate().map(((i, sq)) => [#h(0.5em) #text(fill: mausac.cau-pa)[#strong[#("a)", "b)", "c)", "d)").at(i)]] #sq])) + #text(fill: mau-sac.cau-pa)[*Câu #(idx + 1).* ]#q.nd \ + #list(marker: none, spacing: 0.7em, ..new-subs.enumerate().map(((i, sq)) => [#h(0.5em) #text(fill: mau-sac.cau-pa)[#strong[#("a)", "b)", "c)", "d)").at(i)]] #sq])) ], if has-img [ #align(center + horizon)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) @@ -738,7 +738,7 @@ if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) - v(0.5em); text(fill: mausac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.*] + v(0.5em); text(fill: mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.*] let c-idx = 0 for item in s-TLN { let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item @@ -750,8 +750,8 @@ let end-num = c-idx + n-sub v(0.2em) block(width: 100%, breakable: false)[ - #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mausac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ - #text(fill: mausac.cau-pa)[*Dữ kiện dùng cho từ Câu #start-num đến Câu #end-num:*] \ + #rect(width: 100%, fill: rgb("#f8f9fa"), stroke: (left: 2.5pt + mau-sac.cau-pa), inset: (x: 8pt, y: 6pt), radius: (right: 3pt))[ + #text(fill: mau-sac.cau-pa)[*Dữ kiện dùng cho từ Câu #start-num đến Câu #end-num:*] \ #v(0.1em) #item.du-kien ] ] @@ -765,7 +765,7 @@ #grid( columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + horizon), [ - #text(fill: mausac.cau-pa)[*Câu #(c-idx + 1).* ]#q.nd + #text(fill: mau-sac.cau-pa)[*Câu #(c-idx + 1).* ]#q.nd #if not show-lg [ #v(-0.4em) #pad(left: 0em)[ @@ -786,7 +786,7 @@ if s-TL.len() > 0 { set par(first-line-indent: 0pt) - v(0.3em); text(mausac.cau-pa)[*► TỰ LUẬN (#s-TL.len() câu)*] + v(0.3em); text(mau-sac.cau-pa)[*► TỰ LUẬN (#s-TL.len() câu)*] v(-0.3em) for (idx, q) in s-TL.enumerate() { part4-ans.push((nd: q.nd, lg: q.lg)) @@ -795,7 +795,7 @@ #let has-img = "hv" in q and q.hv != none and q.hv != "" #grid( columns: if has-img { (1fr, auto) } else { (1fr,) }, gutter: 10pt, align: (left + top, center + top), - [ #text(fill: mausac.cau-pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], + [ #text(fill: mau-sac.cau-pa)[*Câu #(idx + 1).* ] #q.nd \ #v(-0.3em) ], if has-img [ #align(center + top)[#if type(q.hv) == content [ #q.hv ] else if type(q.hv) == str [ #image(q.hv, width: 4.5cm) ]] ] ) #if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TL", idx, seed) } @@ -841,7 +841,7 @@ #text(11pt, fill: blue.darken(40%))[*Lời giải:* ] #v(-0.5em) #block(inset: 12pt, fill: yellow.lighten(95%), radius: 4pt, width: 100%)[ - #text(fill: mausac.cau-pa, style: "italic")[#ans.lg] + #text(fill: mau-sac.cau-pa, style: "italic")[#ans.lg] ] #v(-0.5em) ] @@ -900,7 +900,7 @@ return res-chum + res-don } -#let tron-de-bank-Level(banks-matrix, info, show-lg: false, hien-thi-bang-da-pan: true, theo-lv: false) = { +#let tron-de-bank-Level(banks-matrix, info, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: false) = { for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) let base-seed = int(ma-de) @@ -948,7 +948,7 @@ } } - if hien-thi-bang-da-pan { + if hien-thi-bang-dap-an { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -1015,7 +1015,7 @@ info, seed-goc: 2024, show-lg: false, - hien-thi-bang-da-pan: true, + hien-thi-bang-dap-an: true, tf-mode: "y-only", nlc-mode: "full", theo-lv: false, @@ -1075,7 +1075,7 @@ } } - if hien-thi-bang-da-pan { + if hien-thi-bang-dap-an { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] @@ -1142,7 +1142,7 @@ info, seed-goc: 2024, show-lg: false, - hien-thi-bang-da-pan: true, + hien-thi-bang-dap-an: true, xao-cau: true, xao-pa: true, theo-lv: false, @@ -1207,7 +1207,7 @@ } } - if hien-thi-bang-da-pan { + if hien-thi-bang-dap-an { pagebreak() context { counter(page).update(1); set page(footer: none) } align(center)[#text(16pt, weight: "bold")[BẢNG ĐÁP ÁN TRẮC NGHIỆM TỔNG HỢP]] From 7370384d6e98497b831a240f7a75d2d21d56e831 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 15:55:20 +0700 Subject: [PATCH 26/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 242 +++++++++++++------------- 1 file changed, 121 insertions(+), 121 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 457d2341e1..6e6c907454 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -97,10 +97,10 @@ } // ========================================== -// 3. HÀM TẠO QR & HIỂN THỊ LỜI GIẢI +// 3. HÀM TẠO qr & HIỂN THỊ LỜI GIẢI // ========================================== -#let tao-QR-code-key(results) = { - let all_content = "" +#let tao-qr-code-key(results) = { + let all-content = "" for entry in results { let ma-de = str(entry.value.seed) let part1 = entry.value.part1.join("") @@ -220,16 +220,16 @@ num-tl: none, show-lg: false, dong-ke: none, - co_NLC: none, + co_nlc: none, co_tf: none, - co_TLN: none, - co_TL: none, + co_tln: none, + co_tl: none, theo-lv: false, ) = { - let cfg-nlc = if num-nlc != none { num-nlc } else { co_NLC } + let cfg-nlc = if num-nlc != none { num-nlc } else { co_nlc } let cfg-tf = if num-tf != none { num-tf } else { co_tf } - let cfg-tln = if num-tln != none { num-tln } else { co_TLN } - let cfg-tl = if num-tl != none { num-tl } else { co_TL } + let cfg-tln = if num-tln != none { num-tln } else { co_tln } + let cfg-tl = if num-tl != none { num-tl } else { co_tl } let actual-bank = if type(bank-data) == dictionary and "data" in bank-data { bank-data.data @@ -303,10 +303,10 @@ return loc-ques } - let ds-NLC = rut-cau("NLC", cfg-nlc, 107) - let ds-TF = rut-cau("TF", cfg-tf, 233) - let ds-TLN = rut-cau("TLN", cfg-tln, 357) - let ds-TL = rut-cau("TL", cfg-tl, 491) + let ds-nlc = rut-cau("NLC", cfg-nlc, 107) + let ds-tf = rut-cau("TF", cfg-tf, 233) + let ds-tln = rut-cau("TLN", cfg-tln, 357) + let ds-tl = rut-cau("TL", cfg-tl, 491) toan-setup({ if title != none and title != "" { @@ -316,14 +316,14 @@ } // PHẦN I: NLC - if ds-NLC.len() > 0 { + if ds-nlc.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẮC NGHIỆM NHIỀU LỰA CHỌN] } let c-idx = 0 - for item in ds-NLC { + for item in ds-nlc { if item.du-kien != none and item.du-kien != [] { let n-sub = item.cau-hoi-con.len() let start-c = c-idx + 1 @@ -397,12 +397,12 @@ } // PHẦN II: TF - if ds-TF.len() > 0 { + if ds-tf.len() > 0 { set par(first-line-indent: 0pt) v(-0.1em) if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI ĐÚNG/SAI] } let c-idx = 0 - for item in ds-TF { + for item in ds-tf { if item.du-kien != none and item.du-kien != [] { let n-sub = item.cau-hoi-con.len() let start-c = c-idx + 1 @@ -449,12 +449,12 @@ } // PHẦN III: TLN - if ds-TLN.len() > 0 { + if ds-tln.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 13pt)[► BÀI TẬP TRẢ LỜI NGẮN] } let c-idx = 0 - for item in ds-TLN { + for item in ds-tln { if item.du-kien != none and item.du-kien != [] { let n-sub = item.cau-hoi-con.len() let start-c = c-idx + 1 @@ -511,12 +511,12 @@ } // PHẦN IV: TL - if ds-TL.len() > 0 { + if ds-tl.len() > 0 { set par(first-line-indent: 0pt) v(-0.5em) if cm == 1 { text(fill: mau-sac.cau-pa, weight: "bold", size: 11pt)[► BÀI TẬP TỰ LUẬN] } let c-idx = 0 - for item in ds-TL { + for item in ds-tl { for q in item.cau-hoi-con { c-idx += 1 v(-0.4em) @@ -577,25 +577,25 @@ let seed = int(ma-de) - let raw-NLC = q-bank.filter(matrix.NLC-loc) - let xao-NLC = xao-theo-tuy-chon(raw-NLC, seed + 107, theo-lv: theo-lv) - let NLC-dem = calc.min(matrix.NLC-dem, xao-NLC.len()) - let s-NLC = xao-NLC.slice(0, NLC-dem) + let raw-nlc = q-bank.filter(matrix.nlc-loc) + let xao-nlc = xao-theo-tuy-chon(raw-nlc, seed + 107, theo-lv: theo-lv) + let nlc-dem = calc.min(matrix.nlc-dem, xao-nlc.len()) + let s-nlc = xao-nlc.slice(0, nlc-dem) let raw-tf = q-bank.filter(matrix.tf-loc) let xao-tf = xao-theo-tuy-chon(raw-tf, seed + 233, theo-lv: theo-lv) let tf-dem = calc.min(matrix.tf-dem, xao-tf.len()) let s-tf = xao-tf.slice(0, tf-dem) - let raw-TLN = q-bank.filter(matrix.TLN-loc) - let xao-TLN = xao-theo-tuy-chon(raw-TLN, seed + 357, theo-lv: theo-lv) - let TLN-dem = calc.min(matrix.TLN-dem, xao-TLN.len()) - let s-TLN = xao-TLN.slice(0, TLN-dem) + let raw-tln = q-bank.filter(matrix.tln-loc) + let xao-tln = xao-theo-tuy-chon(raw-tln, seed + 357, theo-lv: theo-lv) + let tln-dem = calc.min(matrix.tln-dem, xao-tln.len()) + let s-tln = xao-tln.slice(0, tln-dem) - let raw-TL = q-bank.filter(matrix.TL-loc) - let xao-TL = xao-theo-tuy-chon(raw-TL, seed + 491, theo-lv: theo-lv) - let TL-dem = calc.min(matrix.TL-dem, xao-TL.len()) - let s-TL = xao-TL.slice(0, TL-dem) + let raw-tl = q-bank.filter(matrix.tl-loc) + let xao-tl = xao-theo-tuy-chon(raw-tl, seed + 491, theo-lv: theo-lv) + let tl-dem = calc.min(matrix.tl-dem, xao-tl.len()) + let s-tl = xao-tl.slice(0, tl-dem) let part1-ans = () let part2-ans = () @@ -632,8 +632,8 @@ ) line(length: 100%, stroke: 0.5pt) - if s-NLC.len() > 0 { - let tong-so-cau = s-NLC.fold(0, (acc, q) => { + if s-nlc.len() > 0 { + let tong-so-cau = s-nlc.fold(0, (acc, q) => { if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) @@ -641,7 +641,7 @@ text(fill: mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.* #emph[*Mỗi câu thí sinh chỉ được chọn một phương án.*]#v(0.2em)] let c-idx = 0 - for item in s-NLC { + for item in s-nlc { let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item if is-item-chum { let n-sub = item.cau-hoi-con.len() @@ -728,19 +728,19 @@ ) ] v(-0.4em) - if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TF", idx + s-NLC.len(), seed, tf-indices: sub-indices) } + if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TF", idx + s-nlc.len(), seed, tf-indices: sub-indices) } v(-0.3em) } } - if s-TLN.len() > 0 { - let tong-so-cau = s-TLN.fold(0, (acc, q) => { + if s-tln.len() > 0 { + let tong-so-cau = s-tln.fold(0, (acc, q) => { if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } }) set par(first-line-indent: 0pt) v(0.5em); text(fill: mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.*] let c-idx = 0 - for item in s-TLN { + for item in s-tln { let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item let ds-cau-can-ve = if is-item-chum { item.cau-hoi-con } else { (item,) } @@ -777,18 +777,18 @@ ) ] v(-1em) - if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TLN", c-idx + s-NLC.len() + s-tf.len(), seed) } + if show-lg and "lg" in q and q.lg != [] { hien-thi-lg(q, "TLN", c-idx + s-nlc.len() + s-tf.len(), seed) } v(-0.2em) c-idx += 1 } } } - if s-TL.len() > 0 { + if s-tl.len() > 0 { set par(first-line-indent: 0pt) - v(0.3em); text(mau-sac.cau-pa)[*► TỰ LUẬN (#s-TL.len() câu)*] + v(0.3em); text(mau-sac.cau-pa)[*► TỰ LUẬN (#s-tl.len() câu)*] v(-0.3em) - for (idx, q) in s-TL.enumerate() { + for (idx, q) in s-tl.enumerate() { part4-ans.push((nd: q.nd, lg: q.lg)) v(-0.3em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ @@ -816,7 +816,7 @@ )) ] } -#let in-dap-an-TL(results) = { +#let in-dap-an-tl(results) = { context { counter(page).update(1) set page(footer: none) @@ -826,7 +826,7 @@ v(-0.2em) for entry in results { let ma-de = str(entry.value.seed) - let lg-TL = entry.value.part4 + let lg-tl = entry.value.part4 if lg-TL.len() > 0 { align(left)[ #block(fill: gray.lighten(80%), inset: 5pt, radius: 4pt)[ @@ -900,45 +900,45 @@ return res-chum + res-don } -#let tron-de-bank-Level(banks-matrix, info, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: false) = { +#let tron-de-bank-level(banks-matrix, info, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: false) = { for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) let base-seed = int(ma-de) - let rut-NLC = () + let rut-nlc = () let rut-tf = () - let rut-TLN = () - let rut-TL = () + let rut-tln = () + let rut-tl = () for (b-idx, item) in banks-matrix.enumerate() { let b = item.bank - let NLC-seed = base-seed * 999999 + b-idx * 999999 + 107 + let nlc-seed = base-seed * 999999 + b-idx * 999999 + 107 let tf-seed = base-seed * 999999 + b-idx * 999999 + 233 - let TLN-seed = base-seed * 999999 + b-idx * 999999 + 357 - let TL-seed = base-seed * 999999 + b-idx * 999999 + 491 + let tln-seed = base-seed * 999999 + b-idx * 999999 + 357 + let tl-seed = base-seed * 999999 + b-idx * 999999 + 491 - if "NLC-dem" in item { rut-NLC += rut-cau-Level(b, "NLC", item.NLC-dem, NLC-seed) } + if "nlc-dem" in item { rut-nlc += rut-cau-Level(b, "NLC", item.nlc-dem, nlc-seed) } if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } - if "TLN-dem" in item { rut-TLN += rut-cau-Level(b, "TLN", item.TLN-dem, TLN-seed) } - if "TL-dem" in item { rut-TL += rut-cau-Level(b, "TL", item.TL-dem, TL-seed) } + if "tln-dem" in item { rut-tln += rut-cau-Level(b, "TLN", item.tln-dem, tln-seed) } + if "tl-dem" in item { rut-tl += rut-cau-Level(b, "TL", item.tl-dem, tl-seed) } } - rut-NLC = xao-theo-tuy-chon(rut-NLC, base-seed + 991, theo-lv: theo-lv) + rut-nlc = xao-theo-tuy-chon(rut-nlc, base-seed + 991, theo-lv: theo-lv) rut-tf = xao-theo-tuy-chon(rut-tf, base-seed + 997, theo-lv: theo-lv) - rut-TLN = xao-theo-tuy-chon(rut-TLN, base-seed + 1009, theo-lv: theo-lv) - rut-TL = xao-theo-tuy-chon(rut-TL, base-seed + 1013, theo-lv: theo-lv) + rut-tln = xao-theo-tuy-chon(rut-tln, base-seed + 1009, theo-lv: theo-lv) + rut-tl = xao-theo-tuy-chon(rut-tl, base-seed + 1013, theo-lv: theo-lv) - let final-bank = rut-NLC + rut-tf + rut-TLN + rut-TL + let final-bank = rut-nlc + rut-tf + rut-tln + rut-tl let fake-matrix = ( - NLC-loc: q => q.type == "NLC", - NLC-dem: rut-NLC.len(), + nlc-loc: q => q.type == "NLC", + nlc-dem: rut-nlc.len(), tf-loc: q => q.type == "TF", tf-dem: rut-tf.len(), - TLN-loc: q => q.type == "TLN", - TLN-dem: rut-TLN.len(), - TL-loc: q => q.type == "TL", - TL-dem: rut-TL.len(), + tln-loc: q => q.type == "TLN", + tln-dem: rut-tln.len(), + tl-loc: q => q.type == "TL", + tl-dem: rut-tl.len(), ) render-test(ma-de, final-bank, fake-matrix, info, is-first: is-first, show-lg: show-lg, theo-lv: theo-lv) @@ -986,17 +986,17 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dap-an-TL(results) + in-dap-an-tl(results) } } pagebreak() context { counter(page).update(1); set page(footer: none) } - align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] + align(center)[#text(16pt, weight: "bold")[MÃ QRCODE ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { let results = query() - let all-qrcode = tao-QR-code-key(results) + let all-qrcode = tao-qr-code-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ @@ -1010,7 +1010,7 @@ } } -#let tron-de-chi-Y( +#let tron-de-chi-y( banks-matrix, info, seed-goc: 2024, @@ -1020,42 +1020,42 @@ nlc-mode: "full", theo-lv: false, ) = { - let rut-NLC = () + let rut-nlc = () let rut-tf = () - let rut-TLN = () - let rut-TL = () + let rut-tln = () + let rut-tl = () for (b-idx, item) in banks-matrix.enumerate() { let b = item.bank - let NLC-seed = seed-goc * 999999 + b-idx * 999999 + 107 + let nlc-seed = seed-goc * 999999 + b-idx * 999999 + 107 let tf-seed = seed-goc * 999999 + b-idx * 999999 + 233 - let TLN-seed = seed-goc * 999999 + b-idx * 999999 + 357 - let TL-seed = seed-goc * 999999 + b-idx * 999999 + 491 + let tln-seed = seed-goc * 999999 + b-idx * 999999 + 357 + let tl-seed = seed-goc * 999999 + b-idx * 999999 + 491 - if "NLC-dem" in item { rut-NLC += rut-cau-Level(b, "NLC", item.NLC-dem, NLC-seed) } + if "nlc-dem" in item { rut-nlc += rut-cau-Level(b, "NLC", item.nlc-dem, nlc-seed) } if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } - if "TLN-dem" in item { rut-TLN += rut-cau-Level(b, "TLN", item.TLN-dem, TLN-seed) } - if "TL-dem" in item { rut-TL += rut-cau-Level(b, "TL", item.TL-dem, TL-seed) } + if "tln-dem" in item { rut-tln += rut-cau-Level(b, "TLN", item.tln-dem, tln-seed) } + if "tl-dem" in item { rut-tl += rut-cau-Level(b, "TL", item.tl-dem, tl-seed) } } - rut-NLC = tron-mang(rut-NLC, seed-goc + 991) + rut-nlc = tron-mang(rut-nlc, seed-goc + 991) rut-tf = tron-mang(rut-tf, seed-goc + 997) - rut-TLN = tron-mang(rut-TLN, seed-goc + 1009) - rut-TL = tron-mang(rut-TL, seed-goc + 1013) + rut-tln = tron-mang(rut-tln, seed-goc + 1009) + rut-tl = tron-mang(rut-tl, seed-goc + 1013) for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) - let final-bank = rut-NLC + rut-tf + rut-TLN + rut-TL + let final-bank = rut-nlc + rut-tf + rut-tln + rut-tl let fake-matrix = ( - NLC-loc: q => q.type == "NLC", - NLC-dem: rut-NLC.len(), + nlc-loc: q => q.type == "NLC", + nlc-dem: rut-nlc.len(), tf-loc: q => q.type == "TF", tf-dem: rut-tf.len(), - TLN-loc: q => q.type == "TLN", - TLN-dem: rut-TLN.len(), - TL-loc: q => q.type == "TL", - TL-dem: rut-TL.len(), + tln-loc: q => q.type == "TLN", + tln-dem: rut-tln.len(), + tl-loc: q => q.type == "TL", + tl-dem: rut-tl.len(), ) render-test( @@ -1113,17 +1113,17 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dap-an-TL(results) + in-dap-an-tl(results) } } pagebreak() context { counter(page).update(1); set page(footer: none) } - align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] + align(center)[#text(16pt, weight: "bold")[MÃ qr ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { let results = query() - let all-qrcode = tao-QR-code-key(results) + let all-qrcode = tao-qr-code-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ @@ -1137,7 +1137,7 @@ } } -#let tron-de-cung-Noi-Dung( +#let tron-de-cung-noi-dung( banks-matrix, info, seed-goc: 2024, @@ -1147,49 +1147,49 @@ xao-pa: true, theo-lv: false, ) = { - let rut-NLC = () + let rut-nlc = () let rut-tf = () - let rut-TLN = () - let rut-TL = () + let rut-tln = () + let rut-tl = () for (b-idx, item) in banks-matrix.enumerate() { let b = item.bank - let NLC-seed = seed-goc * 999999 + b-idx * 999999 + 107 + let nlc-seed = seed-goc * 999999 + b-idx * 999999 + 107 let tf-seed = seed-goc * 999999 + b-idx * 999999 + 233 - let TLN-seed = seed-goc * 999999 + b-idx * 999999 + 357 - let TL-seed = seed-goc * 999999 + b-idx * 999999 + 491 + let tln-seed = seed-goc * 999999 + b-idx * 999999 + 357 + let tl-seed = seed-goc * 999999 + b-idx * 999999 + 491 - if "NLC-dem" in item { rut-NLC += rut-cau-Level(b, "NLC", item.NLC-dem, NLC-seed) } + if "nlc-dem" in item { rut-nlc += rut-cau-Level(b, "NLC", item.nlc-dem, nlc-seed) } if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } - if "TLN-dem" in item { rut-TLN += rut-cau-Level(b, "TLN", item.TLN-dem, TLN-seed) } - if "TL-dem" in item { rut-TL += rut-cau-Level(b, "TL", item.TL-dem, TL-seed) } + if "tln-dem" in item { rut-tln += rut-cau-Level(b, "TLN", item.tln-dem, tln-seed) } + if "tl-dem" in item { rut-tl += rut-cau-Level(b, "TL", item.tl-dem, tl-seed) } } - rut-NLC = tron-mang(rut-NLC, seed-goc + 991) + rut-nlc = tron-mang(rut-nlc, seed-goc + 991) rut-tf = tron-mang(rut-tf, seed-goc + 997) - rut-TLN = tron-mang(rut-TLN, seed-goc + 1009) - rut-TL = tron-mang(rut-TL, seed-goc + 1013) + rut-tln = tron-mang(rut-tln, seed-goc + 1009) + rut-tl = tron-mang(rut-tl, seed-goc + 1013) for (i, ma-de) in info.ds-ma-de.enumerate() { let is-first = (i == 0) let base-seed = int(ma-de) - let final-NLC = if xao-cau { xao-theo-tuy-chon(rut-NLC, base-seed + 2001, theo-lv: theo-lv) } else { rut-NLC } + let final-nlc = if xao-cau { xao-theo-tuy-chon(rut-nlc, base-seed + 2001, theo-lv: theo-lv) } else { rut-nlc } let final-tf = if xao-cau { xao-theo-tuy-chon(rut-tf, base-seed + 2011, theo-lv: theo-lv) } else { rut-tf } - let final-TLN = if xao-cau { xao-theo-tuy-chon(rut-TLN, base-seed + 2027, theo-lv: theo-lv) } else { rut-TLN } - let final-TL = if xao-cau { xao-theo-tuy-chon(rut-TL, base-seed + 2039, theo-lv: theo-lv) } else { rut-TL } + let final-tln = if xao-cau { xao-theo-tuy-chon(rut-tln, base-seed + 2027, theo-lv: theo-lv) } else { rut-tln } + let final-tl = if xao-cau { xao-theo-tuy-chon(rut-tl, base-seed + 2039, theo-lv: theo-lv) } else { rut-tl } - let final-bank = final-NLC + final-tf + final-TLN + final-TL + let final-bank = final-nlc + final-tf + final-tln + final-tl let fake-matrix = ( - NLC-loc: q => q.type == "NLC", - NLC-dem: final-NLC.len(), + nlc-loc: q => q.type == "NLC", + nlc-dem: final-nlc.len(), tf-loc: q => q.type == "TF", tf-dem: final-tf.len(), - TLN-loc: q => q.type == "TLN", - TLN-dem: final-TLN.len(), - TL-loc: q => q.type == "TL", - TL-dem: final-TL.len(), + tln-loc: q => q.type == "TLN", + tln-dem: final-tln.len(), + tl-loc: q => q.type == "TL", + tl-dem: final-tl.len(), ) render-test( @@ -1245,17 +1245,17 @@ context { let results = query() if results.any(r => r.value.part4.len() > 0) { - in-dap-an-TL(results) + in-dap-an-tl(results) } } pagebreak() context { counter(page).update(1); set page(footer: none) } - align(center)[#text(16pt, weight: "bold")[MÃ QR ĐÁP ÁN TRẮC NGHIỆM]] + align(center)[#text(16pt, weight: "bold")[MÃ qr ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { let results = query() - let all-qrcode = tao-QR-code-key(results) + let all-qrcode = tao-qr-code-key(results) align(center)[ #block(inset: 15pt, fill: white, radius: 8pt, stroke: gray.lighten(30%) + 1pt)[ #text(size: 14pt, weight: "bold")[ĐÁP ÁN TRẮC NGHIỆM CÁC MÃ ĐỀ] \ @@ -1346,6 +1346,6 @@ // 7. BÍ DANH TIẾNG ANH (API CHUẨN UNIVERSE) // ========================================== #let exercise = bai-tap-in-line -#let make-exam-matrix = tron-de-bank-Level -#let make-exam-sync = tron-de-cung-Noi-Dung -#let make-exam-sub-only = tron-de-chi-Y +#let make-exam-matrix = tron-de-bank-level +#let make-exam-sync = tron-de-cung-noi-dung +#let make-exam-sub-only = tron-de-chi-y From 20323fa0da693b47d3583a05df1a05e29e6210c6 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 15:57:24 +0700 Subject: [PATCH 27/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index 0a5c43eb81..cdbd0262e1 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -161,14 +161,15 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction Tạo các đề thi bằng cách rút ngẫu nhiên câu hỏi từ ngân hàng đề: ```typst +#import "@preview/v-exam:0.1.0": make-exam-matrix, tron-de-bank-level #import "file.typ" as b #let matrix = ( ( bank: b.data, - NLC-dem: (1, 0, 0), + nlc-dem: (1, 0, 0), tf-dem: (0, 1, 0), - TLN-dem: (0, 1, 0), - TL-dem: (0, 1, 0), + tln-dem: (0, 1, 0), + tl-dem: (0, 1, 0), ), ) From 47bd2433d08236cca204f21cd1ab15a447d3de76 Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 16:24:31 +0700 Subject: [PATCH 28/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 6e6c907454..6732b9bd6d 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -220,16 +220,16 @@ num-tl: none, show-lg: false, dong-ke: none, - co_nlc: none, - co_tf: none, - co_tln: none, - co_tl: none, + co-nlc: none, + co-tf: none, + co-tln: none, + co-tl: none, theo-lv: false, ) = { - let cfg-nlc = if num-nlc != none { num-nlc } else { co_nlc } - let cfg-tf = if num-tf != none { num-tf } else { co_tf } - let cfg-tln = if num-tln != none { num-tln } else { co_tln } - let cfg-tl = if num-tl != none { num-tl } else { co_tl } + let cfg-nlc = if num-nlc != none { num-nlc } else { co-nlc } + let cfg-tf = if num-tf != none { num-tf } else { co-tf } + let cfg-tln = if num-tln != none { num-tln } else { co-tln } + let cfg-tl = if num-tl != none { num-tl } else { co-tl } let actual-bank = if type(bank-data) == dictionary and "data" in bank-data { bank-data.data @@ -851,7 +851,7 @@ }) } -#let rut-cau-Level(raw-bank, q-type, dem-config, seed) = { +#let rut-cau-level(raw-bank, q-type, dem-config, seed) = { let actual-bank = if type(raw-bank) == dictionary and "data" in raw-bank { raw-bank.data } else if type(raw-bank) == module { raw-bank.data } else { raw-bank } @@ -917,10 +917,10 @@ let tln-seed = base-seed * 999999 + b-idx * 999999 + 357 let tl-seed = base-seed * 999999 + b-idx * 999999 + 491 - if "nlc-dem" in item { rut-nlc += rut-cau-Level(b, "NLC", item.nlc-dem, nlc-seed) } - if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } - if "tln-dem" in item { rut-tln += rut-cau-Level(b, "TLN", item.tln-dem, tln-seed) } - if "tl-dem" in item { rut-tl += rut-cau-Level(b, "TL", item.tl-dem, tl-seed) } + if "nlc-dem" in item { rut-nlc += rut-cau-level(b, "NLC", item.nlc-dem, nlc-seed) } + if "tf-dem" in item { rut-tf += rut-cau-level(b, "TF", item.tf-dem, tf-seed) } + if "tln-dem" in item { rut-tln += rut-cau-level(b, "TLN", item.tln-dem, tln-seed) } + if "tl-dem" in item { rut-tl += rut-cau-level(b, "TL", item.tl-dem, tl-seed) } } rut-nlc = xao-theo-tuy-chon(rut-nlc, base-seed + 991, theo-lv: theo-lv) @@ -1032,10 +1032,10 @@ let tln-seed = seed-goc * 999999 + b-idx * 999999 + 357 let tl-seed = seed-goc * 999999 + b-idx * 999999 + 491 - if "nlc-dem" in item { rut-nlc += rut-cau-Level(b, "NLC", item.nlc-dem, nlc-seed) } - if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } - if "tln-dem" in item { rut-tln += rut-cau-Level(b, "TLN", item.tln-dem, tln-seed) } - if "tl-dem" in item { rut-tl += rut-cau-Level(b, "TL", item.tl-dem, tl-seed) } + if "nlc-dem" in item { rut-nlc += rut-cau-level(b, "NLC", item.nlc-dem, nlc-seed) } + if "tf-dem" in item { rut-tf += rut-cau-level(b, "TF", item.tf-dem, tf-seed) } + if "tln-dem" in item { rut-tln += rut-cau-level(b, "TLN", item.tln-dem, tln-seed) } + if "tl-dem" in item { rut-tl += rut-cau-level(b, "TL", item.tl-dem, tl-seed) } } rut-nlc = tron-mang(rut-nlc, seed-goc + 991) @@ -1119,7 +1119,7 @@ pagebreak() context { counter(page).update(1); set page(footer: none) } - align(center)[#text(16pt, weight: "bold")[MÃ qr ĐÁP ÁN TRẮC NGHIỆM]] + align(center)[#text(16pt, weight: "bold")[MÃ QRCODE ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { let results = query() @@ -1159,10 +1159,10 @@ let tln-seed = seed-goc * 999999 + b-idx * 999999 + 357 let tl-seed = seed-goc * 999999 + b-idx * 999999 + 491 - if "nlc-dem" in item { rut-nlc += rut-cau-Level(b, "NLC", item.nlc-dem, nlc-seed) } - if "tf-dem" in item { rut-tf += rut-cau-Level(b, "TF", item.tf-dem, tf-seed) } - if "tln-dem" in item { rut-tln += rut-cau-Level(b, "TLN", item.tln-dem, tln-seed) } - if "tl-dem" in item { rut-tl += rut-cau-Level(b, "TL", item.tl-dem, tl-seed) } + if "nlc-dem" in item { rut-nlc += rut-cau-level(b, "NLC", item.nlc-dem, nlc-seed) } + if "tf-dem" in item { rut-tf += rut-cau-level(b, "TF", item.tf-dem, tf-seed) } + if "tln-dem" in item { rut-tln += rut-cau-level(b, "TLN", item.tln-dem, tln-seed) } + if "tl-dem" in item { rut-tl += rut-cau-level(b, "TL", item.tl-dem, tl-seed) } } rut-nlc = tron-mang(rut-nlc, seed-goc + 991) @@ -1251,7 +1251,7 @@ pagebreak() context { counter(page).update(1); set page(footer: none) } - align(center)[#text(16pt, weight: "bold")[MÃ qr ĐÁP ÁN TRẮC NGHIỆM]] + align(center)[#text(16pt, weight: "bold")[MÃ QRCODE ĐÁP ÁN TRẮC NGHIỆM]] v(1em) context { let results = query() @@ -1279,11 +1279,11 @@ ) } -#let dang(title, STT: "1", kieu: "Dạng") = [ +#let dang(title, stt: "1", kieu: "Dạng") = [ #grid( columns: (auto, 1fr), align: center + horizon, column-gutter: -2pt, box(fill: rgb("#72f0b1a2"), radius: 8pt, inset: (x: 10pt, y: 10pt), stroke: 2pt + rgb("#72f0b1a2"))[ - #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #STT:]) + #stack(spacing: 3pt, text(weight: "bold", fill: rgb("#f92a01fd"), size: 1.4em)[#kieu #stt:]) ], box(fill: rgb("#6ff6e484"), width: 100%, radius: 8pt, inset: (x: 15pt, y: 10pt), stroke: 2pt + rgb("#6ff6e484"))[ #text(weight: "bold", fill: rgb("#e90335f8"), size: 1.4em)[#title] From 8d01b66f3b70587d5bb6b214d279b7c21bb0af1c Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Mon, 28 Sep 2026 16:36:25 +0700 Subject: [PATCH 29/30] Update README.md --- packages/preview/v-exam/0.1.0/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/README.md b/packages/preview/v-exam/0.1.0/README.md index cdbd0262e1..df69c23904 100644 --- a/packages/preview/v-exam/0.1.0/README.md +++ b/packages/preview/v-exam/0.1.0/README.md @@ -98,7 +98,7 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction hv: none, lv: 2, nd: [Lời dẫn của câu hỏi], - da: "1.25", + da: 1.25, lg: [Lời giải cho bài toán], dong_ke: 3, ), @@ -107,18 +107,18 @@ Ngân hàng câu hỏi được lưu dưới dạng mảng `array` các `diction type: "TLN", hv: none, lv: 1, - is_chum: true, - du_kien: [Nội dung dùng chung], - cau_hoi_con: ( + is-chum: true, + du-kien: [Nội dung dùng chung], + cau-hoi-con: ( ( nd: [Nội dung lời dẫn câu hỏi 1], - da: "12", + da: 12, lg: [Lời giải 1], dong_ke: 2, ), ( nd: [Nội dung lời dẫn câu hỏi 2], - da: "5", + da: 5, lg: [Lời giải 2], dong_ke: 2, ), @@ -185,7 +185,7 @@ Tạo các đề thi bằng cách rút ngẫu nhiên câu hỏi từ ngân hàng // Gọi lệnh tạo đề: #make-exam-matrix(matrix, info, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: true) // Hoặc alias tiếng Việt: -#tron-de-bank-level(matrix, info, show-lg: false, hienthi-bang-dap-an: true, theo-lv: true) +#tron-de-bank-level(matrix, info, show-lg: false, hien-thi-bang-dap-an: true, theo-lv: true) ``` #### b) Trộn đề cùng nội dung (`make-exam-sync` / `tron-de-cung-noi-dung`) From c21cb566d5fa774afc32a002424deb39f3114bcf Mon Sep 17 00:00:00 2001 From: KieuQuangVu-NCP Date: Tue, 29 Sep 2026 19:59:27 +0700 Subject: [PATCH 30/30] Update lib.typ --- packages/preview/v-exam/0.1.0/lib.typ | 168 ++++++++++++++++++++------ 1 file changed, 128 insertions(+), 40 deletions(-) diff --git a/packages/preview/v-exam/0.1.0/lib.typ b/packages/preview/v-exam/0.1.0/lib.typ index 6732b9bd6d..403efb6d3c 100644 --- a/packages/preview/v-exam/0.1.0/lib.typ +++ b/packages/preview/v-exam/0.1.0/lib.typ @@ -75,7 +75,11 @@ #let tron-mang-theo-lv(arr, seed) = { if arr.len() <= 1 { return arr } - let get-lv(item) = item.at("lv", default: 1) + let get-lv(item) = { + if "lv" in item { item.lv } + else if "cau-hoi-con" in item and item.cau-hoi-con.len() > 0 and "lv" in item.cau-hoi-con.at(0) { item.cau-hoi-con.at(0).lv } + else { 1 } + } let nhom1 = arr.filter(q => get-lv(q) == 1) let nhom2 = arr.filter(q => get-lv(q) == 2) @@ -97,7 +101,7 @@ } // ========================================== -// 3. HÀM TẠO qr & HIỂN THỊ LỜI GIẢI +// 3. HÀM TẠO QR & HIỂN THỊ LỜI GIẢI // ========================================== #let tao-qr-code-key(results) = { let all-content = "" @@ -263,9 +267,24 @@ } }) + let cat-theo-so-cau-con(arr, req-count) = { + if req-count <= 0 or arr.len() == 0 { return () } + let res = () + let current-cnt = 0 + for item in arr { + let n = item.cau-hoi-con.len() + if current-cnt + n <= req-count or res.len() == 0 { + res.push(item) + current-cnt += n + } + if current-cnt >= req-count { break } + } + return res + } + let rut-cau(q-type, dem-config, sub-seed) = { let loc-ques = std-bank.filter(q => q.type == q-type) - if loc-ques.len() == 0 or dem-config == none or dem-config == 0 { return () } + if loc-ques.len() == 0 or dem-config == none { return () } let get-q-lv(item) = { if "lv" in item { item.lv } @@ -275,7 +294,7 @@ if type(dem-config) == int { let processing = if seed == none { loc-ques } else { xao-theo-tuy-chon(loc-ques, seed + sub-seed, theo-lv: theo-lv) } - return processing.slice(0, calc.min(dem-config, processing.len())) + return cat-theo-so-cau-con(processing, dem-config) } if type(dem-config) == array { @@ -293,11 +312,39 @@ b-vd = tron-mang(b-vd, seed + sub-seed + 33) } - let res-nb = b-nb.slice(0, calc.min(nb-req, b-nb.len())) - let res-th = b-th.slice(0, calc.min(th-req, b-th.len())) - let res-vd = b-vd.slice(0, calc.min(vd-req, b-vd.len())) + return cat-theo-so-cau-con(b-nb, nb-req) + cat-theo-so-cau-con(b-th, th-req) + cat-theo-so-cau-con(b-vd, vd-req) + } + + if type(dem-config) == dictionary { + let don-config = dem-config.at("don", default: (0, 0, 0)) + let chum-req = dem-config.at("chum", default: 0) + + let bank-chum = loc-ques.filter(q => q.is-chum == true) + let bank-don = loc-ques.filter(q => q.is-chum != true) + + if seed != none { + bank-chum = tron-mang(bank-chum, seed + sub-seed + 55) + bank-don = tron-mang(bank-don, seed + sub-seed + 77) + } + + let res-chum = bank-chum.slice(0, calc.min(chum-req, bank-chum.len())) + + let res-don = () + if type(don-config) == int { + res-don = cat-theo-so-cau-con(bank-don, don-config) + } else if type(don-config) == array { + let nb-req = don-config.at(0, default: 0) + let th-req = don-config.at(1, default: 0) + let vd-req = don-config.at(2, default: 0) + + let b-nb = bank-don.filter(q => get-q-lv(q) == 1) + let b-th = bank-don.filter(q => get-q-lv(q) == 2) + let b-vd = bank-don.filter(q => get-q-lv(q) == 3) - return res-nb + res-th + res-vd + res-don = cat-theo-so-cau-con(b-nb, nb-req) + cat-theo-so-cau-con(b-th, th-req) + cat-theo-so-cau-con(b-vd, vd-req) + } + + return res-chum + res-don } return loc-ques @@ -633,8 +680,9 @@ line(length: 100%, stroke: 0.5pt) if s-nlc.len() > 0 { - let tong-so-cau = s-nlc.fold(0, (acc, q) => { - if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } + let tong-so-cau = s-nlc.fold(0, (acc, item) => { + let n = if "cau-hoi-con" in item { item.cau-hoi-con.len() } else { 1 } + acc + n }) set par(first-line-indent: 0pt) v(-0.1em) @@ -642,9 +690,11 @@ let c-idx = 0 for item in s-nlc { - let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item + let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item and item.cau-hoi-con.len() > 1 + let ds-cau-can-ve = if "cau-hoi-con" in item { item.cau-hoi-con } else { (item,) } + if is-item-chum { - let n-sub = item.cau-hoi-con.len() + let n-sub = ds-cau-can-ve.len() let start-num = c-idx + 1 let end-num = c-idx + n-sub v(0.2em) @@ -656,8 +706,6 @@ ] } - let ds-cau-can-ve = if is-item-chum { item.cau-hoi-con } else { (item,) } - for q in ds-cau-can-ve { let opt-indices = if seed == 0 or nlc-mode == "none" { range(4) } else { tron-mang(range(4), seed + c-idx * 73) } let new-opts = opt-indices.map(i => q.pa.at(i)) @@ -706,7 +754,8 @@ if s-tf.len() > 0 { set par(first-line-indent: 0pt) v(0.5em); text(mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #s-tf.len().* #emph[ *Trong mỗi ý a), b), c), d) của mỗi câu, thí sinh chọn đúng hoặc sai.*]] - for (idx, q) in s-tf.enumerate() { + for (idx, q-item) in s-tf.enumerate() { + let q = if "cau-hoi-con" in q-item { q-item.cau-hoi-con.at(0) } else { q-item } let sub-indices = if tf-mode == "none" { range(4) } else if tf-mode == "y-only" { let content-str = repr(q.nd) + repr(q.ytf) @@ -734,18 +783,19 @@ } if s-tln.len() > 0 { - let tong-so-cau = s-tln.fold(0, (acc, q) => { - if "is-chum" in q and q.is-chum == true and "cau-hoi-con" in q { acc + q.cau-hoi-con.len() } else { acc + 1 } + let tong-so-cau = s-tln.fold(0, (acc, item) => { + let n = if "cau-hoi-con" in item { item.cau-hoi-con.len() } else { 1 } + acc + n }) set par(first-line-indent: 0pt) v(0.5em); text(fill: mau-sac.cau-pa)[*► Thí sinh trả lời từ câu 1 đến câu #tong-so-cau.*] let c-idx = 0 for item in s-tln { - let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item - let ds-cau-can-ve = if is-item-chum { item.cau-hoi-con } else { (item,) } + let is-item-chum = "is-chum" in item and item.is-chum == true and "cau-hoi-con" in item and item.cau-hoi-con.len() > 1 + let ds-cau-can-ve = if "cau-hoi-con" in item { item.cau-hoi-con } else { (item,) } if is-item-chum { - let n-sub = item.cau-hoi-con.len() + let n-sub = ds-cau-can-ve.len() let start-num = c-idx + 1 let end-num = c-idx + n-sub v(0.2em) @@ -788,7 +838,8 @@ set par(first-line-indent: 0pt) v(0.3em); text(mau-sac.cau-pa)[*► TỰ LUẬN (#s-tl.len() câu)*] v(-0.3em) - for (idx, q) in s-tl.enumerate() { + for (idx, q-item) in s-tl.enumerate() { + let q = if "cau-hoi-con" in q-item { q-item.cau-hoi-con.at(0) } else { q-item } part4-ans.push((nd: q.nd, lg: q.lg)) v(-0.3em) block(width: 100%, inset: (y: 0.3em), breakable: true)[ @@ -804,7 +855,7 @@ } } - align(center)[#text(size: 11pt)[#strong[---- hết ----]]] + align(center)[#text(size: 11pt)[#strong[---- HẾT ----]]] }) [#metadata(( @@ -827,14 +878,14 @@ for entry in results { let ma-de = str(entry.value.seed) let lg-tl = entry.value.part4 - if lg-TL.len() > 0 { + if lg-tl.len() > 0 { align(left)[ #block(fill: gray.lighten(80%), inset: 5pt, radius: 4pt)[ #text(14pt, weight: "bold")[Mã đề: #ma-de] ] #v(-0.51em) ] - for (idx, ans) in lg-TL.enumerate() { + for (idx, ans) in lg-tl.enumerate() { align(left)[ #text(12pt)[*Câu #(idx + 1). * #ans.nd] #v(-0.5em) @@ -855,16 +906,49 @@ let actual-bank = if type(raw-bank) == dictionary and "data" in raw-bank { raw-bank.data } else if type(raw-bank) == module { raw-bank.data } else { raw-bank } - let loc-ques = actual-bank.filter(q => q.type == q-type) + let std-bank = actual-bank.map(q => { + if "cau-hoi-con" in q and type(q.cau-hoi-con) == array and q.cau-hoi-con.len() > 0 { + let is-c = q.at("is-chum", default: q.cau-hoi-con.len() > 1) + let dk = q.at("du-kien", default: none) + let q-tp = q.at("type", default: q.cau-hoi-con.at(0).at("type", default: "NLC")) + let q-lv = q.at("lv", default: 1) + ( + type: q-tp, + lv: q-lv, + is-chum: is-c, + du-kien: dk, + cau-hoi-con: q.cau-hoi-con + ) + } else { + ( + type: q.at("type", default: "NLC"), + lv: q.at("lv", default: 1), + is-chum: false, + du-kien: none, + cau-hoi-con: (q,) + ) + } + }) + + let loc-ques = std-bank.filter(q => q.type == q-type) if loc-ques.len() == 0 { return () } - let bank-chum = loc-ques.filter(q => "is-chum" in q and q.is-chum == true) - let bank-don = loc-ques.filter(q => not ("is-chum" in q and q.is-chum == true)) + let bank-chum = loc-ques.filter(q => q.is-chum == true) + let bank-don = loc-ques.filter(q => q.is-chum != true) - let safe-slice(arr, req-count) = { + let cat-theo-so-cau-con(arr, req-count) = { if req-count <= 0 or arr.len() == 0 { return () } - let take = calc.min(req-count, arr.len()) - return arr.slice(0, take) + let res = () + let current-cnt = 0 + for item in arr { + let n = item.cau-hoi-con.len() + if current-cnt + n <= req-count or res.len() == 0 { + res.push(item) + current-cnt += n + } + if current-cnt >= req-count { break } + } + return res } let xao-chum = tron-mang(bank-chum, seed) @@ -881,21 +965,25 @@ vd-req = dem-config.at(2, default: 0) } else if type(dem-config) == dictionary { let don-arr = dem-config.at("don", default: (0, 0, 0)) - nb-req = don-arr.at(0, default: 0) - th-req = don-arr.at(1, default: 0) - vd-req = don-arr.at(2, default: 0) + if type(don-arr) == array { + nb-req = don-arr.at(0, default: 0) + th-req = don-arr.at(1, default: 0) + vd-req = don-arr.at(2, default: 0) + } else if type(don-arr) == int { + nb-req = don-arr + } chum-req = dem-config.at("chum", default: 0) } else if type(dem-config) == int { - nb-req = dem-config + return cat-theo-so-cau-con(tron-mang(loc-ques, seed), dem-config) } - let res-chum = safe-slice(xao-chum, chum-req) + let res-chum = cat-theo-so-cau-con(xao-chum, chum-req) - let b-nb = xao-don.filter(q => ("lv" in q and q.lv == 1) or not ("lv" in q)) - let b-th = xao-don.filter(q => "lv" in q and q.lv == 2) - let b-vd = xao-don.filter(q => "lv" in q and q.lv == 3) + let b-nb = xao-don.filter(q => q.lv == 1) + let b-th = xao-don.filter(q => q.lv == 2) + let b-vd = xao-don.filter(q => q.lv == 3) - let res-don = safe-slice(b-nb, nb-req) + safe-slice(b-th, th-req) + safe-slice(b-vd, vd-req) + let res-don = cat-theo-so-cau-con(b-nb, nb-req) + cat-theo-so-cau-con(b-th, th-req) + cat-theo-so-cau-con(b-vd, vd-req) return res-chum + res-don } @@ -1185,7 +1273,7 @@ nlc-loc: q => q.type == "NLC", nlc-dem: final-nlc.len(), tf-loc: q => q.type == "TF", - tf-dem: final-tf.len(), + tf-dem: rut-tf.len(), tln-loc: q => q.type == "TLN", tln-dem: final-tln.len(), tl-loc: q => q.type == "TL",