4. Backtracking 2-step booklet python
The python file to make 2-step backtracking booklets is below.
The required LaTeX files are below.
The python file, backtracking_2step_booklet_maker.py, when run, will ask for these inputs:
Choose the type of diagrams:
"Enter 1, 2, 3, 4, 5 or 6 for standard, 1 row build expression, 1 row inverse operations, 1 row from expression, solve from expression, blank "
Choose the first arithmetic process:
"Enter 1, 2, 3, 4 or 5 for +, -, X, /, random for the 1st process"
.Choose the second arithmetic process:
"Enter 1, 2, 3, 4 or 5 for +, -, X, /, random for the 2nd process"
Choose the number of questions from 1 to 100:
"Enter the number of questions from 1 to 100"
Choose the file name base:
"Enter the base filename to be added to the prefix bt2Bk_:"
. The filename will have “_q” added for the question booklet and “_ans” for the answer booklet.The prefix will be “bt2” for standard; “bt2_build” for 1 row build expression; or “bt2_invop” for 1 row inverse operations.
The prefix will be “bt2_fromexp” for 1 row from expression; “bt2_solvefromexp” for solve from expression; or “bt2_blank” for blank.
The filename will have “_q” added for the question diagram and “_ans” for the answer diagram.
4.1. Sample 2-step backtracking booklet
4.2. 2-step backtracking: 1 row; building the expression
4.3. 2-step backtracking: 1 row; inverse operations
4.4. 2-step backtracking: 1 row; from the expression
4.5. 2-step backtracking: solve from the expression
4.6. 2-step backtracking: python
1# 10 to page for standard and solve
2# 20 to page for build
3# 15 to page for inv and from exp
4
5from pathlib import Path
6import subprocess
7import time
8import random
9import magick_pdf_to_png
10import backtracking_functions as btf
11
12currfile_dir = Path(__file__).parent
13tex_template_path = currfile_dir / "backtrack_2step_booklet_template.tex"
14texans_template_path = currfile_dir / "backtrack_2step_booklet_ans_template.tex"
15
16tex_diagram_standard_template_path = (
17 currfile_dir / "backtrack_2step_booklet_diagram_template.tex"
18)
19tex_diagram_buildexp_template_path = (
20 currfile_dir / "backtrack_2step_booklet_diagram_template_1buildexp.tex"
21)
22tex_diagram_invop_template_path = (
23 currfile_dir / "backtrack_2step_booklet_diagram_template_1invop.tex"
24)
25tex_diagram_fromexp_template_path = (
26 currfile_dir / "backtrack_2step_booklet_diagram_template_1invop.tex"
27)
28tex_diagram_solvefromexp_template_path = (
29 currfile_dir / "backtrack_2step_booklet_diagram_template.tex"
30)
31tex_diagram_blank_template_path = (
32 currfile_dir / "backtrack_2step_booklet_diagram_template_blank.tex"
33)
34
35
36def convert_to_pdf(tex_path, currfile_dir, aux_path):
37 """
38 Converts a TeX file to PDF format using pdfLaTeX.
39
40 Args:
41 tex_path (str): The path to the TeX file.
42 currfile_dir (str): The path to the directory where the TeX file is located.
43 aux_path (str): The path to the directory where auxiliary files will be stored.
44
45 Returns:
46 subprocess.CompletedProcess: A subprocess.CompletedProcess object containing information about the completed process.
47
48 Raises:
49 FileNotFoundError: If the TeX file does not exist.
50 subprocess.CalledProcessError: If pdfLaTeX returns a non-zero exit code.
51 """
52 result = subprocess.run(
53 [
54 "pdfLaTeX",
55 tex_path,
56 "-output-directory",
57 currfile_dir,
58 "-aux-directory",
59 aux_path,
60 ],
61 stdout=subprocess.PIPE,
62 )
63
64
65# % end modify values for backtracking
66# tex_keys = ['stepAB','stepABrev','stepBC', 'stepBCrev', boxA','boxB', 'boxC', 'boxCrev, 'boxBrev', 'boxArev' ]
67tex_keys_q = ["stepAB", "stepBC", "boxA", "boxCrev"]
68# used by from expression
69tex_keys_q_fromexp = ["boxC"]
70# used by from expression
71tex_keys_q_solvefromexp = ["boxC", "boxCrev"]
72
73
74def num_for_type(bt_type):
75 """
76 1 standard, 10 per page
77 2 1 row build expression, 20 to page
78 3 1 row inverse operations, 15 per page
79 4 1 row from expression, 15 per page
80 5 solve from expression, 10 per page
81 6 blank, 10 per page
82 """
83 '''Returns the number of pages for a given bt_type.
84
85 Args:
86 bt_type (int): An integer between 1 and 6.
87
88 Returns:
89 int: The number of pages for the given bt_type.
90 '''
91 match bt_type:
92 case 1:
93 num = 20
94 case 2:
95 num = 40
96 case 3:
97 num = 30
98 case 4:
99 num = 30
100 case 5:
101 num = 20
102 case 6:
103 num = 20
104 return num
105
106
107def make1_diagram(tex_diagram_template_txt, num1, num2, tex_keys_q):
108 """
109 This function takes in a LaTeX template for a diagram, two numbers `num1` and `num2`, and a list of keys `tex_keys_q`.
110
111 Args:
112 tex_diagram_template_txt (str): A string representing the LaTeX template for the diagram.
113 num1 (int): An integer representing the first number.
114 num2 (int): An integer representing the second number.
115 tex_keys_q (list): A list of strings representing the keys for the diagram.
116
117 Returns:
118 tuple: A tuple containing two strings. The first string is the LaTeX template with the keys replaced by their corresponding values from `num1` and `num2`. The second string is the same LaTeX template with all keys replaced by their corresponding values from `num1` and `num2`.
119 """
120
121 tex_diagram_template_txt_ans = tex_diagram_template_txt
122 posttext = r"\vspace{-2pt}"
123 kv = btf.get_2step_process_dict(num1, num2)
124
125 for key, value in kv.items():
126 tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace(
127 "<<" + key + ">>", value
128 )
129
130 for key, value in kv.items():
131 if key in tex_keys_q:
132 tex_diagram_template_txt = tex_diagram_template_txt.replace(
133 "<<" + key + ">>", value
134 )
135 else:
136 tex_diagram_template_txt = tex_diagram_template_txt.replace(
137 "<<" + key + ">>", ""
138 )
139
140 # return tex_diagram_template_txt
141 return tex_diagram_template_txt + posttext, tex_diagram_template_txt_ans + posttext
142
143
144def main():
145 input_str = (
146 "Enter 1, 2, 3, 4, 5 or 6 for standard, 1 row build expression, "
147 + "1 row inverse operations, 1 row from expression, solve from expression, blank \n"
148 )
149 bt_type = input(input_str)
150 if bt_type.strip().isdigit():
151 bt_type = int(bt_type)
152 if not bt_type in [1, 2, 3, 4, 5, 6]:
153 bt_type = 1 # standard by default
154 else:
155 bt_type = 1 # standard by default
156 #
157 if bt_type in [1, 2, 3, 4, 5]:
158 num1 = input("Enter 1, 2, 3, 4 or 5 for +, -, X, /, random for 1st process \n")
159 if num1.strip().isdigit():
160 num1 = int(num1)
161 if num1 not in [1, 2, 3, 4, 5]:
162 num1 = 5 # random by default
163 else:
164 num1 = 5 # random by default
165 #
166 num2 = input("Enter 1, 2, 3, 4 or 5 for +, -, X, /, random for 2nd process \n")
167 if num2.strip().isdigit():
168 num2 = int(num2)
169 if num2 not in [1, 2, 3, 4, 5]:
170 num2 = 5 # random by default
171 else:
172 num2 = 5 # random by default
173 #
174 else:
175 # use as placeholders for sake of call below; will end up returning + + dictionary but not used.
176 num1, num2 = None, None
177
178 numq = input(
179 "Enter the number of questions from 1 to 100; default to 2 pages worth \n"
180 )
181 if numq.strip().isdigit():
182 numq = int(numq)
183 if numq not in range(1, 101):
184 numq = num_for_type(bt_type)
185 else:
186 numq = num_for_type(bt_type)
187
188 match bt_type:
189 case 1:
190 tex_diagram_template_path = tex_diagram_standard_template_path
191 fileprefix = "bt2Bk"
192 q_parts_to_fill = tex_keys_q
193 case 2:
194 tex_diagram_template_path = tex_diagram_buildexp_template_path
195 fileprefix = "bt2Bk_build"
196 q_parts_to_fill = tex_keys_q
197 case 3:
198 tex_diagram_template_path = tex_diagram_invop_template_path
199 fileprefix = "bt2Bk_invop"
200 q_parts_to_fill = tex_keys_q
201 case 4:
202 tex_diagram_template_path = tex_diagram_fromexp_template_path
203 fileprefix = "bt2Bk_fromexp"
204 q_parts_to_fill = tex_keys_q_fromexp
205 case 5:
206 tex_diagram_template_path = tex_diagram_solvefromexp_template_path
207 fileprefix = "bt2Bk_solvefromexp"
208 q_parts_to_fill = tex_keys_q_solvefromexp
209 case 6:
210 tex_diagram_template_path = tex_diagram_blank_template_path
211 fileprefix = "bt2Bk_blank"
212 q_parts_to_fill = tex_keys_q
213
214 #
215 filename = input(
216 f"Enter the base filename to be added to the prefix {fileprefix}_: \n"
217 )
218 if not filename:
219 filename = "1" # "bt2Bk_1_q and bt2Bk_1_ans as default file"
220 #
221 # set names of files that are made
222 # questions
223 tex_output_path = currfile_dir / f"{fileprefix}_{filename}_q.tex"
224 aux_path = currfile_dir / "temp"
225 # answers
226 tex_output_path_ans = currfile_dir / f"{fileprefix}_{filename}_ans.tex"
227
228 # Read in the LaTeX template file
229 with open(tex_template_path, "r") as infile:
230 tex_template_txt = infile.read()
231 # Read in the LaTeX template file for answers
232 with open(texans_template_path, "r") as infile:
233 tex_template_txt_ans = infile.read()
234 # Read in the LaTeX diagram template file
235 with open(tex_diagram_template_path, "r") as infile:
236 tex_diagram_template_txt = infile.read()
237
238 # <<cols>>
239 # generate column text and column text for answers
240 col1_text = ""
241 col1_text_ans = ""
242 rmax = numq + 1
243 for _ in range(1, rmax):
244 img_tex, img_tex_ans = make1_diagram(
245 tex_diagram_template_txt, num1, num2, q_parts_to_fill
246 )
247 col1_text += img_tex
248 col1_text_ans += img_tex_ans
249
250 # Replace the <<cols>> placeholder in the LaTeX template with the generated diagrams
251 tex_template_txt = tex_template_txt.replace("<<cols>>", col1_text)
252 tex_template_txt_ans = tex_template_txt_ans.replace("<<cols>>", col1_text_ans)
253
254 # Write the question tex to an output file
255 with open(tex_output_path, "w") as outfile:
256 outfile.write(tex_template_txt)
257
258 # Write the answer tex to an output file
259 if bt_type in [1, 2, 3, 4, 5]:
260 with open(tex_output_path_ans, "w") as outfile:
261 outfile.write(tex_template_txt_ans)
262
263 # Wait for the file to be created
264 time.sleep(1)
265 # Convert the LaTeX files to PDFs
266 convert_to_pdf(tex_output_path, currfile_dir, aux_path)
267 if bt_type in [1, 2, 3, 4, 5]:
268 convert_to_pdf(tex_output_path_ans, currfile_dir, aux_path)
269
270
271if __name__ == "__main__":
272 print("starting")
273 main()
274 print("finished")