生徒の努力を得点じゃなく、「音ゲー」のようなリザルト画面で評しました!

フランスの大学院で先生の仕事をしながら、生徒のためにいつも新たな教え方を探しています。僕はプログラミングのレッスンをしているので、課題として生徒は応用問題を解かなければいけません。

会社に仕事、学校の教育でも、先輩からもらった感謝が第一であるって僕は絶対に思います。今回は先生として、先輩になるからこそ、感謝の正しい伝え方を探しました。生徒の努力をちゃんと認めたら、自然に頑張ります。

生徒には得点を伝えなければならないけれど、応用問題がよくできたかどうかも伝えたい。でも結局、それは十分じゃないと思いました。最初は、応用問題に関して生徒の努力をはっきり感謝したい。そうしたら頑張らなかった生徒は悔しくてやる気になって、よく頑張った生徒はもっと頑張ります。

---

## 得点のかわりは、何？

勇気付けられる物を考えたら「音ゲー」、すなわちリズムゲームを思いだしました。一曲遊んだ後で、リザルト画面は文字スコアで評価を見せます。

あまりできなかったら「B」スコアになり、普通にクリアしたら「A」スコアがあって、もっと上手にできたら「S」スコアがあって、それに完璧だったら「SSS」スコアがあります。これなら評価はわかりやすいし、なら次回はもっと頑張りたい、と感じるようになります。

これを思い出したとたん、文字スコアの利用をすぐに決めました。

![chunithmresult.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/4264d078-25f5-7367-e326-2aaf316b288e.jpeg)
> 「チュウニズム」アケードゲームのリザルト画面（©SEGA)️

上の画像のように、文字スコアは一番大きいテキストですね。その他は、細かいことについてのデータが見れます。リザルト画面は基本的に明るくて、かっこよくて、そして前回からの伸びがわかります。

文字スコアだけじゃなく、応用問題についての細かい説明も表示するのがいいでしょう。例えばソースコードに関して評価をします。そして応用問題の目的がちゃんとできたかどうか、構文規則が悪いかどうか、バグが多いかどうかも表示します。

![maimairesult.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/59563687-852f-ab69-094f-30537ef7dcc6.jpeg)
> 「maimai」アケードゲームのリザルト画面（©SEGA)️

その上maimaiの画面では、画面下にプレイした時間と場所が見れます。それでは、応用問題の名前と日付も書きましょうか。

---

## リザルト画面のやり方

まずどこかのファイルに生徒の評価を書かなければなりません。簡単な記入のために、エクセルがいいと思いました。エクセルファイルは後でPythonで読みやすいし、そして余白イメージにデータを印刷するつもりです。

---

## テンプレートのイメージ

さて、印刷されられるイメージを作りましょう。いつも通り僕は[Affinity Designer](https://affinity.serif.com/ja-jp/designer/)を使いますが、別のソフトでも大丈夫です。

後でPythonでイメージにテキストを印刷するので、空欄が必要です。リズムゲームのような感じにしたいから、カラフルで読みやすいデザインにしました。このファイルは`template.png`という名前にしましょう。

![template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/1eb6be4d-2179-1530-1b0d-7a40dcfc8262.png)
> 例のために日本語に変えちゃった

テキストを印刷するために、空欄の座標を書いておきましょう。イメージ本体のサイズは2048px*1024pxで、応用問題の名前の空欄の座標は(1296,196)、日付の空欄の座標は(1298,902)、などなど。

そして、使用可能なすべての文字スコアは別のイメージでおいて置きましょう。

![letters.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/ccd55db9-0e0b-712d-8094-dc4a03882fe2.png)
> 文字スコアのイメージ

---

## エクセルファイルの用意

評価はあるエクセルファイルにまとめるつもりなので、準備しましょう。１行目には応用問題の名前、日付、レッスンの名前を書いておきます。以降、一行一人、生徒の評価を書いておきます。

![excel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/c584dddf-acef-8415-cdcd-9f2df8d06cda.png)
> エクセルファイルの例

Pythonを使うときのため、データがどこにあるかを覚えましょう。応用問題の名前は「B1」セル、日付は「D1」セル、レッスン名は「F1」セルです。そして3行目からは、生徒の評価です。一番目の生徒のランクは「C3」セル、構文規則ランクは「D3」セル、などなど。

このファイルは`notes.xslx`としましょう。

---

## Pythonで読んで印刷

テンプレートイメージとエクセルファイルが完成したら、Pythonで生徒の結果のイメージが印刷できます。

```printer.py
import os
import argparse

from PIL import Image, ImageDraw, ImageFont
from openpyxl import load_workbook

#色んなサイズのフォントの準備
font_bold_60 = ImageFont.truetype("MPLUS1p-Bold.ttf", 60)
font_bold_52 = ImageFont.truetype("MPLUS1p-Bold.ttf", 52)
font_bold_28 = ImageFont.truetype("MPLUS1p-Bold.ttf", 28)
font_medium_32 = ImageFont.truetype("MPLUS1p-Medium.ttf", 28)

#argparseのおかげで使いやすくなります
parser = argparse.ArgumentParser(description="ある応用問題の結果を印刷差し上げます。")
parser.add_argument("spreadsheet", help="表計算ファイルの名前")
args = parser.parse_args()

#ファイルを開く
excel = load_workbook(args.spreadsheet)
#一番目の表計算を使う
sheet = excel.active

#データを読んでおきます
exercice_name = sheet["B1"].value
exercice_date = sheet["D1"].value
exercice_lesson = sheet["F1"].value

#3行目から表計算を読んで、10列目まで
for row in sheet.iter_rows(min_row=3, max_col=10, values_only=True):
    #一つ行からデータを引き出す
    lastname, firstname, rank, syntax_rank, syntax_note, objective_rank, objective_note, quality_rank, quality_note, notes = row

    #ランクがない場合は多分、結果の打ち込みがまだ
    if rank is None:
        print(f"空きランク、スキップ...")
        continue

    print(f"--> {lastname} {firstname} ● ランク {rank}")

    #テンプレートのイメージを開く
    with Image.open("template.png") as im:
        draw = ImageDraw.Draw(im)

        # テキストの印刷
        draw.text((92, 80), f"{lastname}\n{firstname}", font=font_bold_52, fill=(0,0,0))
        #anchor="mm"の意味は、中央揃えで書く
        draw.text((1296, 196), exercice_name, font=font_bold_60, anchor="mm", fill=(255,255,255))
        draw.text((1298, 902), exercice_date.strftime("%d/%m/%Y"), font=font_bold_28, fill=(0,0,0))
        draw.text((1610, 902), exercice_lesson, font=font_bold_28, fill=(0,0,0))
        #ここからは複数行テキスト
        draw.multiline_text((500, 384), syntax_note or "", font=font_medium_32, anchor="lm", fill=(0,0,0))
        draw.multiline_text((500, 544), objective_note or "", font=font_medium_32, anchor="lm", fill=(0,0,0))
        draw.multiline_text((500, 704), quality_note or "", font=font_medium_32, anchor="lm", fill=(0,0,0))
        draw.multiline_text((280, 870), notes or "", font=font_medium_32, anchor="lm", fill=(255,255,255))

        #文字ランクのイメージのサイズが違っているので、
        #中央揃えのために、正しいx位置を書いておこう
        ranks_x_position = {
            "B": 1496,
            "A": 1466,
            "S": 1490,
            "SS": 1384,
            "SSS": 1278
        }

        #文字ランクのイメージの印刷
        with Image.open(f"rank_{rank}.png") as im_rank:
            im.paste(im_rank, (ranks_x_position[rank], 486), im_rank)

        #構文規則ランクのイメージの印刷
        with Image.open(f"rank_{syntax_rank}.png") as im_syntax_rank:
            im_syntax_rank.thumbnail((94, 94))
            im.paste(im_syntax_rank, (380 if syntax_rank != "A" else 375, 340), im_syntax_rank)

        #目的ランクのイメージの印刷
        with Image.open(f"rank_{objective_rank}.png") as im_objective_rank:
            im_objective_rank.thumbnail((94, 94))
            im.paste(im_objective_rank, (380 if objective_rank != "A" else 375, 500), im_objective_rank)

        #コード質のイメージの印刷
        with Image.open(f"rank_{quality_rank}.png") as im_quality_rank:
            im_quality_rank.thumbnail((94, 94))
            im.paste(im_quality_rank, (380 if quality_rank != "A" else 375, 660), im_quality_rank)

        #最後はイメージを保存する
        im.save(f"{firstname} {lastname} - {exercice_name}.png")
```

スクリプトを実行する前に、フォントのファイルをダウンロードしなきゃいけません。たとえばM+1フォントは[Google Fonts](https://fonts.google.com/specimen/M+PLUS+1)からみつけます。そして、スクリプトは`printer.py`で`notes.xlsx`のエクセルファイルを使いたかったら、ターミナルで実行のはこのようになります。

```bash
$ python printer.py notes.xlsx
```

数秒後、一生徒一枚のイメージが保存されます。

![守 田中 - 福岡地下鉄.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1564614/8ebc53c5-d592-9388-4ee5-73cb78100071.png)
> できたイメージはこういうものです。

---

## 生徒たちへの影響

多分、一番知りたいことでしょうか。基本的に、生徒が自分の能力をちゃんとわかるように、そして後でどうしたらいいかわかるようにするために、役に立ったと思います。

それなのに、次の応用問題を提出してもらったときに、たまに同じミスや悪いやり方を見つけました。その原因はいろいろだと思います。おそらく僕の説明が明らでなかったとか、締め切りの前に生徒が忙し過ぎたとか。だからこそ責任は生徒だけじゃなく、学校や先生にもあると思います。

とりあえず、結果の新しい伝え方がみつけられてうれしいです。せめて生徒が応用問題の結果をもっと気になって、次の応用問題に役立ててくれればうれしいです。

---

読んでいただきありがとうございます。このトピックで話したいなら、ツイッターは[@komanakun](https://twitter.com/komanakun)、Wantedlyは[こちら](https://www.wantedly.com/id/michaelhubert)、LinkedInプロフは[こちら](https://www.linkedin.com/in/michaelhubertme/)です。