]> Devoid-pointer.net GitWeb - Nine-Q.git/commitdiff
- Unify resources tracking
authorMichal Malý <madcatxster@devoid-pointer.net>
Sun, 28 Dec 2014 16:42:19 +0000 (17:42 +0100)
committerMichal Malý <madcatxster@devoid-pointer.net>
Sun, 28 Dec 2014 16:42:19 +0000 (17:42 +0100)
- Preliminary walkthrough implementation in acidobazic suite (no face generator for it yet)

bin/templates/face_acidobazic.html
src/formatting_helpers.adb
src/formatting_helpers.ads
src/handlers/handlers.adb
src/problem_generators/problem_generator-acidobazic_suite.adb
src/problem_generators/problem_generator-titration_curve_suite.adb
src/problem_generators/problem_generator.adb
src/problem_generators/problem_generator.ads
src/problem_manager.adb
src/problem_manager.ads

index 1016d8eefc48fb091936c5c712809ede2ad8ded9..ce5629db5a82bba33ca791348c7c1ecb09ce6102 100644 (file)
          <input type="submit" name="send_answer" value="Zkontrolovat" />
        </div>
       </form>
+      <form class="problem_form" method="post" action="/show_walkthrough">
+       <input type="hidden" name="@_RESERVED__PROBLEM_ID_@" value="@_RESERVED__PROBLEM_ID_VAL_@">
+       <div class="form_line">
+         <input type="submit" name="show_walkthrough" value="Zobrazit řešení" />
+       </div>
+      </form>
     </div>
  
     @_ANSWER_SECTION_@
index 1c884c7d37a4fcd6d9713faf6274aa3876e952dc..7c404edf8cd3d50b77c3f17d49964b0e0ef2a3e4 100644 (file)
@@ -26,7 +26,7 @@ package body Formatting_Helpers is
     package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
     use FHEF;
 
-    ExpDecimals: FH_Float := 10.0 ** Decimals;
+    ExpDecimals: constant FH_Float := 10.0 ** Decimals;
     Log_Arg_Floor: FH_Float;
     Temp: FH_Float;
   begin
@@ -41,9 +41,10 @@ package body Formatting_Helpers is
     Decimal_Part_F: FH_Float;
     Decimal_Part_I: Integer;
     ExpDecimals: constant FH_Float := 10.0 ** Decimals;
+    MNum: FH_Float := Num;
   begin
-    Integer_Part_F := FH_Float'Floor(Num);
-    Decimal_Part_F := (Num - Integer_Part_F) * ExpDecimals;
+    Integer_Part_F := FH_Float'Floor(MNum);
+    Decimal_Part_F := (MNum - Integer_Part_F) * ExpDecimals;
     Decimal_Part_I := Integer(Decimal_Part_F);
 
     Integer_Part := To_UB_Text(Ada.Strings.Fixed.Trim(Source => Integer'Image(Integer(Integer_Part_F)), Side => Ada.Strings.Left));
@@ -55,7 +56,6 @@ package body Formatting_Helpers is
     package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
     use FHEF;
 
-    EPSILON: constant FH_Float := 10.0 ** (-(Decimals + 1));
     ExpDecimals: constant FH_Float := 10.0 ** Decimals;
     PNum: FH_Float;
     Expanded: FH_Float;
@@ -78,23 +78,9 @@ package body Formatting_Helpers is
       Negative := False;
     end if;
 
-    Log_Arg_Floored := FH_Float'Floor(Log(Base => 10.0, X => PNum));
+    Log_Arg_Floored := FH_Float'Floor(Log(Base => 10.0, X => Num));
     Expanded := 10.0 ** Log_Arg_Floored;
-    --PNum := Round_To_Valid_Nums(PNum, Decimals);
-
-      --Ada.Text_IO.Put_Line("EP: " & FH_Float'Image((PNum / Expanded) + EPSILON) & " N: " & FH_Float'Image(PNum / Expanded));
-    declare
-      FPE: constant FH_Float := FH_Float'Floor((PNum / Expanded) + EPSILON);
-      F: constant FH_Float := FH_Float'Floor(PNum / Expanded);
-    begin
-      --Ada.Text_IO.Put_Line("FPE: " & FH_Float'Image(FPE) & " F: " & FH_Float'Image(F));
-      if FPE > F then
-       PNum := PNum + (EPSILON * Expanded);
-       Integer_Part_F := FPE;
-      else
-       Integer_Part_F := F;
-      end if;
-    end;
+    Integer_Part_F := Get_Integer_Part(PNum, Decimals);
     --Integer_Part_F := FH_Float'Floor(PNum / Expanded);
     --Ada.Text_IO.Put_Line("((PNum / Expanded) - Integer_Part_F) * Expanded = " & FH_Float'Image(((PNum / Expanded) - Integer_Part_F) * Expanded));
     Decimal_Part := ((PNum / Expanded) - Integer_Part_F) * ExpDecimals;
@@ -121,7 +107,6 @@ package body Formatting_Helpers is
     Decimal_Part_F: FH_Float;
     Decimal_Part_I: Integer;
     Exponent_Part_I: Integer;
-    ExpDecimals: constant FH_Float := 10.0 ** Decimals;
   begin
     Split_Integer_Decimal_Exponent_Nums(Num, Decimals, Integer_Part_I, Decimal_Part_F, Exponent_Part_I);
     Decimal_Part_I := Integer(Decimal_Part_F);
@@ -134,6 +119,36 @@ package body Formatting_Helpers is
 
   -- BEGIN: Private functions
 
+  function Get_Integer_Part(Num: in out FH_Float; Decimals: in Natural) return FH_Float is
+    package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
+    use FHEF;
+
+    EPSILON: constant FH_Float := 10.0 ** (-(Decimals + 1));
+    Log_Arg_Floored: FH_Float;
+    Expanded: FH_Float;
+    Integer_Part_F: FH_Float;
+  begin
+    Log_Arg_Floored := FH_Float'Floor(Log(Base => 10.0, X => Num));
+    Expanded := 10.0 ** Log_Arg_Floored;
+    --PNum := Round_To_Valid_Nums(PNum, Decimals);
+
+      --Ada.Text_IO.Put_Line("EP: " & FH_Float'Image((PNum / Expanded) + EPSILON) & " N: " & FH_Float'Image(PNum / Expanded));
+    declare
+      FPE: constant FH_Float := FH_Float'Floor((Num / Expanded) + EPSILON);
+      F: constant FH_Float := FH_Float'Floor(Num / Expanded);
+    begin
+      --Ada.Text_IO.Put_Line("FPE: " & FH_Float'Image(FPE) & " F: " & FH_Float'Image(F));
+      if FPE > F then
+       Num := Num + (EPSILON * Expanded);
+       Integer_Part_F := FPE;
+      else
+       Integer_Part_F := F;
+      end if;
+    end;
+
+    return Integer_Part_F;
+  end Get_Integer_Part;
+
   procedure Prepend_Zeros_To_Text(Num: in FH_Float; Decimals: in Natural; Text: in out UB_Text) is
     package FHEF is new Ada.Numerics.Generic_Elementary_Functions(FH_Float);
     use FHEF;
index 12bed86be5735859541d36a29ee6c6bee9ca5d05..5a10e37b82511e56144e78081b0af854839811b4 100644 (file)
@@ -14,6 +14,7 @@ package Formatting_Helpers is
                                                Exponent_Part: out UB_Text);
 
 private
+  function Get_Integer_Part(Num: in out FH_Float; Decimals: in Natural) return FH_Float;
   procedure Prepend_Zeros_To_Text(Num: in FH_Float; Decimals: in Natural; Text: in out UB_Text);
 
 end Formatting_Helpers;
index 92bb41c5f88ef4bd49161cd96a4917a6ad6d121b..2b9b491c3185432597c759112376875386ddec1e 100644 (file)
@@ -3,6 +3,7 @@ with Handler_Default;
 with Handler_Images;
 with Handler_Next_Problem;
 with Handler_Resources;
+with Handler_Show_Walkthrough;
 with Handler_Start;
 with Handler_Static;
 with Handler_Styles;
@@ -29,6 +30,8 @@ package body Handlers is
     Handler.Register(URI => "/resources",
                     Action => Handler_Resources.Callback,
                     Prefix => True);
+    Handler.Register(URI => "/show_walkthrough",
+                    Action => Handler_Show_Walkthrough.Callback);
 
     return Handler;
   end Get_Dispatchers;
index 273003fbeb736a3299193350e1c9aa0d5c6925c0..5806a1a51a6b2542c846f8c37073c5df9039dfc3 100644 (file)
@@ -4,6 +4,9 @@ with Ada.Numerics.Generic_Elementary_Functions;
 with Ada.Strings.Fixed;
 with Ada.Text_IO;
 with Formatting_Helpers;
+-- For walkthrough generator
+with AWS.Templates;
+
 
 separate(Problem_Generator)
 
@@ -17,6 +20,7 @@ package body Acidobazic_Suite is
 
     Parameters := (No_Both_Simplifications => False);
     Problem.Parameters := Parameters;
+    Problem.Walkthrough_Generated := False;
 
     return Problem;
   end Create;
@@ -29,7 +33,7 @@ package body Acidobazic_Suite is
     pH: pH_Float;
     pH_Answered: pH_Float;
   begin
-    pH := Calculate_Solution(Problem);
+    pH := Problem.Answer;
     -- Verify answer data
     if Answer.Find(ANSWER_PH_KEY) = Answer_Info.No_Element then
       return Malformed_Answer;
@@ -152,8 +156,205 @@ package body Acidobazic_Suite is
   end Get_Parameters;
 
   function Get_Walkthrough(Problem: in out Acidobazic_Problem; Walkthrough: out Walkthrough_Info.Map) return RetCode is
+    package FH is new Formatting_Helpers(pH_Float);
+    use AWS.Templates;
+
+    Atpr_Check: constant pH_Float := Walkthrough_Check_Autoprotolysis(Problem);
+    Dissoc_Check: constant pH_Float := Walkthrough_Check_Dissociation(Problem);
+    c_Ion: pH_Float := Walkthrough_Calculate_Concentration(Problem);
+    Trans_CI: Translate_Set;
+    Trans_AC: Translate_Set;
+    Trans_DC: Translate_Set;
+    c_Ion_I: UB_Text;
+    c_Ion_D: UB_Text;
+    c_Ion_E: UB_Text;
+    Kx_I: UB_Text;
+    Kx_D: UB_Text;
+    Kx_E: UB_Text;
+    cX_I: UB_Text;
+    cX_D: UB_Text;
+    cX_E: UB_Text;
+    Atpr_I: UB_Text;
+    Atpr_D: UB_Text;
+    Atpr_E: UB_Text;
+    Dissoc_I: UB_Text;
+    Dissoc_D: UB_Text;
+    Dissoc_E: UB_Text;
+    TeXCode: UB_Text;
+
+    Ret: RetCode;
   begin
-    return E_NOTIMPL;
+    if Problem.Walkthrough_Generated then
+      return OK;
+    end if;
+
+    FH.Split_Integer_Decimal_Exponent_Strs(c_Ion, DECIMALS, c_Ion_I, c_Ion_D, c_Ion_E);
+    FH.Split_Integer_Decimal_Exponent_Strs(Problem.Kx, DECIMALS, Kx_I, Kx_D, Kx_E);
+    FH.Split_Integer_Decimal_Exponent_Strs(Problem.cX, DECIMALS, cX_I, cX_D, cX_E);
+    FH.Split_Integer_Decimal_Exponent_Strs(Dissoc_Check, DECIMALS, Dissoc_I, Dissoc_D, Dissoc_E);
+    FH.Split_Integer_Decimal_Exponent_Strs(Atpr_Check, DECIMALS, Atpr_I, Atpr_D, Atpr_E);
+
+    Insert(Trans_CI, Assoc(CONC_ION_INT_KEY, c_Ion_I));
+    Insert(Trans_CI, Assoc(CONC_ION_DEC_KEY, c_Ion_D));
+    Insert(Trans_CI, Assoc(CONC_ION_EXP_KEY, c_Ion_E));
+
+    Insert(Trans_CI, Assoc(CONC_SUBST_INT_KEY, cX_I));
+    Insert(Trans_CI, Assoc(CONC_SUBST_DEC_KEY, cX_D));
+    Insert(Trans_CI, Assoc(CONC_SUBST_EXP_KEY, cX_E));
+
+    Insert(Trans_CI, Assoc(KX_INT_KEY, Kx_I));
+    Insert(Trans_CI, Assoc(KX_DEC_KEY, Kx_D));
+    Insert(Trans_CI, Assoc(KX_EXP_KEY, Kx_E));
+
+    TeXCode := Parse(Filename => WT_T_PREFIX & "ion_conc.ttex", Translations => Trans_CI);
+    Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_ION_CONC, Problem.Resource_Prefix);
+    if Ret /= OK then
+      return Ret;
+    end if;
+    Problem.Add_Tracked_Resource(WT_F_ION_CONC & WT_F_EXTENSION);
+
+    Insert(Trans_DC, Assoc(CONC_ION_INT_KEY, c_Ion_I));
+    Insert(Trans_DC, Assoc(CONC_ION_DEC_KEY, c_Ion_D));
+    Insert(Trans_DC, Assoc(CONC_ION_EXP_KEY, c_Ion_E));
+
+    Insert(Trans_DC, Assoc(CONC_SUBST_INT_KEY, cX_I));
+    Insert(Trans_DC, Assoc(CONC_SUBST_DEC_KEY, cX_D));
+    Insert(Trans_DC, Assoc(CONC_SUBST_EXP_KEY, cX_E));
+
+    Insert(Trans_DC, Assoc(CHECK_DISSOC_INT_KEY, Dissoc_I));
+    Insert(Trans_DC, Assoc(CHECK_DISSOC_DEC_KEY, Dissoc_D));
+    Insert(Trans_DC, Assoc(CHECK_DISSOC_EXP_KEY, Dissoc_E));
+
+    TeXCode := Parse(Filename => WT_T_PREFIX & "check_dissoc.ttex", Translations => Trans_DC);
+    Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_CHECK_DISSOC, Problem.Resource_Prefix);
+    if Ret /= OK then
+      return Ret;
+    end if;
+    Problem.Add_Tracked_Resource(WT_F_CHECK_DISSOC & WT_F_EXTENSION);
+
+    Insert(Trans_AC, Assoc(CONC_ION_INT_KEY, c_Ion_I));
+    Insert(Trans_AC, Assoc(CONC_ION_DEC_KEY, c_Ion_D));
+    Insert(Trans_AC, Assoc(CONC_ION_EXP_KEY, c_Ion_E));
+
+    Insert(Trans_AC, Assoc(CHECK_ATPR_INT_KEY, Atpr_I));
+    Insert(Trans_AC, Assoc(CHECK_ATPR_DEC_KEY, Atpr_D));
+    Insert(Trans_AC, Assoc(CHECK_ATPR_EXP_KEY, Atpr_E));
+
+    TeXCode := Parse(Filename => WT_T_PREFIX & "check_atpr.ttex", Translations => Trans_AC);
+    Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_CHECK_ATPR, Problem.Resource_Prefix);
+    if Ret /= OK then
+      return Ret;
+    end if;
+    Problem.Add_Tracked_Resource(WT_F_CHECK_ATPR & WT_F_EXTENSION);
+
+    case Problem.Simpl is
+      when Both =>
+        declare
+         pH_I: UB_Text;
+         pH_D: UB_Text;
+         Trans_A: Translate_Set;
+       begin
+         FH.Split_Integer_Decimal_Unscaled_Strs(Problem.Answer, DECIMALS, pH_I, pH_D);
+         Insert(Trans_A, Assoc(WT_ANSWER_PH_INT_KEY, pH_I));
+         Insert(Trans_A, Assoc(WT_ANSWER_PH_DEC_KEY, pH_D));
+         Insert(Trans_A, Assoc(CONC_SUBST_INT_KEY, cX_I));
+         Insert(Trans_A, Assoc(CONC_SUBST_DEC_KEY, cX_D));
+         Insert(Trans_A, Assoc(CONC_SUBST_EXP_KEY, cX_E));
+         Insert(Trans_A, Assoc(KX_INT_KEY, Kx_I));
+         Insert(Trans_A, Assoc(KX_DEC_KEY, Kx_D));
+         Insert(Trans_A, Assoc(KX_EXP_KEY, Kx_E));
+
+         case Problem.Subst_Type is
+           when Acid =>
+             TeXCode := Parse(Filename => WT_T_PREFIX & "result_acid.ttex", Translations => Trans_A);
+           when Base =>
+             TeXCode := Parse(Filename => WT_T_PREFIX & "result_base.ttex", Translations => Trans_A);
+         end case;
+         Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_RESULT, Problem.Resource_Prefix);
+         if Ret /= OK then
+           return Ret;
+         end if;
+         Problem.Add_Tracked_Resource(WT_F_RESULT & WT_F_EXTENSION);
+       end;
+
+      when Autoprotolysis =>
+       declare
+         pH_I: UB_Text;
+         pH_D: UB_Text;
+         Trans_PA: Translate_Set;
+         Trans_A: Translate_Set;
+       begin
+         c_Ion := Walkthrough_Calculate_Concentration_With_Dissoc(Problem);
+
+         FH.Split_Integer_Decimal_Unscaled_Strs(Problem.Answer, DECIMALS, pH_I, pH_D);
+         FH.Split_Integer_Decimal_Exponent_Strs(c_Ion, DECIMALS, c_Ion_I, c_Ion_D, c_Ion_E);
+
+         Insert(Trans_PA, Assoc(CONC_ION_INT_KEY, c_Ion_I));
+         Insert(Trans_PA, Assoc(CONC_ION_DEC_KEY, c_Ion_D));
+         Insert(Trans_PA, Assoc(CONC_ION_EXP_KEY, c_Ion_E));
+         Insert(Trans_PA, Assoc(CONC_SUBST_INT_KEY, cX_I));
+         Insert(Trans_PA, Assoc(CONC_SUBST_DEC_KEY, cX_D));
+         Insert(Trans_PA, Assoc(CONC_SUBST_EXP_KEY, cX_E));
+         Insert(Trans_PA, Assoc(KX_INT_KEY, Kx_I));
+         Insert(Trans_PA, Assoc(KX_DEC_KEY, Kx_D));
+         Insert(Trans_PA, Assoc(KX_EXP_KEY, Kx_E));
+         TeXCode := Parse(Filename => WT_T_PREFIX & "with_dissoc.ttex", Translations => Trans_PA);
+         Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_WITH_DISSOC, Problem.Resource_Prefix);
+         if Ret /= OK then
+           return Ret;
+         end if;
+         Problem.Add_Tracked_Resource(WT_F_WITH_DISSOC & WT_F_EXTENSION);
+
+         Insert(Trans_A, Assoc(WT_ANSWER_PH_INT_KEY, pH_I));
+         Insert(Trans_A, Assoc(WT_ANSWER_PH_DEC_KEY, pH_D));
+         Insert(Trans_A, Assoc(CONC_ION_INT_KEY, c_Ion_I));
+         Insert(Trans_A, Assoc(CONC_ION_DEC_KEY, c_Ion_D));
+         Insert(Trans_A, Assoc(CONC_ION_EXP_KEY, c_Ion_E));
+         case Problem.Subst_Type is
+           when Acid =>
+             TeXCode := Parse(Filename => WT_T_PREFIX & "result_acid2.ttex", Translations => Trans_A);
+           when Base =>
+             TeXCode := Parse(Filename => WT_T_PREFIX & "result_base2.ttex", Translations => Trans_A);
+         end case;
+
+         Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_RESULT, Problem.Resource_Prefix);
+         if Ret /= OK then
+           return Ret;
+         end if;
+         Problem.Add_Tracked_Resource(WT_F_RESULT & WT_F_EXTENSION);
+       end;
+      when Dissociation =>
+       declare
+         pH_I: UB_Text;
+         pH_D: UB_Text;
+         Trans_A: Translate_Set;
+       begin
+         FH.Split_Integer_Decimal_Unscaled_Strs(Problem.Answer, DECIMALS, pH_I, pH_D);
+         Insert(Trans_A, Assoc(WT_ANSWER_PH_INT_KEY, pH_I));
+         Insert(Trans_A, Assoc(WT_ANSWER_PH_DEC_KEY, pH_D));
+         Insert(Trans_A, Assoc(CONC_SUBST_INT_KEY, cX_I));
+         Insert(Trans_A, Assoc(CONC_SUBST_DEC_KEY, cX_D));
+         Insert(Trans_A, Assoc(CONC_SUBST_EXP_KEY, cX_E));
+         Insert(Trans_A, Assoc(KX_INT_KEY, Kx_I));
+         Insert(Trans_A, Assoc(KX_DEC_KEY, Kx_D));
+         Insert(Trans_A, Assoc(KX_EXP_KEY, Kx_E));
+
+         case Problem.Subst_Type is
+           when Acid =>
+             TeXCode := Parse(Filename => WT_T_PREFIX & "result_acid_atpr.ttex", Translations => Trans_A);
+           when Base =>
+             TeXCode := Parse(Filename => WT_T_PREFIX & "result_base_atpr.ttex", Translations => Trans_A);
+         end case;
+         if Ret /= OK then
+           return Ret;
+         end if;
+         Ret := Problem_Generator.TeX_To_PNG(TeXCode, WT_F_RESULT, Problem.Resource_Prefix);
+         Problem.Add_Tracked_Resource(WT_F_RESULT & WT_F_EXTENSION);
+       end;
+    end case;
+
+    Problem.Walkthrough_Generated := True;
+    return OK;
   end Get_Walkthrough;
 
   procedure New_Problem(Problem: in out Acidobazic_Problem) is
@@ -174,6 +375,8 @@ package body Acidobazic_Suite is
 
     Calculate_Concentration_Limits(cX_Min, cX_Max, Problem.Kx, Problem.Simpl);
     Problem.cX := Random_cX(cX_Min, cX_Max);
+
+    Problem.Answer := Calculate_Solution(Problem);
   end New_Problem;
 
   function Set_Parameters(Problem: in out Acidobazic_Problem; Parameters: in Parameters_Info.Map) return RetCode is
@@ -256,20 +459,10 @@ package body Acidobazic_Suite is
       -- We are ignoring autoprotolysis and taking dissociation into account
       when Autoprotolysis =>
        declare
-         D: pH_Float;
-         X_1: pH_Float;
-         X_2: pH_Float;
          pX: pH_Float;
        begin
-         -- Solve the quadratic equation
-         D := (Problem.Kx ** 2.0) + (4.0 * Problem.Kx * Problem.cX);
-         if D < 0.0 then
-           raise Constraint_Error;
-         end if;
-         D := D ** 0.5;
-         X_1 := (-Problem.Kx + D) / 2.0;
-         X_2 := (-Problem.Kx - D) / 2.0;
-         pX := X_To_pX(pH_Float'Max(X_1, X_2));
+         pX := Walkthrough_Calculate_Concentration_With_Dissoc(Problem);
+         pX := X_To_pX(pX);
          if Problem.Subst_Type = Base then
            return 14.0 - pX;
          else
@@ -429,4 +622,51 @@ package body Acidobazic_Suite is
     return MEF.Log(Base => 10.0, X => X) * (-1.0);
   end X_To_pX;
 
+  -- Walkthrough functiokns
+  function Walkthrough_Calculate_Concentration(Problem: in Acidobazic_Problem) return pH_Float is
+    package MEF is new Ada.Numerics.Generic_Elementary_Functions(pH_Float);
+    use MEF;
+  begin
+    return (Problem.Kx * Problem.cX) ** (0.5);
+  end Walkthrough_Calculate_Concentration;
+
+  function Walkthrough_Calculate_Concentration_With_Dissoc(Problem: in Acidobazic_Problem) return pH_Float is
+    package MEF is new Ada.Numerics.Generic_Elementary_Functions(pH_Float);
+    use MEF;
+
+    D: pH_Float;
+    X_1: pH_Float;
+    X_2: pH_Float;
+  begin
+    -- Solve the quadratic equation
+    D := (Problem.Kx ** 2.0) + (4.0 * Problem.Kx * Problem.cX);
+    if D < 0.0 then
+      raise Constraint_Error;
+    end if;
+    D := D ** 0.5;
+    X_1 := (-Problem.Kx + D) / 2.0;
+    X_2 := (-Problem.Kx - D) / 2.0;
+    return pH_Float'Max(X_1, X_2);
+  end Walkthrough_Calculate_Concentration_With_Dissoc;
+
+  function Walkthrough_Check_Autoprotolysis(Problem: in Acidobazic_Problem) return pH_Float is
+    package MEF is new Ada.Numerics.Generic_Elementary_Functions(pH_Float);
+    use MEF;
+  begin
+    return K_W / (Problem.Kx * Problem.cX);
+  end Walkthrough_Check_Autoprotolysis;
+
+  function Walkthrough_Check_Dissociation(Problem: in Acidobazic_Problem) return pH_Float is
+    package MEF is new Ada.Numerics.Generic_Elementary_Functions(pH_Float);
+    use MEF;
+  begin
+    return ((Problem.Kx * Problem.cX) ** (0.5)) / Problem.cX;
+  end Walkthrough_Check_Dissociation;
+
+  -- Destructor
+  overriding procedure Finalize(Problem: in out Acidobazic_Problem) is
+  begin
+    Problem.Free_Tracked_Resources;
+  end Finalize;
+
 end Acidobazic_Suite;
index ffb0ae03b3a32a4562d93ad95a61cf10c23a1529..32f4c523b077259bce3a961c1591882962fc39c6 100644 (file)
@@ -167,6 +167,7 @@ package body Titration_Curve_Suite is
     Draw_Chart_Circle(Ctx, V_Over_Second_Equiv_Ans, V_Over_Second_Equiv, pH_Over_Second_Equiv_Ans);
 
     Status_Out := Cairo.Png.Write_To_Png(Surface, Ada.Strings.Unbounded.To_String(Problem.Resource_Prefix) & TITRATION_CURVE_FILENAME);
+    Problem.Add_Tracked_Resource(TITRATION_CURVE_FILENAME);
     Message := To_UB_Text("");
 
     -- Prepare FillIns
@@ -298,17 +299,8 @@ package body Titration_Curve_Suite is
   end Set_Parameters;
 
   overriding procedure Finalize(Problem: in out Titration_Curve_Problem) is
-    Path: constant String := Ada.Strings.Unbounded.To_String(Problem.Resource_Prefix) & TITRATION_CURVE_FILENAME;
-    File: Ada.Text_IO.File_Type;
   begin
-    begin
-      Ada.Text_IO.Open(File => File, Mode => Ada.Text_IO.In_File, Name => Path);
-      Ada.Text_IO.Close(File);
-      Ada.Directories.Delete_File(Path);
-    exception
-      when Ada.Text_IO.Name_Error =>
-       null;
-    end;
+    Free_Tracked_Resources(Problem);
   end Finalize;
   -- END: Inherited functions
 
index 8e4cae7ba099e14e19aa8e77a619cb8088820bad..ff5cebfa5ab2d67a06700e36e05656fed3c2eec4 100644 (file)
@@ -1,3 +1,7 @@
+with Ada.Directories;
+with Ada.Text_IO;
+with Interfaces.C;
+
 package body Problem_Generator is
 
   function Get_Problem(P_Type: in Problem_Type) return access Chem_Problem'Class is
@@ -12,6 +16,44 @@ package body Problem_Generator is
     end case;
   end Get_Problem;
 
+  function TeX_To_PNG(TeXCode: in UB_Text; Filename: in String; Resource_Prefix: in Ada.Strings.Unbounded.Unbounded_String) return RetCode is
+    function Sys (Arg: Interfaces.C.Char_Array) return Integer;
+    pragma Import(C, Sys, "system");
+
+    Output_File_Param: constant String := Ada.Strings.Unbounded.To_String(Resource_Prefix) & Filename;
+    TeXCode_Param: constant String := Ada.Strings.Unbounded.To_String(TeXCode);
+    Ret_Val: Integer;
+  begin
+    Ret_Val := Sys(Interfaces.C.To_C("./tex2ima -o " & Output_File_Param & " -s '" & TeXCode_Param & "'"));
+    if Ret_Val /= 0 then
+      return E_FAIL;
+    else
+      return OK;
+    end if;
+  end TeX_To_PNG;
+
+  procedure Add_Tracked_Resource(Problem: in out Chem_Problem; Name: in String) is
+    Full_Name: constant String := Ada.Strings.Unbounded.To_String(Problem.Resource_Prefix) & Name;
+  begin
+    Problem.TRL.Append(Full_Name);
+  end Add_Tracked_Resource;
+
+  procedure Free_Tracked_Resources(Problem: in out Chem_Problem) is
+    procedure Delete_Tracked_File(C: in Resource_List.Cursor) is
+      Path: constant String := Resource_List.Element(C);
+      File: Ada.Text_IO.File_Type;
+    begin
+      Ada.Text_IO.Open(File => File, Mode => Ada.Text_IO.In_File, Name => Path);
+      Ada.Text_IO.Close(File);
+      Ada.Directories.Delete_File(Path);
+    exception -- No such file, skip it
+      when Ada.Text_IO.Name_Error =>
+        null;
+    end Delete_Tracked_File;
+  begin
+    Problem.TRL.Iterate(Delete_Tracked_File'Access);
+  end Free_Tracked_Resources;
+
   procedure Set_Resource_Prefix(Problem: in out Chem_Problem; Prefix: in String) is
   begin
     Problem.Resource_Prefix := Ada.Strings.Unbounded.To_Unbounded_String(Prefix);
index 6ad8862cac2da197f3aaadb323917f69c093c1c3..93f117aa098ec33aeabbd68c9fcd9732b4f46fb0 100644 (file)
@@ -1,5 +1,6 @@
 with Global_Types;
 with Problem_Generator_Syswides;
+with Ada.Containers.Indefinite_Doubly_Linked_Lists;
 with Ada.Finalization;
 with Ada.Strings.Unbounded;
 with Cairo;
@@ -21,11 +22,18 @@ package Problem_Generator is
   function Get_Problem(P_Type: in Problem_Type) return access Chem_Problem'Class;
 
 private
+  function TeX_To_PNG(TeXCode: in UB_Text; Filename: in String; Resource_Prefix: in Ada.Strings.Unbounded.Unbounded_String) return RetCode;
 
+  package Resource_List is new Ada.Containers.Indefinite_Doubly_Linked_Lists(Element_Type => String);
   type Chem_Problem is abstract limited new Ada.Finalization.Limited_Controlled with
     record
       Resource_Prefix: Ada.Strings.Unbounded.Unbounded_String;
+      TRL: Resource_List.List;
     end record;
+  procedure Add_Tracked_Resource(Problem: in out Chem_Problem; Name: in String);
+  procedure Free_Tracked_Resources(Problem: in out Chem_Problem);
+
+  WALKTHROUGH_TEMPLATES_PATH: constant String := "walkthrough_templates/";
 
   package Acidobazic_Suite is
     use Problem_Generator_Syswides.Acidobazic_Suite;
@@ -40,6 +48,7 @@ private
       function Get_Parameters(Problem: in out Acidobazic_Problem; Parameters: out Parameters_Info.Map) return RetCode;
       function Get_Walkthrough(Problem: in out Acidobazic_Problem; Walkthrough: out Walkthrough_Info.Map) return RetCode;
       function Set_Parameters(Problem: in out Acidobazic_Problem; Parameters: in Parameters_Info.Map) return RetCode;
+      overriding procedure Finalize(Problem: in out Acidobazic_Problem);
 
     private
       type pH_Float is digits 15;
@@ -65,6 +74,10 @@ private
       function Random_Kx return pH_Float;
       function Random_Simplification(Kx: in pH_Float; No_Both_Simplifications: in Boolean) return Simplification;
       function X_To_pX(X: in pH_Float) return pH_Float;
+      function Walkthrough_Calculate_Concentration(Problem: in Acidobazic_Problem) return pH_Float;
+      function Walkthrough_Calculate_Concentration_With_Dissoc(Problem: in Acidobazic_Problem) return pH_Float;
+      function Walkthrough_Check_Autoprotolysis(Problem: in Acidobazic_Problem) return pH_Float;
+      function Walkthrough_Check_Dissociation(Problem: in Acidobazic_Problem) return pH_Float;
 
       type Acidobazic_Problem is new Problem_Generator.Chem_Problem with
        record
@@ -74,6 +87,7 @@ private
          Parameters: Acidobazic_Parameters;
          Simpl: Simplification;
          Subst_Type: Substance_Type;
+         Walkthrough_Generated: Boolean;
        end record;
 
       Acidic_Min_pH: constant pH_Float := 1.75;
@@ -85,6 +99,33 @@ private
       MAX_CONCENTRATION_DIFF: constant pH_Float := 0.75;
       CONCENTRATION_HARD_MIN_LIMIT: constant pH_Float := 1.0E-6;
       DECIMALS: constant Natural := 3;
+      --
+      CHECK_ATPR_INT_KEY: constant String := "CHECK_ATPR_INT";
+      CHECK_ATPR_DEC_KEY: constant String := "CHECK_ATPR_DEC";
+      CHECK_ATPR_EXP_KEY: constant String := "CHECK_ATPR_EXP";
+      CHECK_DISSOC_INT_KEY: constant String := "CHECK_DISSOC_INT";
+      CHECK_DISSOC_DEC_KEY: constant String := "CHECK_DISSOC_DEC";
+      CHECK_DISSOC_EXP_KEY: constant String := "CHECK_DISSOC_EXP";
+      CONC_ION_INT_KEY: constant String := "CONC_ION_INT";
+      CONC_ION_DEC_KEY: constant String := "CONC_ION_DEC";
+      CONC_ION_EXP_KEY: constant String := "CONC_ION_EXP";
+      CONC_SUBST_INT_KEY: constant String := "CONC_SUBST_INT";
+      CONC_SUBST_DEC_KEY: constant String := "CONC_SUBST_DEC";
+      CONC_SUBST_EXP_KEY: constant String := "CONC_SUBST_EXP";
+      KX_INT_KEY: constant String := "KX_INT";
+      KX_DEC_KEY: constant String := "KX_DEC";
+      KX_EXP_KEY: constant String := "KX_EXP";
+      WT_ANSWER_PH_INT_KEY: constant String := "WT_ANSWER_PH_INT";
+      WT_ANSWER_PH_DEC_KEY: constant String := "WT_ANSWER_PH_DEC";
+      --
+      WT_F_EXTENSION: constant String := ".png";
+      WT_F_RESULT: constant String := "result";
+      WT_F_ION_CONC: constant String := "ion_conc";
+      WT_F_CHECK_ATPR: constant String := "check_atpr";
+      WT_F_CHECK_DISSOC: constant String := "check_dissoc";
+      WT_F_WITH_DISSOC: constant String := "with_dissoc";
+      --
+      WT_T_PREFIX: constant String := WALKTHROUGH_TEMPLATES_PATH & "acidobazic_suite/";
 
   end Acidobazic_Suite;
 
@@ -261,7 +302,7 @@ private
     X_AXIS_UNITS_TEXT: constant String := "V (odměrný roztok) [mL]";
     Y_AXIS_UNITS_TEXT: constant String := "pH";
     --
-    TITRATION_CURVE_FILENAME: constant String := "-curve.png";
+    TITRATION_CURVE_FILENAME: constant String := "curve.png";
 
   end Titration_Curve_Suite;
 
index ce40a39685266a4e84877a90fc8c7012cacbd9b8..11dac59b49baf44c54d37679c28f1384b2ffd2da 100644 (file)
@@ -98,6 +98,50 @@ package body Problem_Manager is
                                        Pr_Cat => Problem_Category'Image(Pr_Cat));
   end Display_Assignment;
 
+  function Display_Walkthrough(UID: in Unique_ID; HTML: out HTML_Code; Pr_ID: in Problem_ID) return RetCode is
+    Assignment: Problem_Generator_Syswides.Assignment_Info.Map;
+    Parameters: Problem_Generator_Syswides.Parameters_Info.Map;
+    Walkthrough: Problem_Generator_Syswides.Walkthrough_Info.Map;
+    Pr_Cat: Problem_Category;
+    Ret: RetCode;
+    Stored: Stored_Problem_All_Access;
+  begin
+    Stored := Active_Sessions.Get_Problem(UID, Pr_ID);
+    if Stored = null then
+      return E_NOTFOUND;
+    end if;
+
+    Pr_Cat := Stored.Category;
+    Ret := Stored.Problem.Get_Parameters(Parameters);
+    if Ret /= OK then
+      Stored.Mutex.Unlock;
+      return Face_Generator.Generate_Error_Face(HTML, ERRMSG_GET_PARAMETERS & " (" & RetCode'Image(Ret) & ")");
+    end if;
+
+    begin
+      Ret := Stored.Problem.Get_Assignment(Assignment);
+      if Ret /= OK then
+       Stored.Mutex.Unlock;
+       Logging_System.Log(ERRMSG_GET_ASSIGNMENT & " (" & RetCode'Image(Ret) & ")", Logging_System.ERROR);
+       return Face_Generator.Generate_Error_Face(HTML, ERRMSG_GET_ASSIGNMENT & " (" & RetCode'Image(Ret) & ")");
+      end if;
+      Ret := Stored.Problem.Get_Walkthrough(Walkthrough);
+      if Ret /= OK then
+       Stored.Mutex.Unlock;
+       Logging_System.Log(ERRMSG_GET_ASSIGNMENT & " (" & RetCode'Image(Ret) & ")", Logging_System.ERROR);
+       return Face_Generator.Generate_Error_Face(HTML, ERRMSG_GET_ASSIGNMENT & " (" & RetCode'Image(Ret) & ")");
+      end if;
+    exception
+      when Ex: others =>
+       Stored.Mutex.Unlock;
+       Logging_System.Log(ERRMSG_UNHANDLED_EXCEPTION & " (" & Ada.Exceptions.Exception_Information(Ex) & ")", Logging_System.ERROR);
+       return Face_Generator.Generate_Error_Face(HTML, ERRMSG_UNHANDLED_EXCEPTION & " (" & Ada.Exceptions.Exception_Information(Ex) & ")");
+    end;
+
+    Stored.Mutex.Unlock;
+    return Ret;
+  end Display_Walkthrough;
+
   function Get_UID(Raw_UID: in String; UID: out Unique_ID) return Boolean is
   begin
     begin
@@ -194,7 +238,7 @@ package body Problem_Manager is
 
   function Build_Resource_Prefix(UID: in Unique_ID; Pr_Cat: in Problem_Category; Pr_ID: in Problem_ID) return String is
   begin
-    return "resources/resource_" & Ada.Strings.Fixed.Trim(Source => Unique_ID'Image(UID), Side => Ada.Strings.Left) & "_" & Ada.Strings.Fixed.Trim(Source => Problem_Category'Image(Pr_Cat), Side => Ada.Strings.Left) & "_" & Ada.Strings.Fixed.Trim(Source => Problem_ID'Image(Pr_ID), Side => Ada.Strings.Left);
+    return "resources/resource_" & Ada.Strings.Fixed.Trim(Source => Unique_ID'Image(UID), Side => Ada.Strings.Left) & "_" & Ada.Strings.Fixed.Trim(Source => Problem_Category'Image(Pr_Cat), Side => Ada.Strings.Left) & "_" & Ada.Strings.Fixed.Trim(Source => Problem_ID'Image(Pr_ID), Side => Ada.Strings.Left) & "-";
   end Build_Resource_Prefix;
 
   procedure Free_Chem_Problem(Problem: in out Chem_Problem_All_Access) is
index 2af5a99ef6bc6779cb301bd9c785b3c3a435f2e7..58aafe766f392ac90e75a8d702e25b8dcb106076 100644 (file)
@@ -12,6 +12,7 @@ package Problem_Manager is
   function Display_Checked_Answer(UID: in Unique_ID; Answer: in Problem_Generator_Syswides.Answer_Info.Map; HTML: out HTML_Code;
                                  Pr_ID: in Problem_ID) return RetCode;
   function Display_Assignment(UID: in Unique_ID; HTML: out HTML_Code) return RetCode;
+  function Display_Walkthrough(UID: in Unique_ID; HTML: out HTML_Code; Pr_ID: in Problem_ID) return RetCode;
   --function Display_Next_Assignment(UID: in Unique_ID;
   --                              Problem_Parameters: in Problem_Generator_Syswides.Parameters_Info.Map;
   --                              HTML: out HTML_Code) return Boolean;
@@ -67,5 +68,5 @@ private
     Last_UID: Unique_ID := Unique_ID'First;
   end Active_Sessions;
 
-  MAX_STORED_PROBLEMS: Problem_ID := 20;
+  MAX_STORED_PROBLEMS: Problem_ID := 3;
 end Problem_Manager;