見出し画像

子ども用の計算ドリルを作る Python

子どもの自宅学習用に計算ドリルを購入しようと思ったが、作れそうなので作ってみた。結果、計算する子どもよりも勉強になったという話。

完成品

PDF形式で以下を選択して計算ドリルを生成する。毎回まったく異なる問題が作られるので永遠に計算できる。

・足し算、引き算、かけ算

・2桁、または3桁までの桁数

・ページ数 1~10ページ

最近はペンタブレットでPDFに直接書き込めるので、印刷の手間も減らせてとってもエコだと思う。

実際に生成される計算シートは次のようなもの。

また、子どもが自分でプリントを作成して取り組めるように以下の画像のようなツールとした。

ソースコード

以下のリンクよりページの体裁を整える方法を参考にさせていただいた。

https://qiita.com/nowicici/items/fd6c03471b22af2e0271

上記のページをベースに、3桁までの計算とGUIを実装した。

import os, sys
import random
import time
import datetime

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

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("culc_creator")
root.geometry('400x400')

fontname = "Helvetica"

# メッセージ文
message = tk.Label(root, text="どれかがちゃんとえらべていないぞ?")
message_cong = tk.Label(root, text="もんだいをつくったよ。がんばってね!")

## 2桁用の定義----
def Set_calc_2(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)

## 2桁用のpdf作成----
def Make_page_2(c,ope,d1_max,d2_max):
    c.setFont(fontname,20)
    c.drawString(5, 800, " name: __________  date: __ / __")
    c.setFont(fontname,30)
    x_list = [35,  145, 255, 365, 475]
    y_list = [730, 580, 430, 280, 130]
    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_2(c,col,row,"+ ",d1,d2)
        elif(ope=="-"):
            if(d1<d2):
                tmp=d1
                d1=d2
                d2=tmp
            Set_calc_2(c,col,row,"- ",d1,d2)
        elif(ope=="x"):
            Set_calc_2(c,col,row,"× ",d1,d2)
        else:
            print("[Error] Not support operation:",ope)
    c.showPage()

## 3桁用の定義-----
def Set_calc_3(c,x,y,ope,d1,d2):
    offset = 30
    _d1 = str(d1)
    _d2 = str(d2)
    if(10<=d1<100):
        _d1 = "  " + _d1
    if(10<=d2<100):
        _d2 = "  " + _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)

## 3桁用のpdf作成----
def Make_page_3(c,ope,d1_max,d2_max):
    c.setFont(fontname,20)
    c.drawString(5, 800, " name: __________  date: __ / __")
    c.setFont(fontname,30)

    x_list = [35,  182, 329, 475]
    y_list = [730, 552, 376, 200]
    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_3(c,col,row,"+ ",d1,d2)
        elif(ope=="-"):
            if(d1<d2):
                tmp=d1
                d1=d2
                d2=tmp
            Set_calc_3(c,col,row,"- ",d1,d2)
        elif(ope=="x"):
            Set_calc_3(c,col,row,"× ",d1,d2)
        else:
            print("[Error] Not support operation:",ope)
    c.showPage()
## 3桁用の定義終わり----

## 各種設定-----
def btn_click():
    dt_now = datetime.datetime.now()
    message.pack_forget()
    what_culc = combobox_culc.get()
    if what_culc == "たしざん":
        what_culc_symbol = '+'
    elif what_culc == "ひきざん":
        what_culc_symbol = '-'
    elif what_culc == "かけざん":
        what_culc_symbol = 'x'
    what_digit = combobox_digit.get()
    what_page = combobox_page.get()
    if not (what_culc=="たしざん" or what_culc=="ひきざん" or what_culc=="かけざん"):
        message.pack()
        pass
    elif not (what_digit=="2" or what_digit=="3"):
        message.pack()
        pass
    elif not (what_page=="1" or what_page=="2" or what_page=="3" or what_page=="4" or what_page=="5" or what_page=="6" or what_page=="7" or what_page=="8" or what_page=="9" or what_page=="10"):
        message.pack()
        pass        
    elif what_digit=="2":
        c = canvas.Canvas(dt_now.strftime('%Y%m%d%H%M%S')+"_"+what_culc+"_calc_train.pdf",pagesize=A4)
        for i in range(int(what_page)):
            Make_page_2(c, what_culc_symbol, 99, 99)
        c.save()
        message_cong.pack()
        exit()
    elif what_digit=="3":
        c = canvas.Canvas(dt_now.strftime('%Y%m%d%H%M%S')+"_"+what_culc+"_calc_train.pdf",pagesize=A4)
        for i in range(int(what_page)):
            Make_page_3(c, what_culc_symbol, 999, 999)
        c.save()
        message_cong.pack()
        exit()

style = ttk.Style()
style.theme_use("winnative")
style.configure("office.TCombobox", padding=5)

culc_label = tk.Label(root, text="なにざんをやりますか?")  #文字ラベル設定
digit_label = tk.Label(root, text="なんけたまでのけいさんをやりますか?")  #文字ラベル設定
page_label = tk.Label(root, text="なんページやりますか?")  #文字ラベル設定
button_label = tk.Label(root, text="えらびおわったらボタンをおしてね")  #文字ラベル設定

culc_module = ('', 'たしざん', 'ひきざん', 'かけざん')
digit_module = ('', 2, 3)
page_module = ('', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

v_culc = tk.StringVar()
v_digit = tk.StringVar()
v_page = tk.StringVar()

combobox_culc = ttk.Combobox(root, textvariable= v_culc, values=culc_module, style="office.TCombobox")
combobox_digit = ttk.Combobox(root, textvariable= v_digit, values=digit_module, style="office.TCombobox")
combobox_page = ttk.Combobox(root, textvariable= v_page, values=page_module, style="office.TCombobox")

button = tk.Button(root, text="OK", command=btn_click)

culc_label.pack()
combobox_culc.pack(pady=10)
digit_label.pack()
combobox_digit.pack(pady=10)
page_label.pack()
combobox_page.pack(pady=10)
button_label.pack()
button.pack()

root.mainloop()

この記事が気に入ったらサポートをしてみませんか?