%% %% This is file `randques.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% randques.dtx (with options: `package') %% %% Copyright (C) 2013 by Qing Lee %% -------------------------------------------------------------------------- %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of LaTeX %% version 2005/12/01 or later. %% %% This work has the LPPL maintenance status "maintained". %% The Current Maintainer of this work is Qing Lee. %% \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3} \GetIdInfo$Id: randques.dtx 182 2013-12-02 03:27:58Z sobenlee@gmail.com $ {Random question selection.} \ProvidesExplPackage{\ExplFileName} {\ExplFileDate}{0.1}{\ExplFileDescription} \RequirePackage { xparse } \RequirePackage { l3keys2e } %\RequirePackage { l3str } \RequirePackage { tikz } \ior_new:N \g__randques_ior \iow_new:N \g__randques_iow \int_new:N \l__randques_tmp_int \int_new:N \l__randques_question_int \int_new:N \l__randques_count_int \int_new:N \l__randques_state_int \int_new:N \g__randques_output_int \tl_new:N \g__randques_output_tl \tl_new:N \l__randques_output_tl \tl_new:N \l__randques_newline_tl \tl_new:N \l__randques_rand_num_tl \tl_new:N \l__randques_question_num_tl \prop_new:N \l__randques_question_prop \bool_new:N \l__randques_skip_bool \bool_new:N \l__randques_subquestion_block_bool \bool_new:N \l__randques_option_block_bool \bool_new:N \l__randques_all_bool \bool_new:N \l__randques_sort_bool \bool_new:N \l__randques_auto_name_bool \str_new:N \l__randques_before_question_block_str \str_new:N \l__randques_before_subquestion_block_str \str_new:N \l__randques_before_option_block_str \str_new:N \l__randques_before_question_str \str_new:N \l__randques_before_subquestion_str \str_new:N \l__randques_before_option_str \str_new:N \l__randques_after_question_str \str_new:N \l__randques_after_subquestion_str \str_new:N \l__randques_after_option_str \str_new:N \l__randques_after_question_block_str \str_new:N \l__randques_after_subquestion_block_str \str_new:N \l__randques_after_option_block_str \cs_new_protected_nopar:Npn \__randques_rand_num:Nnn { \pgfmathrandominteger } \cs_new_protected_nopar:Npn \__randques_rand:nnnNN #1#2#3#4#5 { \int_compare:nNnTF {#3} > {#2} { \msg_warning:nnxxx { randques } { not-enough-questions } {#1} { \int_eval:n {#2} } { \int_eval:n {#3} } \keys_set:nn { randques } { all = true } } { \int_zero:N \l__randques_tmp_int \seq_clear_new:N #4 \prop_clear_new:N #5 \int_do_while:nNnn \l__randques_tmp_int < {#3} { \__randques_rand_num:Nnn \l__randques_rand_num_tl { 1 } {#2} \__randques_rand_aux:oNN { \l__randques_rand_num_tl } #4#5 } } } \msg_new:nnn { randques } { not-enough-questions } { There~are~only~#2~questions~in~file~`#1'.\\ But~you~ask~#3~questions,~so~all~of~them~are~selected. } \cs_new_protected_nopar:Npn \__randques_rand_aux:nNN #1#2#3 { \seq_if_in:NnF #2 {#1} { \seq_put_right:Nn #2 {#1} \prop_put:Nnn #3 {#1} { } \int_incr:N \l__randques_tmp_int } } \cs_generate_variant:Nn \__randques_rand_aux:nNN { o } \cs_new_protected_nopar:Npn \__randques_update_tester:nNNN #1#2#3#4 { \__randques_def:Npn #2 ##1 #1 ##2 \q_stop { \if:w \scan_stop: ##1##2 \scan_stop: ? \else: \use_none:n ##1 ? \fi: } \__randques_def_conditional:Npnn #3 ##1 { T , F , TF } { \if:w \scan_stop: #2 ##1 #1 \q_stop \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } \__randques_def:Npn #4 #1 ##1 \q_stop {##1} } \cs_generate_variant:Nn \__randques_update_tester:nNNN { x } \cs_new_eq:NN \__randques_def:Npn \cs_new:Npn \cs_new_eq:NN \__randques_def_conditional:Npnn \prg_new_conditional:Npnn \cs_new_protected_nopar:Npn \__randques_count:N #1 { \int_zero:N #1 \ior_str_map_inline:Nn \g__randques_ior { \tl_if_blank:nF {##1} { \__randques_tag_is_question:nT {##1} { \int_incr:N #1 } } } \ior_close:N \g__randques_ior } \cs_new_protected_nopar:Npn \__randques_select:n #1 { \int_gincr:N \g__randques_output_int \bool_if:NTF \l__randques_auto_name_bool { \tl_gset:Nx \g__randques_output_tl { \c_sys_jobname_str - questions - \int_use:N \g__randques_output_int } } { \tl_gset_eq:NN \g__randques_output_tl \l__randques_output_tl } \bool_if:NTF \l__randques_freeze_bool { \file_if_exist:nTF { \g__randques_output_tl } { \use_none:n } { \use:n } } { \use:n } { \__randques_count:N \l__randques_count_int \int_compare:nNnTF \l__randques_count_int = \c_zero { \msg_warning:nnx { randques } { no-questions } {#1} } { \bool_if:NF \l__randques_all_bool { \bool_if:NT \l__randques_sort_bool { \int_set_eq:NN \l__randques_selection_int \l__randques_count_int } \__randques_rand:nnnNN {#1} { \l__randques_count_int } { \l__randques_selection_int } \l__randques_rand_seq \l__randques_question_prop \bool_set_false:N \l__randques_skip_bool \tl_clear:N \l__randques_question_num_tl } \__randques_select_aux:n {#1} } } } \msg_new:nnn { randques } { no-questions } { There~is~no~question~be~found~in~file~#1. } \cs_new_protected_nopar:Npn \__randques_select_aux:n #1 { \tl_clear:N \l__randques_question_block_str \int_zero:N \l__randques_question_int \iow_open:Nn \g__randques_iow { \g__randques_output_tl } \tl_if_empty:NF \l__randques_before_question_block_str { \iow_now:Nx \g__randques_iow { \l__randques_before_question_block_str \iow_newline: } } \ior_open:Nn \g__randques_ior {#1} \ior_str_map_inline:Nn \g__randques_ior { \tl_if_blank:nTF {##1} { \tl_set_eq:NN \l__randques_newline_tl \iow_newline: } { \__randques_select_question:n {##1} } } \__randques_output: } \cs_new_protected_nopar:Npn \__randques_select_all:n #1 { \__randques_tag_is_question:nTF {#1} { \__randques_output_question_block: \int_set_eq:NN \l__randques_state_int \c_zero \tl_set:Nx \l__randques_question_block_str { \l__randques_before_question_str \__randques_remove_question_tag:w #1 \q_stop \iow_newline: } \tl_clear:N \l__randques_newline_tl } { \__randques_select_subquestion:n {#1} } } \cs_new_protected_nopar:Npn \__randques_select_rand:n #1 { \__randques_tag_is_question:nTF {#1} { \int_incr:N \l__randques_question_int \seq_if_in:NVTF \l__randques_rand_seq \l__randques_question_int { \__randques_save_question_block: \tl_set:Nx \l__randques_question_num_tl { \int_use:N \l__randques_question_int } \bool_set_false:N \l__randques_skip_bool \int_set_eq:NN \l__randques_state_int \c_zero \tl_set:Nx \l__randques_question_block_str { \l__randques_before_question_str \__randques_remove_question_tag:w #1 \q_stop \iow_newline: } \tl_clear:N \l__randques_newline_tl } { \bool_set_true:N \l__randques_skip_bool } } { \bool_if:NF \l__randques_skip_bool { \__randques_select_subquestion:n {#1} } } } \cs_new_protected_nopar:Npn \__randques_select_sort:n #1 { \__randques_tag_is_question:nTF {#1} { \int_incr:N \l__randques_question_int \__randques_save_question_block: \tl_set:Nx \l__randques_question_num_tl { \int_use:N \l__randques_question_int } \int_set_eq:NN \l__randques_state_int \c_zero \tl_set:Nx \l__randques_question_block_str { \l__randques_before_question_str \__randques_remove_question_tag:w #1 \q_stop \iow_newline: } \tl_clear:N \l__randques_newline_tl } { \__randques_select_subquestion:n {#1} } } \cs_new_protected_nopar:Npn \__randques_select_subquestion:n #1 { \__randques_tag_is_option:nTF {#1} { \tl_put_right:Nx \l__randques_question_block_str { \__randques_item_tail_str: \l__randques_newline_tl \bool_if:NF \l__randques_option_block_bool { \l__randques_before_option_block_str \iow_newline: } \l__randques_before_option_str \__randques_remove_option_tag:w #1 \q_stop \iow_newline: } \int_set_eq:NN \l__randques_state_int \c_two \bool_set_true:N \l__randques_option_block_bool } { \__randques_tag_is_subquestion:nTF {#1} { \tl_put_right:Nx \l__randques_question_block_str { \__randques_item_tail_str: \bool_if:NT \l__randques_option_block_bool { \l__randques_after_option_block_str \iow_newline: } \l__randques_newline_tl \bool_if:NF \l__randques_subquestion_block_bool { \l__randques_before_subquestion_block_str \iow_newline: } \l__randques_before_subquestion_str \__randques_remove_subquestion_tag:w #1 \q_stop \iow_newline: } \bool_set_true:N \l__randques_subquestion_block_bool \bool_set_false:N \l__randques_option_block_bool \int_set_eq:NN \l__randques_state_int 1 } { \tl_put_right:Nx \l__randques_question_block_str { \l__randques_newline_tl #1 \iow_newline: } } } \tl_clear:N \l__randques_newline_tl } \cs_new_protected_nopar:Npn \__randques_output_question_block: { \tl_if_empty:NF \l__randques_question_block_str { \iow_now:Nx \g__randques_iow { \l__randques_question_block_str \__randques_item_tail_str: \bool_if:NT \l__randques_option_block_bool { \l__randques_after_option_block_str \iow_newline: } \bool_if:NT \l__randques_subquestion_block_bool { \l__randques_after_subquestion_block_str \iow_newline: } } \bool_set_false:N \l__randques_option_block_bool \bool_set_false:N \l__randques_subquestion_block_bool } } \cs_new_protected_nopar:Npn \__randques_save_question_block: { \tl_if_empty:NF \l__randques_question_num_tl { \prop_put:NVx \l__randques_question_prop \l__randques_question_num_tl { \l__randques_question_block_str \__randques_item_tail_str: \bool_if:NT \l__randques_option_block_bool { \l__randques_after_option_block_str \iow_newline: } \bool_if:NT \l__randques_subquestion_block_bool { \l__randques_after_subquestion_block_str \iow_newline: } } \bool_set_false:N \l__randques_option_block_bool \bool_set_false:N \l__randques_subquestion_block_bool } } \cs_generate_variant:Nn \prop_put:Nnn { NVx } \cs_new_nopar:Npn \__randques_item_tail_str: { \if_case:w \l__randques_state_int \tl_if_empty:NF \l__randques_after_question_str { \l__randques_after_question_str \iow_newline: } \or: \tl_if_empty:NF \l__randques_after_subquestion_str { \l__randques_after_subquestion_str \iow_newline: } \or: \tl_if_empty:NF \l__randques_after_option_str { \l__randques_after_option_str \iow_newline: } \fi: } \cs_new_protected_nopar:Npn \__randques_output_all: { \tl_if_empty:NF \l__randques_question_block_str { \iow_now:Nx \g__randques_iow { \l__randques_question_block_str \__randques_item_tail_str: \bool_if:NT \l__randques_option_block_bool { \l__randques_after_option_block_str \iow_newline: } \bool_if:NT \l__randques_subquestion_block_bool { \l__randques_after_subquestion_block_str \iow_newline: } \l__randques_after_question_block_str } } \iow_close:N \g__randques_iow } \cs_new_protected_nopar:Npn \__randques_output_rand: { \__randques_save_question_block: \tl_if_empty:NF \l__randques_question_num_tl { \prop_map_inline:Nn \l__randques_question_prop { \iow_now:Nn \g__randques_iow {##2} } \tl_if_empty:NF \l__randques_after_question_block_str { \iow_now:Nx \g__randques_iow { \l__randques_after_question_block_str } } } \iow_close:N \g__randques_iow } \cs_new_protected_nopar:Npn \__randques_input: { \file_input:n { \g__randques_output_tl } } \bool_set_true:N \l__randques_auto_name_bool \keys_define:nn { randques } { all .choice: , all / true .code:n = { \bool_set_true:N \l__randques_all_bool \cs_set_eq:NN \__randques_select_question:n \__randques_select_all:n \cs_set_eq:NN \__randques_output: \__randques_output_all: } , all / false .code:n = { \bool_set_false:N \l__randques_all_bool \bool_set_false:N \l__randques_sort_bool \cs_set_eq:NN \__randques_select_question:n \__randques_select_rand:n \cs_set_eq:NN \__randques_output: \__randques_output_rand: } , all / randsort .code:n = { \bool_set_false:N \l__randques_all_bool \bool_set_true:N \l__randques_sort_bool \cs_set_eq:NN \__randques_select_question:n \__randques_select_sort:n \cs_set_eq:NN \__randques_output: \__randques_output_rand: } , all .initial:n = { false } , all .default:n = { true } , freeze .bool_set:N = \l__randques_freeze_bool , random .int_set:N = \l__randques_selection_int , random .initial:n = { 1 } , random .default:n = { 1 } , output .code:n = { \bool_false:N \l__randques_auto_name_tl \tl_set:Nx \l__randques_output_tl {#1} } , output .value_required:n=true , question-tag .code:n = { \__randques_update_tester:xNNN { \tl_to_str:n {#1} } \__randques_tag_is_question:w \__randques_tag_is_question:n \__randques_remove_question_tag:w } , subquestion-tag .code:n = { \__randques_update_tester:xNNN { \tl_to_str:n {#1} } \__randques_tag_is_subquestion:w \__randques_tag_is_subquestion:n \__randques_remove_subquestion_tag:w } , option-tag .code:n = { \__randques_update_tester:xNNN { \tl_to_str:n {#1} } \__randques_tag_is_option:w \__randques_tag_is_option:n \__randques_remove_option_tag:w } , question-tag .initial:n = { \question } , question-tag .default:n = { \question } , subquestion-tag .initial:n = { \subquestion } , subquestion-tag .default:n = { \subquestion } , option-tag .initial:n = { \option } , option-tag .default:n = { \option } , before-question-block .code:n = { \str_set:Nn \l__randques_before_question_block_str {#1} } , before-subquestion-block .code:n = { \str_set:Nn \l__randques_before_subquestion_block_str {#1} } , before-option-block .code:n = { \str_set:Nn \l__randques_before_option_block_str {#1} } , before-question .code:n = { \str_set:Nn \l__randques_before_question_str {#1} } , before-subquestion .code:n = { \str_set:Nn \l__randques_before_subquestion_str {#1} } , before-option .code:n = { \str_set:Nn \l__randques_before_option_str {#1} } , after-question .code:n = { \str_set:Nn \l__randques_after_question_str {#1} } , after-subquestion .code:n = { \str_set:Nn \l__randques_after_subquestion_str {#1} } , after-option .code:n = { \str_set:Nn \l__randques_after_option_str {#1} } , after-question-block .code:n = { \str_set:Nn \l__randques_after_question_block_str {#1} } , after-subquestion-block .code:n = { \str_set:Nn \l__randques_after_subquestion_block_str {#1} } , after-option-block .code:n = { \str_set:Nn \l__randques_after_option_block_str {#1} } , before-question-block .initial:n = { \begin { enumerate } } , before-subquestion-block .initial:n = { \begin { enumerate } } , before-option-block .initial:n = { \begin { enumerate } } , before-question .initial:n = { \item } , before-subquestion .initial:n = { \item } , before-option .initial:n = { \item } , after-question-block .initial:n = { \end { enumerate } } , after-subquestion-block .initial:n = { \end { enumerate } } , after-option-block .initial:n = { \end { enumerate } } } \cs_set_eq:NN \__randques_def:Npn \cs_set:Npn \cs_set_eq:NN \__randques_def_conditional:Npnn \prg_set_conditional:Npnn \NewDocumentCommand \RandSelQuestions { o m } { \ior_open:NnTF \g__randques_ior {#2} { \group_begin: \IfNoValueF {#1} { \keys_set:nn { randques } {#1} } \__randques_select:n {#2} \ior_close:N \g__randques_ior \group_end: \__randques_input: } { \msg_error:nnn { randques } { database-not-found } {#2} } } \msg_new:nnn { randques } { database-not-found } { Question~database~`#1'~not~found.\\ randques~will~not~work! } \NewDocumentCommand \RandSelQueSetup { m } { \keys_set:nn { randques } {#1} } \ProcessKeysOptions { randques } %% %% This package consists of the file randques.dtx, %% and the derived files randques.pdf, %% randques.sty, and %% randques.ins. %% %% End of file `randques.sty'.