diff options
Diffstat (limited to 'Master/texmf-dist/tex/latex/xsim/xsim.random.code.tex')
-rw-r--r-- | Master/texmf-dist/tex/latex/xsim/xsim.random.code.tex | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/xsim/xsim.random.code.tex b/Master/texmf-dist/tex/latex/xsim/xsim.random.code.tex new file mode 100644 index 00000000000..3120c800bd8 --- /dev/null +++ b/Master/texmf-dist/tex/latex/xsim/xsim.random.code.tex @@ -0,0 +1,307 @@ +% ---------------------------------------------------------------------------- +% the XSIM package - random module +% +% eXercise Sheets IMproved +% +% ---------------------------------------------------------------------------- +% Clemens Niederberger +% Web: https://github.com/cgnieder/xsim +% E-Mail: contact@mychemistry.eu +% ---------------------------------------------------------------------------- +% Copyright 2017 Clemens Niederberger +% +% 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 Clemens Niederberger. +% ---------------------------------------------------------------------------- +% If you have any ideas, questions, suggestions or bugs to report, please +% feel free to contact me. +% ---------------------------------------------------------------------------- +\XSIMmodule{random}{randomly select exercises from collections} + +\xsim_load_modules:n {collections} + +\tl_new:N \l_xsim_random_collection_tl +\tl_new:N \l_xsim_random_exclude_list_tl +\tl_new:N \l__xsim_print_random_choice_tl +\tl_const:Nn \c__xsim_print_random_both_tl {both} +\tl_const:Nn \c__xsim_print_random_exercise_tl {exercise} +\tl_const:Nn \c__xsim_print_random_solution_tl {solution} +\seq_new:N \g__xsim_random_list_seq +\seq_new:N \l__xsim_allowed_exercise_ids_seq +\int_new:N \g__xsim_random_list_id_int +\bool_new:N \l__xsim_sort_random_bool + +% #1: random list id +% #2: csv list of integers +\xsim_new_aux_cs:cpn {random} #1#2 + { + \xsim_random_list_if_exist:nF {#1} + { \xsim_new_random_list:n {#1} } + \xsim_set_random_list:nn {#1} {#2} + } + +\cs_new_protected:Npn \xsim_new_random_list:n #1 + { + \xsim_verbose:n {Defining~ new~ random~ list~ `#1'} + \seq_new:c {g__xsim_random_#1 _seq} + } + +\cs_new_protected:Npn \xsim_set_random_list:nn #1#2 + { \seq_gset_from_clist:cn {g__xsim_random_#1_seq} {#2} } + +\cs_new_protected:Npn \xsim_set_random_list_from_seq:nN #1#2 + { \seq_gset_eq:cN {g__xsim_random_#1_seq} #2 } + +\cs_new:Npn \xsim_use_random_list:nn #1#2 + { \seq_use:cn {g__xsim_random_#1_seq} {#2} } + +\cs_new_protected:Npn \xsim_map_random_list:nn #1#2 + { \seq_map_inline:cn {g__xsim_random_#1_seq} {#2} } + +\prg_new_conditional:Npnn \xsim_random_list_if_exist:n #1 {p,T,F,TF} + { + \seq_if_exist:cTF {g__xsim_random_#1_seq} + { \prg_return_true: } + { \prg_return_false: } + } + +\prg_new_conditional:Npnn \xsim_random_list_if_empty:n #1 {p,T,F,TF} + { + \seq_if_empty:cTF {g__xsim_random_#1_seq} + { \prg_return_true: } + { \prg_return_false: } + } + +% #1: random list id +% #2: sequence variable to set list from +\cs_new_protected:Npn \xsim_save_random_list:nN #1#2 + { + \xsim_random_list_if_exist:nF {#1} + { \xsim_new_random_list:n {#1} } + \xsim_random_list_if_empty:nT {#1} + { \xsim_set_random_list_from_seq:nN {#1} #2 } + \xsim_verbose:n {Saving~ random~ list~ `#1'} + \xsim_add_cs_to_aux:nn {random} + { {#1} { \xsim_use_random_list:nn {#1} {,} } } + } + +% #1: collection +% #2: number of items +% #3: csv list of excluded ids +\cs_new_protected:Npn \xsim_print_random_list:nnn #1#2#3 + { + \xsim_if_collection_exists:nTF {#1} + { + \int_gincr:N \g__xsim_random_list_id_int + \int_compare:nNnTF { \xsim_collection_count:n {#1} } = {0} + { \xsim_rerun: } + { + % generate seq of allowed ids from collection: + \xsim_foreach_exercise_id:n + { + \tl_set:Nx \l__xsim_tmpa_tl + { \xsim_get_type_for_property:nn {id} {##1} } + \xsim_if_in_collection:nVnT {#1} \l__xsim_tmpa_tl {##1} + { + \clist_if_in:nnF {#3} {##1} + { \seq_put_right:Nn \l__xsim_allowed_exercise_ids_seq {##1} } + } + } + \int_compare:nNnTF + {#2} + > + { \seq_count:N \l__xsim_allowed_exercise_ids_seq } + { + \int_set:Nn \l__xsim_tmpa_int + { \seq_count:N \l__xsim_allowed_exercise_ids_seq } + } + { \int_set:Nn \l__xsim_tmpa_int {#2} } + % generate random list: + \xsim_generate_random_list:nnnN + { \int_to_alph:n { \g__xsim_random_list_id_int } } + { \seq_count:N \l__xsim_allowed_exercise_ids_seq } + { \l__xsim_tmpa_int } + \g__xsim_random_list_seq + } + \xsim_save_random_list:nN + { \int_to_alph:n { \g__xsim_random_list_id_int } } + \g__xsim_random_list_seq + \xsim_verbose:x + { + Printing~ exercises~ of~ random~ list~ + `\int_to_alph:n { \g__xsim_random_list_id_int }'~ of~ + collection~ `#1' + } + \xsim_print_random_exercises:Nn + \l__xsim_allowed_exercise_ids_seq + { \int_to_alph:n { \g__xsim_random_list_id_int } } + } + { \msg_error:nnn {xsim} {unknown-collection} {#1} } + } +\cs_generate_variant:Nn \xsim_print_random_list:nnn {VnV} + +% #1: random list id +% #2: max number to choose from +% #3: number of items +% #4: seq variable +\cs_new_protected:Npn \xsim_generate_random_list:nnnN #1#2#3#4 + { + \bool_if:nT + { + !\xsim_random_list_if_exist_p:n {#1} + || + \xsim_random_list_if_empty_p:n {#1} + } + { + \xsim_verbose:n + {Generating~ random~ list~ `#1'~ with~ #3~ out~ of~ #2~ items} + \seq_gclear:N #4 + \int_do_until:nNnn { \seq_count:N #4 } = {#3} + { + \tl_set:Nx \l__xsim_tmpa_tl + { \fp_eval:n { randint(#2) } } + \seq_if_in:NVF #4 + \l__xsim_tmpa_tl + { \seq_gput_right:NV #4 \l__xsim_tmpa_tl } + } + \bool_if:NT \l__xsim_sort_random_bool + { + \seq_sort:Nn #4 + { + \int_compare:nNnTF {##1} > {##2} + { \sort_return_swapped: } + { \sort_return_same: } + } + } + } + } + +% #1: seq variable of ids +% #2: random list id +\cs_new_protected:Npn \xsim_print_random_exercises:Nn #1#2 + { + \bool_if:nT + { + \xsim_random_list_if_exist_p:n {#2} + && + !\xsim_random_list_if_empty_p:n {#2} + } + { + \xsim_verbose:x + { + Printing~ + \l__xsim_print_random_choice_tl \c_space_tl + \str_if_eq:onT { \l__xsim_print_random_choice_tl } {both} + { exercises~ and~ solutions~ } + of~ random~ list~ `#2' + } + \xsim_map_random_list:nn {#2} + { + \tl_set:Nx \l__xsim_tmpa_tl + { \seq_item:Nn #1 {##1} } + \tl_set:Nx \l__xsim_tmpb_tl + { \xsim_get_type_for_property:nV {id} \l__xsim_tmpa_tl } + \bool_if:nT + { + \tl_if_eq_p:NN + \l__xsim_print_random_choice_tl + \c__xsim_print_random_both_tl + || + \tl_if_eq_p:NN + \l__xsim_print_random_choice_tl + \c__xsim_print_random_exercise_tl + } + { + \xsim_if_exercise_exists:VVT + \l__xsim_tmpb_tl + \l__xsim_tmpa_tl + { + \xsim_insert:VVnn + \l__xsim_tmpb_tl + \l__xsim_tmpa_tl + {} + {exercise} + } + } + \bool_if:nT + { + \tl_if_eq_p:NN + \l__xsim_print_random_choice_tl + \c__xsim_print_random_both_tl + || + \tl_if_eq_p:NN + \l__xsim_print_random_choice_tl + \c__xsim_print_random_solution_tl + } + { + \xsim_if_solution_exists:VVT + \l__xsim_tmpb_tl + \l__xsim_tmpa_tl + { + \xsim_insert:VVnn + \l__xsim_tmpb_tl + \l__xsim_tmpa_tl + {} + {solution} + } + } + } + } + } + +\keys_define:nn {xsim/random} + { + sort .bool_set:N = \l__xsim_sort_random_bool , + sort .initial:n = true , + collection .tl_set:N = \l_xsim_random_collection_tl , + collection .initial:n = all~exercises , + exclude .code:n = \__xsim_exclude_ids:n {#1} , + print .choice: , + print/exercises .code:n = + \tl_set:Nn \l__xsim_print_random_choice_tl {exercise} , + print/solutions .code:n = + \tl_set:Nn \l__xsim_print_random_choice_tl {solution} , + print/both .code:n = + \tl_set:Nn \l__xsim_print_random_choice_tl {both} , + print/unknown .code:n = + \msg_warning:nnn {xsim} {print-collection-choice} {#1} + \tl_set:Nn \l__xsim_print_random_choice_tl {exercise} , + print .initial:n = exercises + } + +\cs_new_protected:Npn \__xsim_exclude_ids:n #1 + { + \seq_clear:N \l__xsim_tmpa_seq + \clist_map_inline:nn {#1} + { + \tl_set:Nx \l__xsim_tmpa_tl + { \xsim_get_id_for_property:nn {ID} {##1} } + \tl_if_blank:NTF \l__xsim_tmpa_tl + { \seq_put_right:Nn \l__xsim_tmpa_seq {##1} } + { + \seq_put_right:Nx \l__xsim_tmpa_seq + { \xsim_get_id_for_property:nn {ID} {##1} } + } + } + \seq_remove_duplicates:N \l__xsim_tmpa_seq + \tl_set:Nx \l_xsim_random_exclude_list_tl + { \seq_use:Nn \l__xsim_tmpa_seq {,} } + } + +% use this in the exclude list: +% \xsim_get_type_for_property:nn {id} {} +% or a combination of: +% \xsim_get_type_for_property:nn {ID} {} +% \xsim_get_id_for_property:nn {ID} {} + +% ---------------------------------------------------------------------------- +\tex_endinput:D |