python と LaTeX で100マス計算プリント用texファイルを自動生成できるようにしてみた

小学生に100マス計算させたい!ネットに色々転がってるけど、かゆいところに手が届かない。細かく難度調整できるようにしつつ大量にプリント生成したい……

というわけで初心者ですが、プログラムの勉強がてら作ってみました。

無駄だらけのコードだと思いますが、生温かい目で見てください

?「Python からLaTeX経由してPDF生成するより、htmlベースで書いて直接PythonでPDF生成した方が早いじゃん。」

いやほんと、そうですよね。完成した後に気づきました。

環境

・Python: Google Colab
・LaTeX: Windowsに適当にインストール
Pythonは個人PCにも入れているのですが、Google Colabだとどこからでもアクセスできるので便利かなと思ってこちらにしました。
コードも files のところとかが多少Google Colab用になってますが、大体普通のpython と同じでよかったです。

工程

  1. LaTeXで基礎を作る

  2. Pythonで100マス計算のランダム生成および texファイルへの落とし込みができるようにする

とざっくりこんな感じです。

1. LaTeXで基礎を作る

LaTeXで作った基礎はこんな感じ。一ページで2問の100マス計算。解答も別ページに印刷します。
python に転写する作業がめんどくさいので極力シンプルに。


\documentclass[10pt,a4j]{jsarticle}
\usepackage{array}

\pagestyle{empty}
\setlength{\headheight}{0pt}
\setlength{\marginparwidth}{0pt}

\begin{document}
\underline{\Large 百マス計算 No.x}\\
\vspace{1\baselineskip}
\renewcommand{\arraystretch}{1.4}
\begin{center}
    \begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.3cm} wc{2.5cm}} \cline{1-11}
        + & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \cline{1-11}
        1 & & & & & & & & & & \\ \cline{1-11}
        2 & & & & & & & & & & & & \hfill 月~~~~~~~日 \\ \cline{1-11} \cline{13-13}
        3 & & & & & & & & & & \\ \cline{1-11}
        4 & & & & & & & & & & \\ \cline{1-11}
        5 & & & & & & & & & & \\ \cline{1-11}
        6 & & & & & & & & & & & & \hfill 分~~~~~~~秒 \\ \cline{1-11} \cline{13-13}
        7 & & & & & & & & & & \\ \cline{1-11}
        8 & & & & & & & & & & \\ \cline{1-11}
        9 & & & & & & & & & & \\ \cline{1-11}
        10 & & & & & & & & & & & & \hfill 点 \\ \cline{1-11} \cline{13-13}
    \end{tabular} \\
    \vspace{2.5\baselineskip}    
    \begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.3cm} wc{2.5cm}} \cline{1-11}
        + & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \cline{1-11}
        1 & & & & & & & & & & \\ \cline{1-11}
        2 & & & & & & & & & & \\ \cline{1-11}
        3 & & & & & & & & & & \\ \cline{1-11}
        4 & & & & & & & & & & \\ \cline{1-11}
        5 & & & & & & & & & & \\ \cline{1-11}
        6 & & & & & & & & & & & & \hfill 分~~~~~~~秒 \\ \cline{1-11} \cline{13-13}
        7 & & & & & & & & & & \\ \cline{1-11}
        8 & & & & & & & & & & \\ \cline{1-11}
        9 & & & & & & & & & & \\ \cline{1-11}
        10 & & & & & & & & & & & & \hfill 点 \\ \cline{1-11} \cline{13-13}
    \end{tabular} 
\end{center}
\newpage
\underline{\Large 百マス計算 No.x 解答}\\
\vspace{1\baselineskip}
\renewcommand{\arraystretch}{1.4}
\begin{center}
    \begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|} \hline
        + & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \hline
        1 & & & & & & & & & & \\ \hline
        2 & & & & & & & & & & \\ \hline
        3 & & & & & & & & & & \\ \hline
        4 & & & & & & & & & & \\ \hline
        5 & & & & & & & & & & \\ \hline
        6 & & & & & & & & & & \\ \hline
        7 & & & & & & & & & & \\ \hline
        8 & & & & & & & & & & \\ \hline
        9 & & & & & & & & & & \\ \hline
        10 & & & & & & & & & & \\ \hline
    \end{tabular} \\
    \vspace{2.5\baselineskip}
    \begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|} \hline
        + & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \hline
        1 & & & & & & & & & & \\ \hline
        2 & & & & & & & & & & \\ \hline
        3 & & & & & & & & & & \\ \hline
        4 & & & & & & & & & & \\ \hline
        5 & & & & & & & & & & \\ \hline
        6 & & & & & & & & & & \\ \hline
        7 & & & & & & & & & & \\ \hline
        8 & & & & & & & & & & \\ \hline
        9 & & & & & & & & & & \\ \hline
        10 & & & & & & & & & & \\ \hline
    \end{tabular} 
\end{center}
\newpage
\end{document}

2. Python に落とし込み

やっぱり思ったより時間かかっちゃいました。
個人的に学び/過去の知識を思い出すきっかけになったのは以下の3つでした
1. int と str が混ざったリストを一文にまとめるときは format関数を使う
2. copy は 浅いコピーと深いコピーを使い分ける
3. python は "\" の扱いがめんどくさいので、これを含む要素は直前にrを置いたりして対処する

完成

完成したプログラムは最後に置きます。
ポイントは
・難度調整を細かくできるようにしたこと(好きな数字の範囲で出題できる)
・プリントページ数を自由に変えられるようにしたこと
・プリントに自由にナンバーを振れるようにしたこと
あたりです。
桁数が大きくなっちゃうと枠の幅が足りなくなっちゃうけど、まぁそんなレベルまでつくらないからいいか。

ちょこちょこっと学んだ過去の知識を掘り起こしながら作成できて結構楽しかったです。
以上、備忘録まで。

! rm "/content/mas.tex"

import random
import copy
from google.colab import files

# ----- control ------

num_page = 15
start_No = 26
mylist = list(range(1,11)) # range(a,b): a 以上 b 未満の範囲の数字で100マス計算を生成。ここで難度調整する。

# ----- def ------

texbase = [
    r'\documentclass[10pt,a4j]{jsarticle}',                                               #0
    r'\usepackage{array}',                                                                #1
    r'\pagestyle{empty}',                                                                 #2
    r'\setlength{\headheight}{0pt}',                                                      #3
    r'\setlength{\marginparwidth}{0pt}',                                                  #4
    r'\begin{document}',                                                                  #5
    r'\renewcommand{\arraystretch}{1.4}',                                                 #6
    r'\underline{\Large 百マス計算 No.x}\\',                                             #7
    r'\vspace{1\baselineskip}',                                                           #8
    r'\begin{center}',                                                                    #9
    r'\begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.3cm} wc{2.5cm}} \cline{1-11}',  #10
    r'+ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \cline{1-11}',                        #11
    r'1 & & & & & & & & & & \\ \cline{1-11}',                                             #12
    r'2 & & & & & & & & & & & & \hfill 月~~~~~~~日 \\ \cline{1-11} \cline{13-13}',        #13
    r'3 & & & & & & & & & & \\ \cline{1-11}',                                             #14
    r'4 & & & & & & & & & & \\ \cline{1-11}',                                             #15
    r'5 & & & & & & & & & & \\ \cline{1-11}',                                             #16
    r'6 & & & & & & & & & & & & \hfill 分~~~~~~~秒 \\ \cline{1-11} \cline{13-13}',        #17
    r'7 & & & & & & & & & & \\ \cline{1-11}',                                             #18
    r'8 & & & & & & & & & & \\ \cline{1-11}',                                             #19
    r'9 & & & & & & & & & & \\ \cline{1-11}',                                             #20
    r'10 & & & & & & & & & & & & \hfill 点 \\ \cline{1-11} \cline{13-13}',                #21
    r'\end{tabular} \\',                                                                  #22
    r'\vspace{2.5\baselineskip}',                                                         #23
    r'\begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.3cm} wc{2.5cm}} \cline{1-11}',   #24
    r'+ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \cline{1-11}',                        #25
    r'1 & & & & & & & & & & \\ \cline{1-11}',                                             #26
    r'2 & & & & & & & & & & \\ \cline{1-11}',                                             #27
    r'3 & & & & & & & & & & \\ \cline{1-11}',                                             #28
    r'4 & & & & & & & & & & \\ \cline{1-11}',                                             #29
    r'5 & & & & & & & & & & \\ \cline{1-11}',                                             #30
    r'6 & & & & & & & & & & & & \hfill 分~~~~~~~秒 \\ \cline{1-11} \cline{13-13}',        #31
    r'7 & & & & & & & & & & \\ \cline{1-11}',                                             #32
    r'8 & & & & & & & & & & \\ \cline{1-11}',                                             #33
    r'9 & & & & & & & & & & \\ \cline{1-11}',                                             #34
    r'10 & & & & & & & & & & & & \hfill 点 \\ \cline{1-11} \cline{13-13}',                #35
    r'\end{tabular} ',                                                                    #36
    r'\end{center}',                                                                      #37
    r'\newpage',                                                                          #38
    r'\underline{\Large 百マス計算 No.x 解答}\\',                                       #39
    r'\vspace{1\baselineskip}',                                                           #40
    r'\begin{center}',                                                                    #41
    r'\begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|} \hline', #42
    r'+ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \hline',                              #43
    r'1 & & & & & & & & & & \\ \hline',                                                   #44
    r'2 & & & & & & & & & & \\ \hline',                                                   #45
    r'3 & & & & & & & & & & \\ \hline',                                                   #46
    r'4 & & & & & & & & & & \\ \hline',                                                   #47
    r'5 & & & & & & & & & & \\ \hline',                                                   #48
    r'6 & & & & & & & & & & \\ \hline',                                                   #49
    r'7 & & & & & & & & & & \\ \hline',                                                   #50
    r'8 & & & & & & & & & & \\ \hline',                                                   #51
    r'9 & & & & & & & & & & \\ \hline',                                                   #52
    r'10 & & & & & & & & & & \\ \hline',                                                  #53
    r'\end{tabular} \\',                                                                  #54
    r'\vspace{2.5\baselineskip}',                                                         #55
    r'\begin{tabular}{|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|wc{0.6cm}|} \hline',                                      #56
    r'+ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \\ \hline',                              #57
    r'1 & & & & & & & & & & \\ \hline',                                                   #58
    r'2 & & & & & & & & & & \\ \hline',                                                   #59
    r'3 & & & & & & & & & & \\ \hline',                                                   #60
    r'4 & & & & & & & & & & \\ \hline',                                                   #61
    r'5 & & & & & & & & & & \\ \hline',                                                   #62
    r'6 & & & & & & & & & & \\ \hline',                                                   #63
    r'7 & & & & & & & & & & \\ \hline',                                                   #64
    r'8 & & & & & & & & & & \\ \hline',                                                   #65
    r'9 & & & & & & & & & & \\ \hline',                                                   #66
    r'10 & & & & & & & & & & \\ \hline',                                                  #67
    r'\end{tabular}',                                                                     #68
    r'\end{center}',                                                                      #69
    r'\newpage',                                                                          #70
    r'\end{document}',                                                                    #71
]

def mas_gen(l):
  # 10個の数字を入れたリストを突っ込むとQ, Aの二つのリストをくっつけた形でreturnする
    tate = random.sample(l,10)
    yoko = random.sample(l,10)
    masQ = []
    masQ.append(yoko)
    masQ[0].insert(0,'+')
    for i in range(10):
      masQ.append([tate[i],'','','','','','','','','',''])
    masA = []
    masA.append(yoko)
    for i in range(10):
      add = [tate[i]]
      for j in range(1,11):
        add.append(tate[i]+yoko[j])
      masA.append(add)
    return masQ, masA

def array_trans_Q1(l):
  a = []
  for i in range(len(l)):
    tmp = l[i][0]
    for j in range(1,len(l[i])):
      tmp = '{} & {}'.format(tmp, l[i][j])
    if i == 2:
      tmp = '{}{}'.format(tmp,r' & & \hfill 月~~~~~~~日 \\ \cline{1-11} \cline{13-13}')
      a.append(tmp)
    elif i == 6:
      tmp = '{}{}'.format(tmp,r' & & \hfill 分~~~~~~~秒 \\ \cline{1-11} \cline{13-13}')
      a.append(tmp)
    elif i == 10:
      tmp = '{}{}'.format(tmp,r' & & \hfill 点 \\ \cline{1-11} \cline{13-13}')
      a.append(tmp)
    else:
      tmp = '{}{}'.format(tmp,r' \\ \cline{1-11}')
      a.append(tmp)
  return a

def array_trans_Q2(l):
  a = []
  for i in range(len(l)):
    tmp = l[i][0]
    for j in range(1,len(l[i])):
      tmp = '{} & {}'.format(tmp, l[i][j])
    if i == 6:
      tmp = '{}{}'.format(tmp,r' & & \hfill 分~~~~~~~秒 \\ \cline{1-11} \cline{13-13}')
      a.append(tmp)
    elif i == 10:
      tmp = '{}{}'.format(tmp,r' & & \hfill 点 \\ \cline{1-11} \cline{13-13}')
      a.append(tmp)
    else:
      tmp = '{}{}'.format(tmp,r' \\ \cline{1-11}')
      a.append(tmp)
  return a

def array_trans_A(l):
  a = []
  for i in range(len(l)):
    tmp = l[i][0]
    for j in range(1,len(l[i])):
      tmp = '{} & {}'.format(tmp, l[i][j])
    tmp = '{}{}'.format(tmp,r' \\ \hline')
    a.append(tmp)
  return a

def mas_prepare(n):
  page = []
  for i in range(n):
    N1 = []
    N2 = []
    mas1 = mas_gen(mylist)
    Q1 = array_trans_Q1(mas1[0])
    A1 = array_trans_A(mas1[1])
    N1.append(Q1), N1.append(A1)
    mas2 = mas_gen(mylist)
    Q2 = array_trans_Q2(mas2[0])
    A2 = array_trans_A(mas2[1])
    N2.append(Q2), N2.append(A2)
    page.append(N1), page.append(N2)
  return page

def page_translator(l_page):
  tex_writer= copy.deepcopy(texbase)
  del tex_writer[7:71]
  for i in range(len(l_page)//2):
    tex_content = copy.deepcopy(texbase)
    tex_content[7] = '{}{}{}'.format(r'\underline{\Large 百マス計算 No.', start_No + i ,r'}\\')
    tex_content[39] = '{}{}{}'.format(r'\underline{\Large 百マス計算 No.', start_No + i ,r' 解答}\\')
    for j in range(11,22):
      tex_content[j] = l_page[i][0][j-11]
    for k in range(25,36):
      tex_content[k] = l_page[i+1][0][k-25]
    for m in range(43,54):
      tex_content[m] = l_page[i][1][m-43]
    for n in range(57,68):
      tex_content[n] = l_page[i+1][1][n-57]
    #
    tmp = copy.deepcopy(tex_content[7:71])
    for o in range(len(tmp)):
      tex_writer.insert(-1,tmp[o])
  return tex_writer

# ----- main ------

test = mas_prepare(num_page)
filecontent = page_translator(test)

cont = filecontent[0]
for i in range(1,len(filecontent)):
  cont = '{}\n{}'.format(cont,filecontent[i])

with open('mas.tex','w') as x:
  print(cont,file=x)
files.download('mas.tex')

いいなと思ったら応援しよう!