5. Backtracking 1-step booklet python

The 2 custom python modules required are:
The Python to create a multi page booklet of 1-step backtracking booklets, with 10 backtracking diagrams per page, is below.
The python file, backtracking_1step_booklet_maker.py, when run, will ask for these inputs:
  • Choose the arithmetic process: "Enter 1, 2, 3, 4 or 5 for +, -, X, /, random".

  • Choose the number of questions form 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 bt1Bk_:". The filename will have β€œ_q” added for the question booklet and β€œ_ans” for the answer booklet.

The Python to create a multi page booklet of 1-step backtracking booklets, with 10 backtracking diagrams per page, is below.
  1from pathlib import Path
  2import subprocess
  3import os
  4import time
  5import backtracking_functions as btf
  6
  7currfile_dir = Path(__file__).parent
  8tex_template_path = currfile_dir / "backtrack_1step_booklet_template.tex"
  9texans_template_path = currfile_dir / "backtrack_1step_booklet_ans_template.tex"
 10tex_diagram_template_path = currfile_dir / "backtrack_1step_booklet_diagram_template.tex"
 11
 12
 13def merge_files(file1, file2, outputname):
 14    result = subprocess.run(["pdfunite", file1, file2, outputname])
 15
 16
 17def convert_to_pdf(tex_path, outputdir):
 18    tex_path = Path(tex_path).resolve()
 19    outputdir = Path(outputdir).resolve()
 20    # for testing
 21    # print(f"tex_path: {tex_path}")
 22    # print(f"outputdir: {outputdir}")
 23    try:
 24        # Generate the PDF
 25        subprocess.run(["latexmk", "-pdf", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 26        # # Clean auxiliary files after successful PDF generation
 27        subprocess.run(["latexmk", "-c", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 28        # for hosted remove stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL for debugging any errors
 29        # Remove the .tex file manually
 30        if tex_path.exists():
 31            os.remove(tex_path)
 32    except subprocess.CalledProcessError as e:
 33        print(f"Error: {e}")
 34
 35
 36# tex_keys = ['stepAB','stepABrev','boxA','boxB','boxBrev', 'boxArev' ]
 37tex_keys_q = ["stepAB", "boxA", "boxBrev"]
 38
 39
 40def make1_diagram(tex_diagram_template_txt, num):
 41    tex_diagram_template_txt_ans = tex_diagram_template_txt
 42    posttext = r"\vspace{-2pt}"
 43    kv = btf.get_1step_process_dict(num)
 44
 45    for key, value in kv.items():
 46        tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace("<<" + key + ">>", value)
 47
 48    for key, value in kv.items():
 49        if key in tex_keys_q:
 50            tex_diagram_template_txt = tex_diagram_template_txt.replace("<<" + key + ">>", value)
 51        else:
 52            tex_diagram_template_txt = tex_diagram_template_txt.replace("<<" + key + ">>", "")
 53
 54    # return tex_diagram_template_txt
 55    return tex_diagram_template_txt + posttext, tex_diagram_template_txt_ans + posttext
 56
 57
 58def main():
 59    num = input("Enter 1, 2, 3, 4 or 5 for +, -, X, /, random \n")
 60    if num.strip().isdigit():
 61        num = int(num)
 62        if not num in [1, 2, 3, 4, 5]:
 63            num = 5  # random by default
 64    else:
 65        num = 5  # random by default
 66    #
 67    numq = input("Enter the number of questions from 1 to 100 \n")
 68    if numq.strip().isdigit():
 69        numq = int(numq)
 70        if not numq in range(1, 101):
 71            numq = 20  # random by default
 72    else:
 73        numq = 20  # random by default
 74    #
 75    filename = input("Enter the base filename to be added to the prefix bt1Bk_: \n")
 76    if not filename:
 77        filename = "1"  # "bt1Bk_1st_q and bt1Bk_1st_ans as default file"
 78    # set names of files that are made
 79    # questions
 80    tex_output_path = currfile_dir / f"bt1Bk_{filename}_q.tex"
 81
 82    # answers
 83    tex_output_path_ans = currfile_dir / f"bt1Bk_{filename}_ans.tex"
 84
 85    # Read in the LaTeX template file
 86    with open(tex_template_path, "r") as infile:
 87        tex_template_txt = infile.read()
 88    # Read in the LaTeX template file for answers
 89    with open(texans_template_path, "r") as infile:
 90        tex_template_txt_ans = infile.read()
 91    # Read in the LaTeX diagram template file
 92    with open(tex_diagram_template_path, "r") as infile:
 93        tex_diagram_template_txt = infile.read()
 94
 95    # <<diagrams>>
 96    # generate column text and column text for answers
 97    diagram_text = ""
 98    diagram_text_ans = ""
 99    for _ in range(1, numq + 1):
100        img_tex, img_tex_ans = make1_diagram(tex_diagram_template_txt, num)
101        diagram_text += img_tex
102        diagram_text_ans += img_tex_ans
103
104    # Replace the <<diagrams>> placeholder in the LaTeX template with the generated diagrams
105    tex_template_txt = tex_template_txt.replace("<<diagrams>>", diagram_text)
106    tex_template_txt_ans = tex_template_txt_ans.replace("<<diagrams>>", diagram_text_ans)
107
108    # Write the question tex to an output file
109    with open(tex_output_path, "w") as outfile:
110        outfile.write(tex_template_txt)
111
112    # Write the answer tex to an output file
113    with open(tex_output_path_ans, "w") as outfile:
114        outfile.write(tex_template_txt_ans)
115
116    # Wait for the file to be created
117    time.sleep(1)
118    # Convert the LaTeX files to PDFs
119    convert_to_pdf(tex_output_path, currfile_dir)
120    convert_to_pdf(tex_output_path_ans, currfile_dir)
121
122
123if __name__ == "__main__":
124    print("starting")
125    main()
126    print("finished")
The custom Python module that is required to work out the various texts for the diagrams, is below.
It includes the module functions for 2 step backtracking as well.
  1"""
  2Module of functions to return diagram dictionary for LaTeX
  3"""
  4import random
  5
  6
  7def get_1step_process_dict(num):
  8    if num is None or num == 5:
  9        num = random.randint(1, 4)
 10    match num:
 11        case 1:
 12            return add_dict()
 13        case 2:
 14            return sub_dict()
 15        case 3:
 16            return times_dict()
 17        case 4:
 18            return div_dict()
 19
 20
 21def add_dict():
 22    # bb = nx + na
 23    nx = random.randint(1, 10)
 24    na = random.randint(1, 10)
 25    bb = nx + na
 26    mod_dict = dict()
 27    mod_dict["stepAB"] = f"+{na}"
 28    mod_dict["stepABrev"] = f"-{na}"
 29
 30    mod_dict["boxA"] = f"x"
 31    mod_dict["boxB"] = f"x+{na}"
 32    mod_dict["boxBrev"] = f"{bb}"
 33    mod_dict["boxArev"] = f"{nx}"
 34    return mod_dict
 35
 36
 37def sub_dict():
 38    # bb = nx - na
 39    na = random.randint(1, 10)
 40    nx = na + random.randint(1, 10)
 41    bb = nx - na
 42    mod_dict = dict()
 43    mod_dict["stepAB"] = f"-{na}"
 44    mod_dict["stepABrev"] = f"+{na}"
 45
 46    mod_dict["boxA"] = f"x"
 47    mod_dict["boxB"] = f"x-{na}"
 48    mod_dict["boxBrev"] = f"{bb}"
 49    mod_dict["boxArev"] = f"{nx}"
 50    return mod_dict
 51
 52
 53def times_dict():
 54    # bb = nx * na
 55    nx = random.randint(2, 10)
 56    na = random.randint(2, 10)
 57    bb = nx * na
 58    mod_dict = dict()
 59    mod_dict["stepAB"] = f"\\times{na}"
 60    mod_dict["stepABrev"] = f"\\div{na}"
 61
 62    mod_dict["boxA"] = f"x"
 63    mod_dict["boxB"] = f"{na}x"
 64    mod_dict["boxBrev"] = f"{bb}"
 65    mod_dict["boxArev"] = f"{nx}"
 66    return mod_dict
 67
 68
 69def div_dict():
 70    #  bb = nx / na; nx = na * bb
 71    # escape {} in f strings by doubling them up {{}}
 72    na = random.randint(2, 10)
 73    nx = na * random.randint(2, 10)
 74    bb = int(nx / na)
 75    mod_dict = dict()
 76    mod_dict["stepAB"] = f"\\div{na}"
 77    mod_dict["stepABrev"] = f"\\times{na}"
 78
 79    mod_dict["boxA"] = f"x"
 80    mod_dict["boxB"] = f"\\frac{{x}}{{{na}}}"
 81    mod_dict["boxBrev"] = f"{bb}"
 82    mod_dict["boxArev"] = f"{nx}"
 83    return mod_dict
 84
 85
 86
 87# ############################################
 88
 89def val_in_list_exclude(low, high, exclude):
 90    # random 2 step: avoid xx, x/, /x, //, ++, --, +-, -+
 91    vals = list(range(low, high + 1))
 92    if exclude in vals:
 93        if exclude in [1, 2]:
 94            vals.remove(1)
 95            vals.remove(2)
 96        elif exclude in [3, 4]:
 97            vals.remove(3)
 98            vals.remove(4)
 99    return random.choice(vals)
100
101
102def get_2step_process_dict(num1, num2):
103    if num1 is None or num1 == 5:
104        num1 = random.randint(1, 4)
105    if num2 is None or num2 == 5:
106        num2 = val_in_list_exclude(1, 4, num1)
107    processes = (num1, num2)
108    # processes = (3,3)
109    match processes:
110        case (1, 1):
111            return add_add_dict()
112        case (1, 2):
113            return add_sub_dict()
114        case (1, 3):
115            return add_times_dict()
116        case (1, 4):
117            return add_div_dict()
118        case (2, 1):
119            return sub_add_dict()
120        case (2, 2):
121            return sub_sub_dict()
122        case (2, 3):
123            return sub_times_dict()
124        case (2, 4):
125            return sub_div_dict()
126        case (3, 1):
127            return times_add_dict()
128        case (3, 2):
129            return times_sub_dict()
130        case (3, 3):
131            return times_times_dict()
132        case (3, 4):
133            return times_div_dict()
134        case (4, 1):
135            return div_add_dict()
136        case (4, 2):
137            return div_sub_dict()
138        case (4, 3):
139            return div_times_dict()
140        case (4, 4):
141            return div_div_dict()
142        case _:
143            return add_add_dict()
144
145
146def add_add_dict():
147    # bc = nx + na + nb
148    nx = random.randint(1, 10)
149    na = random.randint(1, 10)
150    nb = random.randint(1, 10)
151    bb = nx + na
152    bc = bb + nb
153
154    mod_dict = dict()
155    mod_dict["stepAB"] = f"+{na}"
156    mod_dict["stepABrev"] = f"-{na}"
157    mod_dict["stepBC"] = f"+{nb}"
158    mod_dict["stepBCrev"] = f"-{nb}"
159
160    mod_dict["boxA"] = f"x"
161    mod_dict["boxB"] = f"x+{na}"
162    mod_dict["boxC"] = f"x+{na + nb}"
163    mod_dict["boxCrev"] = f"{bc}"
164    mod_dict["boxBrev"] = f"{bb}"
165    mod_dict["boxArev"] = f"{nx}"
166    return mod_dict
167
168
169def add_sub_dict():
170    # bc = nx + na - nb
171    nx = random.randint(1, 10)
172    na = random.randint(1, 10)
173    bb = nx + na
174    if bb > 10:
175        nb = random.randint(1, 10)
176    else:
177        nb = random.randint(1, bb)
178    bc = bb - nb
179
180    mod_dict = dict()
181    mod_dict["stepAB"] = f"+{na}"
182    mod_dict["stepABrev"] = f"-{na}"
183    mod_dict["stepBC"] = f"-{nb}"
184    mod_dict["stepBCrev"] = f"+{nb}"
185
186    mod_dict["boxA"] = f"x"
187    mod_dict["boxB"] = f"x+{na}"
188    if na - nb > 0:
189        mod_dict["boxC"] = f"x+{na - nb}"
190    else:
191        mod_dict["boxC"] = f"x-{nb - na}"
192    mod_dict["boxCrev"] = f"{bc}"
193    mod_dict["boxBrev"] = f"{bb}"
194    mod_dict["boxArev"] = f"{nx}"
195    return mod_dict
196
197
198def add_times_dict():
199    # bc = nx * na * nb
200    nx = random.randint(1, 10)
201    na = random.randint(1, 10)
202    nb = random.randint(1, 10)
203    bb = nx + na
204    bc = bb * nb
205
206    mod_dict = dict()
207    mod_dict["stepAB"] = f"+{na}"
208    mod_dict["stepABrev"] = f"-{na}"
209    mod_dict["stepBC"] = f"\\times{nb}"
210    mod_dict["stepBCrev"] = f"\\div{nb}"
211
212    mod_dict["boxA"] = f"x"
213    mod_dict["boxB"] = f"x+{na}"
214    mod_dict["boxC"] = f"{nb}(x + {na})"
215    mod_dict["boxCrev"] = f"{bc}"
216    mod_dict["boxBrev"] = f"{bb}"
217    mod_dict["boxArev"] = f"{nx}"
218    return mod_dict
219
220
221def add_div_dict():
222    # bc = (nx + na) / nb
223    # nx = (bc * nb) - na
224    bc = random.randint(1, 10)
225    nb = random.randint(1, 10)
226    bb = bc * nb
227    if bb > 10:
228        na = random.randint(1, 10)
229    else:
230        na = random.randint(1, bb)
231    nx = bb - na
232
233    mod_dict = dict()
234    mod_dict["stepAB"] = f"+{na}"
235    mod_dict["stepABrev"] = f"-{na}"
236    mod_dict["stepBC"] = f"\\div{nb}"
237    mod_dict["stepBCrev"] = f"\\times{nb}"
238
239    mod_dict["boxA"] = f"x"
240    mod_dict["boxB"] = f"x+{na}"
241    mod_dict["boxC"] = f"\\frac{{(x+{na})}}{{{nb}}}"
242    mod_dict["boxCrev"] = f"{bc}"
243    mod_dict["boxBrev"] = f"{bb}"
244    mod_dict["boxArev"] = f"{nx}"
245    return mod_dict
246
247
248def sub_add_dict():
249    # bc = nx - na + nb
250    na = random.randint(1, 10)
251    nx = na + random.randint(1, 10)
252    nb = random.randint(1, 10)
253    bb = nx - na
254    bc = bb + nb
255
256    mod_dict = dict()
257    mod_dict["stepAB"] = f"-{na}"
258    mod_dict["stepABrev"] = f"+{na}"
259    mod_dict["stepBC"] = f"-{nb}"
260    mod_dict["stepBCrev"] = f"+{nb}"
261
262    mod_dict["boxA"] = f"x"
263    mod_dict["boxB"] = f"x-{na}"
264    mod_dict["boxC"] = f"x-{na + nb}"
265    mod_dict["boxCrev"] = f"{bc}"
266    mod_dict["boxBrev"] = f"{bb}"
267    mod_dict["boxArev"] = f"{nx}"
268    return mod_dict
269
270
271def sub_sub_dict():
272    # bc = nx - na - nb
273    # nx = bc + nb + na
274    bc = random.randint(1, 10)
275    na = random.randint(1, 10)
276    nb = random.randint(1, 10)
277    bb = bc + nb
278    nx = bb + na
279
280    mod_dict = dict()
281    mod_dict["stepAB"] = f"-{na}"
282    mod_dict["stepABrev"] = f"+{na}"
283    mod_dict["stepBC"] = f"-{nb}"
284    mod_dict["stepBCrev"] = f"+{nb}"
285
286    mod_dict["boxA"] = f"x"
287    mod_dict["boxB"] = f"x-{na}"
288    mod_dict["boxC"] = f"x-{na + nb}"
289    mod_dict["boxCrev"] = f"{bc}"
290    mod_dict["boxBrev"] = f"{bb}"
291    mod_dict["boxArev"] = f"{nx}"
292    return mod_dict
293
294
295def sub_times_dict():
296    # bc = (nx - na) * nb
297    # nx = (bc + nb) * na
298    na = random.randint(1, 10)
299    nx = na + random.randint(1, 10)
300    nb = random.randint(1, 10)
301    bb = nx - na
302    bc = bb * nb
303
304    mod_dict = dict()
305    mod_dict["stepAB"] = f"-{na}"
306    mod_dict["stepABrev"] = f"+{na}"
307    mod_dict["stepBC"] = f"\\times{nb}"
308    mod_dict["stepBCrev"] = f"\\div{nb}"
309
310    mod_dict["boxA"] = f"x"
311    mod_dict["boxB"] = f"x-{na}"
312    mod_dict["boxC"] = f"{nb}(x-{na})"
313    mod_dict["boxCrev"] = f"{bc}"
314    mod_dict["boxBrev"] = f"{bb}"
315    mod_dict["boxArev"] = f"{nx}"
316    return mod_dict
317
318
319def sub_div_dict():
320    # bc = nx - na / nb
321    # nx = (bc + nb) * na
322    bc = random.randint(1, 10)
323    na = random.randint(1, 10)
324    nb = random.randint(1, 10)
325    bb = bc * nb
326    nx = bb + na
327
328    mod_dict = dict()
329    mod_dict["stepAB"] = f"-{na}"
330    mod_dict["stepABrev"] = f"+{na}"
331    mod_dict["stepBC"] = f"\\div{nb}"
332    mod_dict["stepBCrev"] = f"\\times{nb}"
333
334    mod_dict["boxA"] = f"x"
335    mod_dict["boxB"] = f"x-{na}"
336    mod_dict["boxC"] = f"\\frac{{(x-{na})}}{{{nb}}}"
337    mod_dict["boxCrev"] = f"{bc}"
338    mod_dict["boxBrev"] = f"{bb}"
339    mod_dict["boxArev"] = f"{nx}"
340    return mod_dict
341
342
343def times_add_dict():
344    # bc = nx * na + nb
345    nx = random.randint(2, 10)
346    na = random.randint(2, 10)
347    nb = random.randint(2, 10)
348    bb = nx * na
349    bc = nx * na + nb
350
351    mod_dict = dict()
352    mod_dict["stepAB"] = f"\\times{na}"
353    mod_dict["stepABrev"] = f"\\div{na}"
354    mod_dict["stepBC"] = f"+{nb}"
355    mod_dict["stepBCrev"] = f"-{nb}"
356
357    mod_dict["boxA"] = f"x"
358    mod_dict["boxB"] = f"{na}x"
359    mod_dict["boxC"] = f"{na}x + {nb}"
360    mod_dict["boxCrev"] = f"{bc}"
361    mod_dict["boxBrev"] = f"{bb}"
362    mod_dict["boxArev"] = f"{nx}"
363    return mod_dict
364
365
366def times_sub_dict():
367    # bc = nx * na - nb
368    nx = random.randint(2, 10)
369    na = random.randint(2, 10)
370    bb = nx * na
371    if bb > 10:
372        nb = random.randint(2, 10)
373    else:
374        nb = random.randint(2, bb)
375    bc = bb - nb
376
377    mod_dict = dict()
378    mod_dict["stepAB"] = f"\\times{na}"
379    mod_dict["stepABrev"] = f"\\div{na}"
380    mod_dict["stepBC"] = f"-{nb}"
381    mod_dict["stepBCrev"] = f"+{nb}"
382
383    mod_dict["boxA"] = f"x"
384    mod_dict["boxB"] = f"{na}x"
385    mod_dict["boxC"] = f"{na}x - {nb}"
386    mod_dict["boxCrev"] = f"{bc}"
387    mod_dict["boxBrev"] = f"{bb}"
388    mod_dict["boxArev"] = f"{nx}"
389    return mod_dict
390
391
392def times_times_dict():
393    # bc = nx * na * nb
394    nx = random.randint(2, 10)
395    na = random.randint(2, 10)
396    nb = random.randint(2, 10)
397    bb = nx * na
398    bc = nx * na * nb
399
400    mod_dict = dict()
401    mod_dict["stepAB"] = f"\\times{na}"
402    mod_dict["stepABrev"] = f"\\div{na}"
403    mod_dict["stepBC"] = f"\\times{nb}"
404    mod_dict["stepBCrev"] = f"\\div{nb}"
405
406    mod_dict["boxA"] = f"x"
407    mod_dict["boxB"] = f"{na}x"
408    mod_dict["boxC"] = f"{na * nb}x"
409    mod_dict["boxCrev"] = f"{bc}"
410    mod_dict["boxBrev"] = f"{bb}"
411    mod_dict["boxArev"] = f"{nx}"
412    return mod_dict
413
414
415def times_div_dict():
416    # bc = nx * na / nb
417    nb = random.randint(2, 3)
418    na = nb * random.randint(2, 4)
419    nx = random.randint(2, 10)
420    bb = nx * na
421    bc = int(bb / nb)
422
423    mod_dict = dict()
424    mod_dict["stepAB"] = f"\\times{na}"
425    mod_dict["stepABrev"] = f"\\div{na}"
426    mod_dict["stepBC"] = f"\\div{nb}"
427    mod_dict["stepBCrev"] = f"\\times{nb}"
428
429    mod_dict["boxA"] = f"x"
430    mod_dict["boxB"] = f"{na}x"
431    mod_dict["boxC"] = f"{int(na / nb)}x"
432    mod_dict["boxCrev"] = f"{bc}"
433    mod_dict["boxBrev"] = f"{bb}"
434    mod_dict["boxArev"] = f"{nx}"
435    return mod_dict
436
437
438def div_add_dict():
439    # bc = (nx / na) + nb
440    # nx = (bc - nb) * na
441    na = random.randint(2, 10)
442    nx = na * random.randint(1, 10)
443    nb = random.randint(1, 10)
444    bb = int(nx / na)
445    bc = bb + nb
446
447    mod_dict = dict()
448    mod_dict["stepAB"] = f"\\div{na}"
449    mod_dict["stepABrev"] = f"\\times{na}"
450    mod_dict["stepBC"] = f"+{nb}"
451    mod_dict["stepBCrev"] = f"-{nb}"
452    mod_dict["boxA"] = f"x"
453    mod_dict["boxB"] = f"\\frac{{x}}{{{na}}}"
454    mod_dict["boxC"] = f"\\frac{{x}}{{{na}}} + {nb}"
455    mod_dict["boxCrev"] = f"{bc}"
456    mod_dict["boxBrev"] = f"{bb}"
457    mod_dict["boxArev"] = f"{nx}"
458    return mod_dict
459
460
461def div_sub_dict():
462    # bc = (nx / na) - nb
463    # nx = (bc + nb) * na
464    bc = random.randint(2, 10)
465    na = random.randint(2, 10)
466    nb = random.randint(2, 10)
467    bb = bc + nb
468    nx = bb * na
469
470    mod_dict = dict()
471    mod_dict["stepAB"] = f"\\div{na}"
472    mod_dict["stepABrev"] = f"\\times{na}"
473    mod_dict["stepBC"] = f"-{nb}"
474    mod_dict["stepBCrev"] = f"+{nb}"
475    mod_dict["boxA"] = f"x"
476    mod_dict["boxB"] = f"\\frac{{x}}{{{na}}}"
477    mod_dict["boxC"] = f"\\frac{{x}}{{{na}}} - {nb}"
478    mod_dict["boxCrev"] = f"{bc}"
479    mod_dict["boxBrev"] = f"{bb}"
480    mod_dict["boxArev"] = f"{nx}"
481    return mod_dict
482
483
484def div_times_dict():
485    # bc = (nx / na) * nb
486    na = random.randint(2, 10)
487    nx = na * random.randint(2, 10)
488    nb = random.randint(2, 10)
489    bb = int(nx / na)
490    bc = bb * nb
491
492    mod_dict = dict()
493    mod_dict["stepAB"] = f"\\div{na}"
494    mod_dict["stepABrev"] = f"\\times{na}"
495    mod_dict["stepBC"] = f"\\div{nb}"
496    mod_dict["stepBCrev"] = f"\\times{nb}"
497    mod_dict["boxA"] = f"x"
498    mod_dict["boxB"] = f"\\frac{{x}}{{{na}}}"
499    mod_dict["boxC"] = f"\\frac{{x}}{{{na * nb}}}"
500    mod_dict["boxCrev"] = f"{bc}"
501    mod_dict["boxBrev"] = f"{bb}"
502    mod_dict["boxArev"] = f"{nx}"
503    return mod_dict
504
505
506def div_div_dict():
507    # bc = (nx / na) / nb
508    # escape {} in f strings by doubling them up {{}}
509    bc = random.randint(2, 10)
510    na = random.randint(2, 10)
511    nb = random.randint(2, 10)
512    bb = bc * nb
513    nx = bb * na
514
515    mod_dict = dict()
516    mod_dict["stepAB"] = f"\\div{na}"
517    mod_dict["stepABrev"] = f"\\times{na}"
518    mod_dict["stepBC"] = f"\\div{nb}"
519    mod_dict["stepBCrev"] = f"\\times{nb}"
520    mod_dict["boxA"] = f"x"
521    mod_dict["boxB"] = f"\\frac{{x}}{{{na}}}"
522    mod_dict["boxC"] = f"\\frac{{x}}{{{na * nb}}}"
523    mod_dict["boxCrev"] = f"{bc}"
524    mod_dict["boxBrev"] = f"{bb}"
525    mod_dict["boxArev"] = f"{nx}"
526    return mod_dict