計算ドリルプリントを作る

# はじめに
小学校低学年向けの自習用プリントを作るために、計算ドリル生成プログラムを作りました。pythonでランダムに数式を作って、A4用紙サイズでpdf化します。作成したファイルを自宅かコンビニなどで印刷して、子供が自習してくれれば目的達成です。

### 環境
+ Ubuntu 18.04[Windows10上でWSL(Windows Subsystem for Linux)使用]
+ python3.6
 

## ReportLabのインストール

生成した計算式を印刷するために、pdf化用のライブラリ・ReportLabを使用します。

```console
$ sudo pip3 install ReportLab
```
ReportLabに関する詳細なドキュメントは下記です。
https://www.reportlab.com/docs/reportlab-userguide.pdf

## 出力イメージ
今回は2桁の足し算、引き算、掛け算をプリントに出力します。
![image002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532819/2e628eea-7ff7-4cf7-de06-86f1d1f0077f.png)

## pdf出力用関数 drawStringとlineの使い方
今回のプリント作成は主にdrawString()とline()の2つの関数を使って実現します。プログラム本体に入る前に、基本的な使い方だけまとめておきます。

```py

from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import A4

# Canvasを作成。ファイル名とサイズを指定
c = canvas.Canvas("calc_train.pdf",pagesize=A4)
# 出力座標を設定
x=0
y=0
# "hoge"という文字列を座標(0,0)に書き出し
c.drawString(x,y,"hoge")
# 直線を描画
c.line(x,y,x+10,y)
# pdf1ページを生成
c.showPage()
# ファイルを保存
c.save()
```
ReportLabの座標はページの"左下"が原点になっています。

## 計算ドリル自動生成プログラム
下記が、今回の目的であるReportLabを使った計算ドリル自動生成プログラムです。

```python
import os, sys
import random

from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import A4

# 5x5の計算式の基本座標
x_list = [20, 130,  240, 350, 460]
y_list = [730, 580, 430, 280, 130]
# フォントを指定することも可能です
fontname = "Helvetica"
# 日本語を出力させる場合、下記のように設定します。
# パスはご自身の環境を参照ください。
#pdfmetrics.registerFont(TTFont(fontname,"/mnt/c/Windows/Fonts/msgothic.ttc"))

# 計算式1個を指定した座標に出力する関数
# 想定している計算は各要素が2桁以下です。
def Set_calc(c,x,y,ope,d1,d2):
    # c: canvas
    # x, y : 座標
    # ope : 数学記号の文字列
    offset = 30
    _d1 = str(d1)
    _d2 = str(d2)
    # 文字幅の調整
    if(d1<10):
        _d1 = " " + _d1
    if(d2<10):
        _d2 = " " + _d2        
    c.drawString(x+offset, y,        _d1)
    c.drawString(x,        y-offset, ope)
    c.drawString(x+offset, y-offset, _d2)
    c.line(x,y-offset-5,x+offset*2.5,y-offset-5)

# 1ページ分の計算式を生成する関数
def Make_page(c,ope,d1_max,d2_max):
    # c: canvas
    # ope : 数学記号の文字列
    # d1_max, d2_max : 計算する値の最大値設定
    c.setFont(fontname,20)
    # ヘッダー部分の文字列出力
    c.drawString(5,800, " Name：　　Day：　/   ")
    c.setFont(fontname,30)

    # Set Value
    for row in y_list:
      for col in x_list:
        # 設定された最大値の中でランダムに要素を生成
        d1 = random.randint(1, d1_max)
        d2 = random.randint(1, d2_max)
        # 加算の場合
        if(ope=="+"):
            Set_calc(c,col,row,"+ ",d1,d2)
        # 減算の場合
        elif(ope=="-"):
            # 負の値は扱わない
            if(d1<d2):
                tmp=d1
                d1=d2
                d2=tmp
            Set_calc(c,col,row,"- ",d1,d2)
        # 乗算の場合
        elif(ope=="x"):
            Set_calc(c,col,row,"× ",d1,d2)
        else:
            print("[Error] Not support operation:",ope)
    c.showPage()

# 以下メイン関数
print(" >>> Start")
c = canvas.Canvas("calc_train.pdf",pagesize=A4)

# 足し算 （各要素の最大値：99）
Make_page(c,"+",99,99)
# 引き算 （要素の最大値：99と9）
Make_page(c,"-",99,9)
# 引き算 2 （各要素の最大値：99）
Make_page(c,"-",99,99)
# 掛け算 （要素の最大値：99と9）
Make_page(c,"x",99,9)
c.save()

print(" >>> Finish")

```

上記サンプルを実行すると、A4サイズ用紙に5x5個の計算式が出力されます。お子さんの学年に応じて計算範囲を修正、1枚当たりの計算式数を調整して使ってみてください。

![image003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532819/5396bcef-0229-6bf7-4bda-f0847ebd129c.png)


以上です。お疲れ様でした。