% ---------------------------------------------------------------------------- % the XSIM package - solutions module % % eXercise Sheets IMproved % % ---------------------------------------------------------------------------- % Clemens Niederberger % Web: https://github.com/cgnieder/xsim % E-Mail: contact@mychemistry.eu % ---------------------------------------------------------------------------- % Copyright 2017--2020 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{solutions}{managing solutions} \xsim_load_modules:n {tags,properties} \bool_new:N \l_xsim_inside_solution_bool \bool_new:N \l__xsim_include_question_bool \bool_new:N \l__xsim_printsolutions_headings_bool \bool_new:N \l__xsim_printsolutions_conditions_bool \bool_new:N \l____xsim_this_condition_bool \seq_new:N \l__xsim_printsolutions_conditions_seq \int_new:N \l_xsim_printsolutions_section_int \int_new:N \l_xsim_printsolutions_chapter_int \tl_new:N \l__xsim_printsolutions_headings_template_tl \tl_new:N \ExerciseSection \tl_new:N \ExerciseChapter \tl_new:N \l__xsim_printsolutions_collection_tl % ---------------------------------------------------------------------------- \prg_new_conditional:Npnn \xsim_if_inside_solution: {p,T,F,TF} { \bool_if:NTF \l_xsim_inside_solution_bool { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \xsim_if_solution_print:n #1 {p,T,F,TF} { \bool_if:cTF {l__xsim_#1_solution_print_bool} { \prg_return_true: } { \prg_return_false: } } % #1: type % #2: id \prg_new_protected_conditional:Npnn \xsim_solution_if_print:nn #1#2 {T,F,TF} { \bool_set_true:N \l____xsim_print_bool \xsim_if_tagged:nnF {#1} {#2} { \bool_set_false:N \l____xsim_print_bool } \xsim_if_boolean_property:nnnF {#1} {#2} {print} { \bool_set_false:N \l____xsim_print_bool } \bool_if:cF {l__xsim_#1_solution_print_bool} { \bool_set_false:N \l____xsim_print_bool } \bool_if:NTF \l____xsim_print_bool { \prg_return_true: } { \prg_return_false: } } \cs_generate_variant:Nn \xsim_solution_if_print:nnT {nV,oo} % #1: type % #2: id \prg_new_protected_conditional:Npnn \xsim_if_solution_exist:nn #1#2 {T,F,TF} { \xsim_if_boolean_property:nnnTF {#1} {#2} {solution} { \xsim_if_exist:nnnTF {#1} {#2} {exercise} } { \xsim_if_exist:nnnTF {#1} {#2} {solution} } { \prg_return_true: } { \prg_return_false: } } \cs_generate_variant:Nn \xsim_if_solution_exist:nnT {VV,oo} \cs_generate_variant:Nn \xsim_if_solution_exist:nnTF {oo} % #1: type % #2: options \cs_new_protected:Npn \xsim_start_solution:nn #1#2 { \keys_set:xn { xsim/\xsim_get_parameter:nn {#1} {solution-env} } {#2} \bool_set_true:N \l_xsim_inside_solution_bool \refstepcounter { \xsim_get_parameter:nn {#1} {solution-counter} } } \cs_new_protected:Npn \xsim_stop_solution:n #1 {} % ---------------------------------------------------------------------------- % #1: conditional base function (three n args) % #2: name % #3: code (refer to type and id with `#1' and `#2'), #3 refers to the boolean % properties use/print \cs_new_protected:Npn \xsim_new_solutions_condition:Nnn #1#2#3 { \prg_new_protected_conditional:Npnn #1 ##1##2##3 {T,F,TF} { \xsim_if_in_list:nnTF {##3} {##1-##2=={true}} { \__xsim_printsolutions_if_condition:nTF {#2} { \__xsim_printsolutions_condition_true: #3 } { \prg_return_false: } } { \prg_return_false: } } } % per section condition: \xsim_new_solutions_condition:Nnn \__xsim_if_solutions_per_section:nnn {per-section} { \xsim_if_in_list:nxTF {section-value} { #1-#2 == { \int_use:N \l_xsim_printsolutions_section_int } } { \tl_set:Nx \ExerciseSection { \xsim_get_property:nnn {#1} {#2} {section} } \prg_return_true: } { \prg_return_false: } } % per chapter condition: \xsim_new_solutions_condition:Nnn \__xsim_if_solutions_per_chapter:nnn {per-chapter} { \xsim_if_in_list:nxTF {chapter-value} { #1-#2 == { \int_use:N \l_xsim_printsolutions_chapter_int } } { \tl_set:Nx \ExerciseChapter { \xsim_get_property:nnn {#1} {#2} {chapter} } \prg_return_true: } { \prg_return_false: } } % per collection condition: \xsim_new_solutions_condition:Nnn \__xsim_if_solutions_in_collection:nnn {per-collection} { \tl_if_blank:VTF \l__xsim_printsolutions_collection_tl { \prg_return_false: } { \xsim_if_in_collection:VnnTF \l__xsim_printsolutions_collection_tl {#1} {#2} { \prg_return_true: } { \prg_return_false: } } } % ---------------------------------------------------------------------------- % conditions mechanism \cs_new_protected:Npn \__xsim_printsolutions_condition_false: { \bool_set_false:N \l__xsim_printsolutions_conditions_bool } \cs_new_protected:Npn \__xsim_printsolutions_condition_true: { \bool_set_true:N \l__xsim_printsolutions_conditions_bool } % #1: type % #2: id % #3: boolean property \prg_new_conditional:Npnn \__xsim_printsolutions_if_conditions:nnn #1#2#3 {T,F,TF} { \bool_if:NTF \l__xsim_printsolutions_conditions_bool { \prg_return_true: } { \xsim_if_in_list:nnTF {#3} {#1-#2=={true}} { \prg_return_false: } { \prg_return_true: } } } % #1: name % #2: condition \cs_new_protected:Npn \xsim_declare_printsolutions_condition:nn #1#2 { \bool_new:c {l__xsim_printsolutions_#1_condition_bool} \seq_put_right:Nn \l__xsim_printsolutions_conditions_seq {#1} \xsim_attribute_set:nnn {printsolutions} {#1} {#2} } \prg_new_conditional:Npnn \__xsim_printsolutions_if_condition:n #1 {T,F,TF} { \bool_if:cTF {l__xsim_printsolutions_#1_condition_bool} { \prg_return_true: } { \prg_return_false: } } % #1: name % #2: true|false \cs_new_protected:Npn \__xsim_printsolutions_condition:nn #1#2 { \bool_set_eq:cc {l__xsim_printsolutions_#1_condition_bool} {c_#2_bool} } % false if any condition is false for this solution: % #1: type % #2: id % #3: boolean property \prg_new_protected_conditional:Npnn \__xsim_printsolutions_check_conditions:nnn #1#2#3 {T,F,TF} { \__xsim_printsolutions_condition_false: \bool_set_true:N \l____xsim_this_condition_bool \seq_map_inline:Nn \l__xsim_printsolutions_conditions_seq { \bool_if:cT {l__xsim_printsolutions_##1_condition_bool} { \xsim_attribute_get:nn {printsolutions} {##1} {#1} {#2} {#3} { } { \bool_set_false:N \l____xsim_this_condition_bool } } } \bool_if:NTF \l____xsim_this_condition_bool { \prg_return_true: } { \prg_return_false: } } % #1: type % #2: id % #3: boolean property % #4: code \cs_new_protected:Npn \xsim_if_this_solution_do:nnnn #1#2#3#4 { \xsim_if_solution_exist:nnT {#1} {#2} { \__xsim_printsolutions_check_conditions:nnnT {#1} {#2} {#3} {#4} } } % #1: type % #2: boolean property % #3: code \cs_new_protected:Npn \xsim_if_solutions_do:nnn #1#2#3 { \xsim_foreach_exercise_type_id:nn {#2} { \xsim_if_this_solution_do:nnnn {#1} {##2} {#2} {#3} } } % ---------------------------------------------------------------------------- % #1: boolean -- if true only the solutions of printed exercises will be % output % #2: pre % #3: post % #4: type % #5: code (refer to type with #1 and id with #2) \cs_new_protected:Npn \xsim_print_type_code:nnnnn #1#2#3#4#5 { \group_begin: \cs_set_protected:Npn \__xsim_print_entry:nn ##1##2 {#5} #2 \bool_set_false:N \l__xsim_tmpa_bool \bool_if:nTF {#1} { \xsim_if_solutions_do:nnn {#4} {print} { \bool_set_true:N \l__xsim_tmpa_bool } } { \xsim_if_solutions_do:nnn {#4} {used} { \bool_set_true:N \l__xsim_tmpa_bool } } \tl_set:Nn \ExerciseType {#4} \bool_if:NT \l__xsim_tmpa_bool { \bool_if:NT \l__xsim_printsolutions_headings_bool { \xsim_use_template:nV {heading} \l__xsim_printsolutions_headings_template_tl } } \bool_if:nTF {#1} { \xsim_if_solutions_do:nnn {#4} {print} { \__xsim_print_entry:nn {#4} {##2} } } { \xsim_if_solutions_do:nnn {#4} {used} { \__xsim_print_entry:nn {#4} {##2} } } #3 \group_end: } % #1: boolean -- if true only the solutions of printed exercises will be % output % #2: options % #3: type \cs_new_protected:Npn \xsim_print_type_solutions:nnn #1#2#3 { \xsim_print_type_code:nnnnn {#1} { \xsim_verbose:n { Printing~ solutions~ for~ exercise~ type~ `#3'. } \keys_set:nn {xsim/print-solutions} {#2} } {} {#3} { \xsim_insert:nnnn {##1} {##2} {} {solution} } } % #1: boolean -- if true only the solutions of printed exercises will be % output % #2: options \cs_new_protected:Npn \xsim_print_all_solutions_per_type:nn #1#2 { \xsim_foreach_exercise_type:n { \xsim_print_type_solutions:nnn {#1} {#2} {##1} } } % #1: boolean -- if true only the solutions of printed exercises will be % output % #2: options \cs_new_protected:Npn \xsim_print_all_solutions_per_id:nn #1#2 { \xsim_verbose:n { Printing~ solutions. } \group_begin: \keys_set:nn {xsim/print-solutions} {#2} \bool_set_false:N \l__xsim_tmpa_bool \bool_if:nTF {#1} { \xsim_foreach_exercise_id_type:nn {print} { \xsim_if_this_solution_do:nnnn {##1} {##2} {print} { \xsim_insert:nnnn {##1} {##2} {} {solution} } } } { \xsim_foreach_exercise_id_type:nn {used} { \xsim_if_this_solution_do:nnnn {##1} {##2} {used} { \xsim_insert:nnnn {##1} {##2} {} {solution} } } } \group_end: } % ---------------------------------------------------------------------------- \xsim_declare_printsolutions_condition:nn {per-section} { \__xsim_if_solutions_per_section:nnnTF } \xsim_declare_printsolutions_condition:nn {per-chapter} { \__xsim_if_solutions_per_chapter:nnnTF } \xsim_declare_printsolutions_condition:nn {per-collection} { \__xsim_if_solutions_in_collection:nnnTF } % ---------------------------------------------------------------------------- \keys_define:nn {xsim/print-solutions} { headings .bool_set:N = \l__xsim_printsolutions_headings_bool , headings .initial:n = true , headings-template .tl_set:N = \l__xsim_printsolutions_headings_template_tl , headings-template .initial:n = default , include-exercise .bool_set:N = \l__xsim_include_question_bool , include-exercise .initial:n = false , section .choice: , section/true .code:n = \__xsim_printsolutions_condition:nn {per-section} {true} \int_set:Nn \l_xsim_printsolutions_section_int { \value {section} } , section/false .code:n = \__xsim_printsolutions_condition:nn {per-section} {false} , section/unknown .code:n = \__xsim_printsolutions_condition:nn {per-section} {true} \int_set:Nn \l_xsim_printsolutions_section_int {#1} , section .default:n = true , section .initial:n = false , chapter .choice: , chapter/true .code:n = \__xsim_printsolutions_condition:nn {per-chapter} {true} \int_set:Nn \l_xsim_printsolutions_chapter_int { \value {chapter} } , chapter/false .code:n = \__xsim_printsolutions_condition:nn {per-chapter} {false} , chapter/unknown .code:n = \__xsim_printsolutions_condition:nn {per-chapter} {true} \int_set:Nn \l_xsim_printsolutions_chapter_int {#1} , chapter .default:n = true , chapter .initial:n = false , collection .choice: , collection/false .code:n = \__xsim_printsolutions_condition:nn {per-collection} {false} , collection/unknown .code:n = \xsim_if_collection_exist:nT {#1} { \__xsim_printsolutions_condition:nn {per-collection} {true} \tl_set:Nn \l__xsim_printsolutions_collection_tl {#1} } , collection .initial:n = false } % ---------------------------------------------------------------------------- \file_input_stop: 2020/02/23 - resolve bug #56 2020/03/16 - performance optimizations