4. Decimals pythonο
The python below requires the following .tex files:
1"""
2Module of functions to return decimals dictionary for LaTeX
3"""
4
5import random
6
7
8def get_dec_dict(nump, numip, numdp):
9 if nump is None or nump == 3:
10 nump = random.randint(1, 2)
11 match nump:
12 case 1:
13 return add_dict(numip, numdp)
14 case 2:
15 return sub_dict(numip, numdp)
16
17
18def add_dict(numip, numdp):
19 # na + nb = nc
20 # Generate a random decimal number between 0.00001 and 9999
21 na = random.uniform(10**-numdp, (10**numip) - 0.1)
22 nb = random.uniform(10**-numdp, (10**numip) - 0.1 - na)
23 # Format the result to 0 to 5 decimal places
24 format_string = "{:." + str(numdp) + "f}"
25 na = format_string.format(na)
26 nb = format_string.format(nb)
27 nc = float(na) + float(nb)
28 nc = format_string.format(nc)
29 kv = dict()
30 kv["num1"] = f"{na}"
31 kv["num2"] = f"{nb}"
32 kv["process"] = "+"
33 kv["answer"] = f"{nc}"
34 kv["numip"] = f"{str(numip)}"
35 kv["numdp"] = f"{str(numdp)}"
36 return kv
37
38
39def sub_dict(numip, numdp):
40 # na + nb = nc
41 # Generate a random decimal number between 0.01 and 100
42 nc = random.uniform(10**-numdp, (10**numip) - 0.1)
43 nb = random.uniform(10**-numdp, (10**numip) - 0.1 - nc)
44 # Format the result to 0 to 5 decimal places
45 format_string = "{:." + str(numdp) + "f}"
46 nc = format_string.format(nc)
47 nb = format_string.format(nb)
48 na = float(nc) + float(nb)
49 na = format_string.format(na)
50 #
51 kv = dict()
52 kv["num1"] = f"{na}"
53 kv["num2"] = f"{nb}"
54 kv["process"] = "-"
55 kv["answer"] = f"{nc}"
56 kv["numip"] = f"{str(numip)}"
57 kv["numdp"] = f"{str(numdp)}"
58 return kv
59
The Python to create booklets of questions involving the addition and subtraction of decimals, is below.
1from pathlib import Path
2import subprocess
3import os
4import time
5import decimals_functions as decf
6
7# import magick_pdf_to_png
8
9
10currfile_dir = Path(__file__).parent
11tex_template_path = currfile_dir / "decimals_booklet_template.tex"
12texans_template_path = currfile_dir / "decimals_booklet_ans_template.tex"
13tex_diagram_template_path = (currfile_dir /
14 "decimals_booklet_diagram_template.tex")
15
16colbreak = "\columnbreak % Break column after 30 questions \n"
17
18
19def convert_to_pdf(tex_path, outputdir):
20 tex_path = Path(tex_path).resolve()
21 outputdir = Path(outputdir).resolve()
22 # for testing
23 # print(f"tex_path: {tex_path}")
24 # print(f"outputdir: {outputdir}")
25 try:
26 # Generate the PDF
27 subprocess.run(["latexmk", "-pdf", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
28 # # Clean auxiliary files after successful PDF generation
29 subprocess.run(["latexmk", "-c", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
30 # for hosted remove stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL for debugging any errors
31 # Remove the .tex file manually
32 if tex_path.exists():
33 os.remove(tex_path)
34 except subprocess.CalledProcessError as e:
35 print(f"Error: {e}")
36
37
38# tex_keys = ["num1", "num2", "process", "numip", "numdp"]
39tex_keys_q = ["answer"]
40
41def make1_diagram(tex_diagram_template_txt, nump, numip, numdp):
42 tex_diagram_template_txt_ans = tex_diagram_template_txt
43 kv = decf.get_dec_dict(nump, numip, numdp)
44 posttext = r"\vspace{-1pt}"
45
46 for key, value in kv.items():
47 tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace(
48 "<<" + key + ">>", value
49 )
50
51 for key, value in kv.items():
52 if key in tex_keys_q:
53 tex_diagram_template_txt = tex_diagram_template_txt.replace(
54 "<<" + key + ">>", ""
55 )
56 else:
57 tex_diagram_template_txt = tex_diagram_template_txt.replace(
58 "<<" + key + ">>", value
59 )
60 # return tex_diagram_template_txt
61 return tex_diagram_template_txt + posttext, tex_diagram_template_txt_ans + posttext
62
63
64def get_title(nump):
65 match nump:
66 case 1:
67 return "Addition"
68 case 2:
69 return "Subtraction"
70 case 3:
71 return "Multiplication"
72 case 4:
73 return "Addition and subtraction"
74 case 5:
75 return "Addition, subtraction and multiplication"
76
77
78def main():
79 nump = input("Enter 1, 2, or 3 for +, -, random for the process \n")
80 if nump.strip().isdigit():
81 nump = int(nump)
82 if not nump in [1, 2]:
83 nump = 3 # random by default
84 else:
85 nump = 3 # random by default
86 # get title for part of heading indicating which process/es
87 title = get_title(nump)
88 #
89 numip = input(
90 "Enter 0, 1, 2, 3, or 4 for the number of places before the decimal point: \n"
91 )
92 if numip.strip().isdigit():
93 numip = int(numip)
94 if not numip in [0, 1, 2, 3, 4]:
95 numip = 1 # 1 by default
96 else:
97 numip = 1 # 1 by default
98 #
99 numdp = input(
100 "Enter 1, 2, 3, 4, or 5 for the number of decimal places: \n")
101 if numdp.strip().isdigit():
102 numdp = int(numdp)
103 if not numdp in [1, 2, 3, 4, 5]:
104 numdp = 1 # 1 by default
105 else:
106 numdp = 1 # 1 by default
107 #
108 #
109 numq = input(
110 "Enter the number of questions from 1 to 108, with 27 per page: \n")
111 if numq.strip().isdigit():
112 numq = int(numq)
113 if not numq in range(1, 109):
114 numq = 27 # 27 by default
115 else:
116 numq = 27 # 27 by default
117 #
118 filename = input(
119 "Enter the base filename to be added to the prefix asd_: \n")
120 if not filename:
121 filename = "1" # "asd_1_q and asd_1_ans as default file"
122 # set names of files that are made
123 # questions
124 tex_output_path = currfile_dir / f"asdBk_{filename}_q.tex"
125
126 # answers
127 tex_output_path_ans = currfile_dir / f"asdBk_{filename}_ans.tex"
128
129 # Read in the LaTeX template file
130 with open(tex_template_path, "r") as infile:
131 tex_template_txt = infile.read()
132 # Read in the LaTeX template file for answers
133 with open(texans_template_path, "r") as infile:
134 tex_template_txt_ans = infile.read()
135 # Read in the LaTeX diagram template file
136 with open(tex_diagram_template_path, "r") as infile:
137 tex_diagram_template_txt = infile.read()
138
139 # <<diagrams>>
140 # generate column text and column text for answers
141 diagram_text = ""
142 diagram_text_ans = ""
143 for i in range(1, numq + 1):
144 img_tex, img_tex_ans = make1_diagram(tex_diagram_template_txt, nump,
145 numip, numdp)
146 diagram_text += img_tex
147 diagram_text_ans += img_tex_ans
148 if i % 27 == 0 and i > 0 and i != numq:
149 diagram_text += colbreak
150 diagram_text_ans += colbreak
151
152 # Replace the <<title>> placeholder in the LaTeX template
153 tex_template_txt = tex_template_txt.replace("<<title>>", title)
154 tex_template_txt_ans = tex_template_txt_ans.replace("<<title>>", title)
155 # Replace the <<diagrams>> placeholder in the LaTeX template with the generated diagrams
156 tex_template_txt = tex_template_txt.replace("<<diagrams>>", diagram_text)
157 tex_template_txt_ans = tex_template_txt_ans.replace(
158 "<<diagrams>>", diagram_text_ans)
159
160 # Write the question tex to an output file
161 with open(tex_output_path, "w") as outfile:
162 outfile.write(tex_template_txt)
163
164 # Write the answer tex to an output file
165 with open(tex_output_path_ans, "w") as outfile:
166 outfile.write(tex_template_txt_ans)
167
168 # Wait for the file to be created
169 time.sleep(1)
170 # Convert the LaTeX files to PDFs
171 convert_to_pdf(tex_output_path, currfile_dir)
172 convert_to_pdf(tex_output_path_ans, currfile_dir)
173
174
175if __name__ == "__main__":
176 print("starting")
177 main()
178 print("finished")