タートルグラフィックスで学ぶ Python のキホン 第 26 章
教材コード
第26章

じゆうに書く

白紙のエディタです.思いついたことを,そのまま試してください.

教材のページは,どれも「読んでから試す」順番になっています. このページは逆です.先に書いて,動かしてみるための場所です. 習ったことを試すのにも,課題を書くのにも, ただ落書きするのにも使ってかまいません.

下のボタンから右側にひな形を読み込み,好きなように書き換えて 「▶ 実行」(Ctrl + Enter)を押してください.

このページの使い方
  • 書いた内容はブラウザが覚えています.ページを閉じても消えません.
  • まっさらに戻したいときは「↺ 最初から」を押します.
  • できたものは「⤓ 保存」で .py ファイルとして手元に保存できます.作品として残すときは,このファイルを保存しておきます.
  • 動き続けるプログラム(ontimer を使ったもの)は「■ 停止」で止めます.
  • 命令の名前を忘れたら,タートル命令リファレンスを見てください.

白紙のひな形

いちばん短い,何も入っていないプログラムです.ここから始めてください.

mynote.py
from turtle import *

done()
ヒント 1 行目の from turtle import * は「タートルの道具箱を開ける」合図, 最後の done() は「おしまい」の合図です. この 2 行のあいだに書いていきます.

困ったときは — 書き出しのテンプレート

「何から書けばいいかわからない」ときは,作りたいものに近いひな形を開いて, 中身を書き換えるのがいちばん速い方法です.4 つ用意しました.

作りたいもの使うひな形おもに使う章
絵や模様を描く① 図形を描く第 2・5・6・7 章
ものを動かす② アニメーション第 10・11 章
遊べるものを作る③ ゲーム第 12 章
数を入力して使う④ 入力を使う第 3・9 章
draw_template.py
# 題名:
# 名前:
# 日付:

from turtle import *

pensize(3)
pencolor("navy")

# ここから描く
for i in range(6):
    fd(90)
    rt(60)

ht()
done()
図 1 ① のひな形を実行したところ.range の数と角度を変えてみてください.
anim_template.py
# 題名:
# 名前:
# 日付:

from turtle import *

setup(620, 460)

# --- 準備(1 回だけ) ---
t = Turtle()
t.shape("turtle")
t.color("seagreen")
t.pu()
t.goto(-280, 0)

# --- 1 コマぶんの処理 ---
def tick():
    t.fd(5)
    if t.xcor() > 290:
        t.goto(-280, t.ycor())
    ontimer(tick, 30)      # ← 次のコマを予約する

ontimer(tick, 30)          # ← 最初の 1 回

done()
ヒント ブラウザでは while True: で動かし続けることができません. 動くものを作るときは,かならず ontimer を使ってください (第 10 章・第 12 章).
game_template.py
# 作品名:
# 名前:
# 日付:
# 遊び方:

from turtle import *
import random

setup(620, 460)
bgcolor("#0d1117")

# --- 1. 準備 ---------------------------------------------------
player = Turtle()
player.shape("triangle")
player.color("cyan")
player.pu()
player.goto(0, -170)

board = Turtle()
board.ht()
board.pu()
board.color("white")
board.goto(-290, 190)

score = 0
playing = True

def show_score():
    board.clear()
    board.write("スコア " + str(score), font=("Arial", 18, "normal"))

# --- 2. 操作 ---------------------------------------------------
def go_left():
    if playing:
        player.setx(max(-290, player.xcor() - 20))

def go_right():
    if playing:
        player.setx(min(290, player.xcor() + 20))

# --- 3. 毎フレームの処理 ---------------------------------------
def tick():
    global score, playing

    # ここに「動かす」「当たり判定」を書く

    show_score()

    # ここに「終わりの条件」を書く

    ontimer(tick, 30)

show_score()
onkeypress(go_left, "Left")
onkeypress(go_right, "Right")
listen()
ontimer(tick, 30)

done()
ヒント キーが効かないときは,一度タートル画面をクリックしてください. コード欄に文字カーソルがあると,キーはコード欄に取られます.
input_template.py
# 題名:
# 名前:
# 日付:

from turtle import *

name = input("名前を入れてください:")
n = int(input("何角形にしますか:"))

print("こんにちは," + name + " さん")
print(str(n) + " 角形を描きます")

pensize(3)
pencolor("darkorange")

for i in range(n):
    fd(240 / n)
    rt(360 / n)

ht()
done()
ヒント input() を使うプログラムは,右下の コンソールの入力行にあらかじめ答えを 1 行ずつ書いておくか, そこを空にしたまま実行して,出てくる窓に打ち込みます. このひな形には ひろしま と 6 が入れてあります. 書き換えて試してください. input() が返すのは文字なので, 計算に使うときは int() で数に直します.

よく使う命令の早見

くわしくはタートル命令リファレンスにあります. ここには,書き出すときによく使うものだけを並べます.

やりたいこと書き方
進む・下がるfd(100) bk(50)
曲がるlt(90) rt(45)
線を引かずに動くpu() → goto(x, y) → pd()
色と太さpencolor("red") pensize(3)
塗りつぶすbegin_fill() … end_fill()
同じことを繰り返すfor i in range(6):
条件で分けるif x > 100:
まとまりに名前を付けるdef kaku():
かめを増やすt = Turtle()
文字を書くwrite("文字", font=("Arial", 18, "normal"))
動かし続けるontimer(tick, 30)
キーを受けるonkeypress(go, "Left") + listen()
当たり判定if t.distance(u) < 30:
でたらめな数import random + random.randint(1, 6)
かめを消すht()

うまくいかないときは

  • コンソールを見る.エラーには行番号と種類が出ます.まずそこを読んでください.
  • 全角に注意.() , や全角スペースは使えません.SyntaxError: invalid character と出たらこれです.
  • 1 行目を確かめる.NameError: name 'fd' is not defined は,from turtle import * の書き忘れです.
  • 少しずつ書く.2〜3 行書いては実行する人のほうが,結果的に速く進みます.
  • 最後に足した行を消す.そこまでは動いていたはずです.
  • 速さを落とす.「とてもゆっくり」にすると,かめがどこで思わぬ方へ曲がったかが目で追えます.
ヒント 自由に試すページです.授業での採点や提出は先生の指示に従ってください. 壊れても,消しても,何を書いてもかまいません. 失敗できる場所があることが,上達のいちばんの近道です.

総合作品を作る:企画から提出まで

このページは白紙のエディタとしても使えます.授業の自由制作では,以下の手順で作品を育ててください.題材は自由ですが,提出するには次の最低条件をすべて満たします.提出の方法や締め切りは先生の指示に従い,確認した操作と残った課題を記録します.

提出の最低条件

  1. 第23・24章のクラス(または第21章の辞書と関数)で図形などのデータを持ち,追加・取り消しなど状態を変える操作が2つ以上ある
  2. 作品データを version を含むJSONで保存し,読み込んだデータを検査してから復元できる(第25章)
  3. 空・上限などの境界を含む assert を3件以上残し,最初から実行し直しても通る(第22章)
  4. 冒頭のコメントに,目的の1文・操作方法・対応する範囲と制限を書いている(制作26-15の項目)
評価の目安4つすべてを満たして正しく動けば8,発展の工夫を1つ以上加えれば9,学習した範囲を大きく超える作り込みなら10が目安です.条件が1〜2つ足りなければ7です.題材の派手さやコードの長さでは評価しません.

制作26-1 誰が,何をする作品かを決める

自由制作は,何でもよいと言われるほど,最初の一歩を決めにくくなることがあります.

まず「誰が,何をして,どんな結果を得るか」を1文で書きます.例えば「利用者が画面をクリックして,色の付いた点を並べた作品を作る」です.

この1文が,機能を選ぶ基準になります.題名だけでは,何ができたら完成か判断できません.

自分が使う作品でも,初めて見る人を想定して説明してみましょう.

操作を知らない人が何を押すか,結果を見て成功したと分かるかを考えます.複雑な機能がなくても,目的が分かり,操作の結果が見える作品は伝わりやすくなります.

題材の派手さと,プログラムの設計の良さは別です.

このガイドでは,クリックで点を置く小さな作品を共通例にします.

同じものを作ることが必須ではありません.模様,簡単なゲーム,データの可視化など,自分の題材へ各段階の考え方を適用してください.

重要なのは,一度に完成形を書こうとせず,確かめられる小さな段階へ分けることです.

制作ノートには,目的の1文,想定する操作,完成したときの画面を残します.

絵が苦手なら,文字で位置と表示内容を書くだけでも構いません.あとで機能を追加したくなったら,最初の目的を支えるものか,別の作品に分けたほうがよいものかを判断できます.

制作自分の作品へ適用する

自分の作品について,利用者,操作,結果を1文で書き,画面に必要な要素を3つ以内で挙げてください.コード欄のコメントを企画メモとして使い,最初に見せたい結果をprintで表示します.

制作26-2 必須の機能と,後から足す機能

作りたい機能をすべて最初から入れると,どこまでできれば完成か分からなくなります.

目的を満たすために欠かせない機能と,できたら追加したい機能を分けましょう.点を置く作品なら,クリックした位置に点が出ることが最小の必須機能です.

色の切り替え,取り消し,保存は,その動作を確かめてから追加できます.

必須機能は,観察できる条件で書きます.

「使いやすい」だけでは確認できないので,「画面に操作方法が表示される」「最後の点を1回のキー操作で消せる」などへ具体化します.機能の数を増やすより,確認できる完成条件をそろえることが,制作を進める助けになります.

追加機能を保留することは,諦めることではありません.

最小の動作が安定すると,後から何を変えたか比較しやすくなります.最初から保存も描画も入力も同時に書くと,動かなかったときに原因が広がります.

依存する機能を順番に作る計画にします.

制作時間には,実装だけでなく,検証と説明を含めます.

終了直前まで新機能を追加していると,入力の端や失敗時の動作を確認できません.前半で必須機能,次に検証,余裕があれば追加機能,最後に提出物の確認という順を意識してください.

授業の時間に合わせて,作る範囲を調整します.

制作自分の作品へ適用する

必須機能を2つ,追加機能を2つ書いてください.各必須機能について,どの操作をすると何が起きれば成功かも記します.追加機能がなくても作品の目的を説明できるか確かめます.

制作26-3 まず,操作なしの1枚を作る

入力へ反応する作品でも,最初は決められた位置に図形を1個描くところから始めます.

この段階なら,入力イベントや状態管理を考えず,座標,大きさ,色,画面内の配置を確かめられます.見せたいものが正しく描けることを確認してから,位置を入力で変えるようにします.

完成例をすべて写すより,数行の小さい動作を自分で作るほうが,どの値が何に影響するかを追いやすくなります.

点の大きさを変えたらどこが変わるか,位置を変えたらどの命令を直すかを説明してください.必要な命令を忘れたら,早見表で調べて小さく試します.

この段階のコードを保存しておくと,後で動かなくなったときの比較対象になります.

長い作品のどこかが壊れた場合でも,最小の描画が動くかを確認すれば,環境の問題と自分が加えた処理の問題を分けられます.動く地点を残しながら進むことが,制作中の安心材料になります.

以下のひな形は,原点に青い点を描きます.

自分の作品の最小要素へ置き換えてください.ゲームならプレイヤー1体,可視化なら棒1本,模様なら単位となる図形1個です.

複数個を描く仕組みを追加する前に,1個の形と位置を確かめます.

制作自分の作品へ適用する

自分の作品を構成する最小の図形を1個だけ描いてください.位置,大きさ,色の値を1か所ずつ変更し,結果を説明します.複数個の配置や操作は,この段階ではまだ加えません.

制作26-4 変化する値を,データとして外へ出す

描画ができたら,変化させたい位置,大きさ,色をデータへまとめます.

描画命令の中へ数値を何度も直接書くと,後から入力へ対応させる際に変更箇所が増えます.1個の図形を辞書へまとめ,描画側はその値を使う形にすると,操作による状態の変化を表しやすくなります.

どの値を保存するかは,作品の意味に合わせます.

点の作品ならx,y,size,colorで足りるかもしれません.選択する機能を入れるならIDも必要かもしれません.

画面へ文字を出すためだけの一時的な文字列を,状態として二重に保存する必要があるかは考えてください.元の値から作り直せるものは,必要なときに求める方法もあります.

データの形を決めたら,キーの名前と意味を説明します.

sizeが直径なのか半径なのか,xとyが中心なのか左下なのかを明記してください.同じ数値を別の描画命令へ渡すとき,意味が違うと大きさや位置が変わります.

データの約束は,後で保存やクラスへ進める際の基礎になります.

ひな形では,点の中心と直径を辞書で表します.

ここへ2個目の辞書を加えると,作品の一覧へ進めます.まず1個の辞書の値だけを変更し,描画の手順を変えずに見た目が変わることを確認してください.

データと描画を分ける効果を,具体的な変更で確かめます.

制作自分の作品へ適用する

shapeの辞書を使って点を描いてください.sizeは直径,xとyは中心とする約束です.辞書の色と位置だけを変え,描画命令の部分を書き換えずに別の配置を作ります.

制作26-5 複数の図形は,一覧として管理する

図形を増やす段階では,1個ずつ別の変数を追加するより,図形データのリストを作ります.

描画はforで順に行い,図形が何個あっても同じ手順を使います.作品の数が増えるたびに描画コードをコピーする設計では,色の扱いや修正箇所が散らばりやすくなります.

データの数と,処理のコード量を分けて考えます.

リストの順番は描画順を表します.

重なっている図形では,後に描くものが上へ見える場合があります.同じ位置の図形を勝手に重複除去すると,作品の意味が変わるかもしれません.

リストを選んだ理由を,順序と重複の扱いから説明してください.

追加・削除をした後にも,空の作品を表示できるようにします.

forは空なら何もしないので,必ず1個目を取り出すコードより自然に扱えることがあります.作品の開始時と,すべて消した後は,空の一覧という同じ状態で表せます.

特別な状態を必要以上に増やさない設計を考えます.

以下のひな形は2個の点を持ちます.

まず3個目を加え,次に順番を変えて見た目を比較してください.座標や色を変えず,順番だけの変更による違いを観察します.

その後,空リストでもエラーにならないことを確かめて,入力による追加へ進みます.

制作自分の作品へ適用する

shapesへ3個目の点を追加し,描画のfor文は変更せずに表示してください.同じ位置へ色の違う点を重ね,順序を変えた効果を説明します.空の場合も試します.

制作26-6 同じ手順を,名前の付いた関数へ分ける

追加や削除のたびに画面を描き直すなら,再描画を関数へまとめると使いやすくなります.

その関数が何を受け取り,どの画面を変更し,何を返すかを決めます.描画用の関数は画面への作用を持ちますが,面積や範囲を求める関数は値だけを返すようにすると,テストの方法を分けられます.

関数へ分ける基準は,行数を均等にすることではありません.

同じ目的の処理がまとまっているか,別の場面から使いたい操作かを考えます.例えばdraw_allは一覧を描く,create_shapeは正しい形の辞書を作る,という分け方なら,名前から責任が分かります.

処理1,処理2という名前では,中身を開かないと用途が伝わりません.

引数を使うと,関数の外の変数名へ依存しすぎずに済みます.

shapesを直接読む関数と,itemsを引数で受け取る関数では,再利用できる範囲が違います.ただし,最初からすべてを一般化する必要はありません.

作品の中で変更しそうな部分から,入出力を明確にします.

以下は,描く役割を関数へ分けたひな形です.

渡したリストの順に点を描きます.次の課題では,位置を移動した新しいデータを作る関数を別に加えてください.

描画の関数へ移動の計算まで詰め込まず,計算結果を渡す構成にします.

制作自分の作品へ適用する

draw_allはそのまま使い,右へ50移動したデータを作ってから渡してください.元のデータが変わらないことを確かめ,計算と描画を分ける利点を説明します.

制作26-7 入力を追加し,1回の操作を確かめる

静止した作品ができたら,クリックやキーへ反応する処理を加えます.

最初は1種類の入力だけにし,その入力が届いたことをprintで確認します.描画,データの追加,得点の計算を同時に加える前に,イベントの座標やキー名を正しく受け取れるかを確かめましょう.

クリックしたときに点を描くだけなら,コールバックでgotoとdotを呼べます.

ただし,後から取り消しや保存をしたい場合は,描く前に点のデータを一覧へ追加する必要があります.画面へ描いた結果だけでは,どの点を消して何を保存するか管理しにくいためです.

入力,状態の更新,再描画という順を意識します.

キー入力は,実行結果の画面へフォーカスがあるかによって受け取れるかが変わります.

コード欄に入力している文字と,作品の操作キーを混同しないよう,画面をクリックしてから操作します.作品の説明にも,操作する場所を具体的に書いてください.

動かないという報告が来たら,入力が届いているかから確認します.

ひな形はクリック位置を表示して点を描きます.

クリックを3回行い,毎回1個ずつ増えるかを確かめてください.同じ場所を繰り返し押した場合にも,イベントが何回発生したかをコンソールで確認できます.

見た目だけでは重なって1個に見える場合があるため,数値の記録が役立ちます.

制作自分の作品へ適用する

クリックした位置をコンソールへ出し,同じ場所へ点を描いてください.3回の操作を試した後,点のデータをリストへ追加する処理を加え,長さも表示します.

制作26-8 操作してよい範囲と,上限を決める

入力を受け付ける作品では,利用者が何回も操作した場合を考えます.

点を無制限に追加すると,画面が読みにくくなり,描画にも時間がかかるかもしれません.授業の作品では,例えば50個までという上限を決め,超えたときは追加せずに説明を表示できます.

上限は,作品の目的に合わせて選びます.

画面のどこでも操作してよいかも決めます.

上部に説明や得点を表示するなら,その範囲へ図形を置かない仕様にすることがあります.座標の条件を関数へまとめると,境界を含むかどうかを単独でテストできます.

見た目の枠と,実際に受け付ける範囲が一致しているかも確認してください.

拒否した操作では,元の作品を変えないことを明確にします.

上限を超えた点をいったん追加してから消すより,条件を確認してから追加するほうが分かりやすい場合があります.画面には追加しないのにデータだけ増える,という状態のずれを避けます.

以下のひな形は,座標の範囲だけを調べる関数です.

中央,境界,少し外側を試してから,クリック処理の入口へ組み込んでください.入力の条件を描画の奥へ散らばらせず,更新する前に確認する構成にします.

制作自分の作品へ適用する

xが-250〜250,yが-180〜180の範囲だけ受け付ける条件を作ります.境界を含め,外側を拒否するテストを書いてください.自分の作品では,この条件をどこで確認するか説明します.

制作26-9 取り消しの意味を,小さく決める

取り消し機能を作るときは,何を1回の操作として戻すかを決めます.

最後に追加した点を消すだけなら,図形一覧の末尾をpopすることで表せます.色の変更や全体移動まで戻す場合には,変更前の状態や操作の履歴が必要になります.

まず,今回の作品に必要な範囲へ絞って実装します.

一覧が空のときにも取り消しキーを押せることを考えてください.

空のリストへpopするとIndexErrorになります.何もせずに説明を表示するか,ボタンを無効にするかなど,利用者が予測できる振る舞いを決めます.

失敗した操作で作品が壊れないことが大切です.

データから最後の点を消しただけでは,画面の点が自動的に消えるわけではありません.

描画を消し,現在のデータをすべて描き直す手順が必要です.このため,早い段階でデータと再描画の関数を用意したことが役立ちます.

画面を真実の保存場所にせず,データを基準に表示を作ります.

以下は,取り消しによる一覧の変化だけを確認する例です.

実際の入力へつなぐ前に,3個から2個,1個,0個,さらにもう1回という順で確かめます.取り消しと追加を交互に行う操作列も試すと,空から再開できるか確認できます.

制作自分の作品へ適用する

最後の要素を消すundoを作り,空でもエラーにならないようにしてください.戻せたらTrue,空ならFalseを返す仕様にします.自分の描画処理では,undo後にどこで再描画するかを決めます.

制作26-10 クラスへまとめるか,関数のままにするか

データと操作が増えたら,クラスへまとめることを検討します.

ただし,クラスを使ったというだけで作品の質が上がるわけではありません.図形ごとの状態と操作がまとまっているならDot,作品全体の一覧と操作がまとまっているならSceneという形にできます.

関数と辞書のままでも,役割が明確なら十分な場合があります.

クラスを使う場合は,誰が何を持つかを先に決めます.

Dotは位置・大きさ・色を持ち,自分を描く操作を提供します.Sceneは図形の一覧を持ち,追加・取り消し・全体の描画を担当します.

入力の設定は,Sceneの操作をイベントへ結び付ける役割です.1個のクラスへ全部を詰め込まないようにします.

整理の前に,動いているコードと確認した操作列を残してください.

クラスへ書き換えた後,同じ操作で同じ図形数と配置になるかを比べます.見た目を変える新機能と,内部を整理する変更を同時に行うと,どこで違いが生じたか分かりにくくなります.

まず動作を保って整理し,その後で拡張します.

以下は,図形のデータを持つ最小のクラスです.

面積など必要な操作を加える前に,別の個体が独立しているかを確認してください.完成例を利用する場合も,DotとSceneのどちらを変えれば目的の機能を追加できるか説明してから編集します.

制作自分の作品へ適用する

Dotを2個作り,片方の色だけを変えても,もう片方は変わらないことをテストしてください.自分の作品でクラスを使う場合と使わない場合の,データと操作の置き場所を説明します.

制作26-11 必須機能を,操作の一覧でテストする

作品が動くようになったら,最初に決めた完成条件へ戻ります.

実装した機能を眺めるだけでなく,利用者が行う操作を順に試してください.点の作品なら,1個追加,3個追加,同じ場所へ追加,1個取り消し,すべて取り消し,空でもう一度取り消し,という確認が考えられます.

それぞれに期待する結果を書いてから操作します.

図形数,位置,色,コンソールの表示を具体的に決めます.動かしてから都合よく期待値を変えてしまうと,不具合を見逃します.

仕様が曖昧だった場合は,先に約束を決め直し,その約束に合わせてコードとテストを修正します.

通常の操作だけでなく,限界や順序の違いも試します.

上限まで追加した後,取り消して再び追加できるか,色を変えてから取り消した場合に次の色はどうなるか,といった組み合わせです.全部の組み合わせを試すことはできませんが,状態が切り替わる境目を優先すると,重要な問題を見つけやすくなります.

以下のひな形は,図形数の変化を画面なしで確認します.

実際のブラウザ操作でも同じ順を試してください.データだけの確認と,入力が届いて描画される確認は役割が違います.

両方を行うことで,計算は正しいが入力の結び付けが違う,といった問題を見つけられます.

制作自分の作品へ適用する

自分の作品の確認操作を5つ以上書き,各操作の前後で何が変わるかを記録します.通常の操作に加え,空または上限の状態を必ず含めてください.

制作26-12 見つけた不具合を,最小の例にする

制作中に問題が起きたら,動かなかった操作と入力を記録します.

「ときどき消せない」だけでは再現できないので,「点が0個の状態でUを押すと例外が出る」のように,直前の状態まで書きます.そこまでの操作列を短くできれば,原因を調べやすくなります.

原因の候補を一度に直そうとせず,確認したい仮説を1つ選びます.

図形数が正しいのに画面が残るなら,再描画やclearの担当を調べます.データ自体が増えていないなら,入力が届いているか,追加条件で拒否されていないかを調べます.

途中の値を見て,最初に期待と違う段階へ絞ります.

修正したら,失敗した操作をもう一度試し,さらに以前成功していた操作も確認します.

空の取り消しを直すつもりで,通常の取り消しまで何もしなくなることがあるからです.新しく加えた条件が,他の経路へどんな影響を与えるか考えてください.

以下は,空の一覧から取り消す問題を小さくした例です.

実際の作品で起きた不具合も,同じように短いコードへ切り出してみましょう.原因が分かったら元の作品へ修正を戻し,その説明をノートへ残します.

試行回数より,判断の根拠が伝わる記録を目指します.

制作自分の作品へ適用する

自分の作品で1件の不具合,または起こりそうな境界の問題を選び,短い入力で再現してください.期待値,実測値,原因,修正,再テストを記録します.

制作26-13 保存するデータを,作品の意味から選ぶ

作品を次回も編集したいなら,図形のデータを保存します.

画面の画像だけでは,どの点を動かすか,何色へ変えるかを管理しにくいからです.今回の点の作品では,中心座標,直径,色,並び順を残します.

ペンやイベントの関数は,読み込み後にコードが用意し直します.

形式にはversionやkindを含め,どの種類の作品かを区別します.

点のsizeが直径で,四角形のsizeが辺なら,同じキー名でも意味が違います.第25章の四角形データを,点の作品へ無条件に読み込ませないようにします.

構造の似たデータほど,意味を表す約束が重要です.

保存した後は,読み込みと検証が成功してから現在の作品を置き換えます.

壊れたJSONや違う形式を選んだ場合,現在の作品を残して理由を知らせます.保存は出力だけの機能ではなく,後で正しく使えることまで含むと考えてください.

完成例ではSでブラウザ内のdrawing.jsonへ書き,このページのJSON保存ボタンで手元へ取り出せます.

読み込むときはJSONを選び,実行結果の画面へ戻ってLを押します.作品は同じでも,仮想ファイルと手元のファイルは別なので,操作の順序を説明に含めます.

制作自分の作品へ適用する

自分の作品で残す値を列挙し,保存用の辞書を作ってJSONへ変換してください.実行中の道具を含めず,読み戻した値から何を作り直すかも説明します.

制作26-14 初めて使う人が,操作を見つけられるか

作品の使い方を知っているのは,作った本人だけかもしれません.

どこをクリックするか,どのキーを使うか,終了や取り消しはどうするかを,最初の画面や説明へ書きます.コードのコメントだけでは,作品を使う人へ伝わらない場合があります.

操作する人が見える場所に情報を置いてください.

状態が変わったときの反応も必要です.

色を切り替えたら次の色を表示し,上限で追加しなかったら理由を知らせます.何も起きないと,入力が届かなかったのか,条件で拒否されたのか分かりません.

ただし,毎フレーム大量の文字を出すと大事な情報が埋もれるので,変化のあるときに表示します.

色だけで状態を表している場合は,文字や形の違いも添えられないか考えます.

例えば選択中の色名を表示すれば,色の見分け方が違う人にも状態を伝えやすくなります.文字の大きさや背景との区別も確認し,自分の画面だけで読めればよいとしないようにします.

ひな形は操作一覧をコンソールへ出します.

自分の作品の操作に合わせて書き換えてください.友人へ説明せずに試してもらうと,見つけにくい操作に気付けます.

何を押そうとしたかを観察し,説明や配置を改善します.学習者向けの作品でも,使う人を想定した確認は大切です.

制作自分の作品へ適用する

操作方法,現在の状態,失敗したときの案内をそれぞれ1つ書いてください.色の変化だけでなく文字でも伝えられる状態を選び,表示するタイミングを決めます.

制作26-15 他の人の操作で,説明の不足を見つける

自分で確認した後は,他の人に作品を触ってもらうと,想定していなかった操作を見つけられます.

説明を口頭で補う前に,画面と短い使い方だけで試してもらいましょう.操作できなかった場合は,利用者の間違いと決め付けず,どの表示から何を予想したかを聞きます.

感想を集めるときは,「よかったですか」だけでなく,具体的な質問を使います.

最初に何をしようとしたか,取り消しを見つけられたか,色の切り替え結果が分かったかなどです.回答と実際の操作を対応させると,どこを直せばよいか判断しやすくなります.

改善は,目的に関係するものから選びます.

すべての要望を追加すると,作品が複雑になって元の目的が見えなくなるかもしれません.必須機能を使いやすくする変更を優先し,大きな追加案は次の版の候補として残すこともできます.

判断した理由をノートへ書けば,設計の振り返りになります.

以下のひな形は,確認する操作を一覧にするためのものです.

実際に観察した結果を追記してください.録画や名前などの情報をむやみに集める必要はありません.

今回の改善に必要な操作と結果を記録します.完成後の説明には,どの観察を受けて何を変えたかを具体的に述べます.

制作自分の作品へ適用する

2つの操作を他の人に試してもらう想定で,確認したいことと成功条件を書いてください.実際に試した場合は,観察した事実と自分の解釈を分けて記録します.

制作26-16 提出物と,再現手順をそろえる

作品が完成したら,コード,必要なデータ,使い方,確認した内容をそろえます.

先生から演習記録の提出が指定されている場合は,公開鍵の設定や入力した学生情報を確認し,演習記録ZIPをLMSへ提出します.作品JSONと演習記録ZIPは用途が違うため,どちらを提出する指示かを区別してください.

再現手順には,開くページ,実行するコード,必要なファイル,操作の順序を書きます.

ブラウザの中にたまたま残っているデータへ依存していないか,ページを開き直した状態でも確認します.保存したファイルを使う場合は,どのタイミングで読み込むかも明記してください.

コードだけ渡しても,必要な状態が再現できなければ作品を評価しにくくなります.

説明には,工夫した点だけでなく,残った制限も具体的に書きます.

例えば図形は50個まで,色は2色,取り消しは最後の追加だけ,という内容です.何でもできるように見せるより,対応する範囲が分かるほうが使いやすくなります.

未完成の機能がある場合は,動く範囲と次に直す点を分けて伝えます.

最後に,最初の目的の1文へ戻り,実際の作品がそれを満たしているかを確認します.

使った文法の数やコードの長さだけでなく,どの設計が変更や確認をしやすくしたかを振り返ってください.次の作品でも使いたい考え方を1つ選ぶと,今回の制作がその場限りで終わらず,次の学習へつながります.

制作自分の作品へ適用する

使い方,必要ファイル,確認した操作,制限,工夫,次の改善をそれぞれ短く書いてください.保存したコードを最初から実行し,説明の手順だけで作品を再現できるか確認します.

組み合わせた実装例:点を置く作品

以下はクリックで点を追加し,Uで取り消し,Cで次の色を切り替える例です.Sで保存の準備をし,停止してからJSON保存ボタンで手元へ取り出します.復元はJSONを読み込み,例題を実行し,画面でLを押します.第25章の四角形とは別の形式です.

入出力は作品を停止してから行ってください.

project26_complete.py
from turtle import *
import json

class Dot:
    def __init__(self, x, y, size, color):
        self.x, self.y = x, y
        self.size, self.color = size, color
    def draw(self, pen):
        pen.penup()
        pen.goto(self.x, self.y)
        pen.dot(self.size, self.color)
    def to_data(self):
        return {"x": self.x, "y": self.y, "size": self.size, "color": self.color}

class Scene:
    def __init__(self, pen):
        self.pen = pen
        self.shapes = []
        self.color = "blue"
    def add(self, x, y):
        if len(self.shapes) >= 50:
            print("50個までです")
            return
        self.shapes.append(Dot(x, y, 20, self.color))
        self.draw(self.pen)
    def undo(self):
        if self.shapes:
            self.shapes.pop()
        self.draw(self.pen)
    def change_color(self):
        self.color = "red" if self.color == "blue" else "blue"
        print("次の色", self.color)
    def draw(self, pen):
        pen.clear()
        for shape in self.shapes:
            shape.draw(pen)
        print("図形数", len(self.shapes))
    def save(self):
        data = {"version": 1, "kind": "dot-art", "shapes": [s.to_data() for s in self.shapes]}
        with open("drawing.json", "w", encoding="utf-8") as file:
            json.dump(data, file, ensure_ascii=False, indent=2)
        print("drawing.jsonへ保存しました.JSONを保存ボタンで取り出してください")
    def load(self):
        try:
            with open("drawing.json", encoding="utf-8") as file:
                data = json.load(file)
            if not isinstance(data, dict) or data.get("kind") != "dot-art" or type(data.get("version")) is not int or data["version"] != 1:
                raise ValueError("点の作品の形式ではありません")
            records = data.get("shapes")
            if not isinstance(records, list) or len(records) > 50:
                raise ValueError("点の一覧は50個以下です")
            restored = []
            for record in records:
                if not isinstance(record, dict):
                    raise ValueError("点は辞書です")
                for key, limit in (("x", 320), ("y", 240), ("size", 100)):
                    value = record.get(key)
                    if type(value) not in (int, float) or not -limit <= value <= limit:
                        raise ValueError("数値の範囲が違います")
                if record["size"] <= 0 or record.get("color") not in ("blue", "red"):
                    raise ValueError("大きさか色が違います")
                restored.append(Dot(record["x"], record["y"], record["size"], record["color"]))
        except (OSError, ValueError) as error:
            print("読み込めません:", error)
        else:
            self.shapes = restored
            self.draw(self.pen)

pen = Turtle()
pen.hideturtle()
pen.speed(0)
scene = Scene(pen)
onscreenclick(scene.add)
onkey(scene.undo, "u")
onkey(scene.change_color, "c")
onkey(scene.save, "s")
onkey(scene.load, "l")
listen()
print("クリック:追加 / U:取り消し / C:次の色 / S:保存準備 / L:復元")
done()
発展発展:3色に増やして保存・復元する

完成例を青・赤・緑の3色へ拡張してください.色の切り替えだけでなく,読み込み時に許可する色の検査も対応させます.緑の点を保存し,ページを開き直して同じ色で復元できることを確認してください.変更する場所を探すときは,画面で使う値と,ファイルで受け付ける値の約束が一致しているかに注目します.

評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. 色の切り替えが青→赤→緑→青の順に回り,次の色をコンソールか画面に表示する
  2. 許可する色を1か所(例:COLORS というリスト)にまとめ,切り替えと読み込みの検査の両方でそれを使っている
  3. 緑の点を含む作品を保存し,ページを開き直して同じ色で復元できたことを,手順と結果のコメントで記録している

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 色を4色以上に増やしても,1か所の変更だけで済むことを確かめている
  • 現在の色を,色だけでなく文字でも画面に表示している

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

発展発展:上限を変更して境界を確かめる

図形の上限を10個へ変更し,9個からの追加,10個からの追加,取り消した後の再追加を試してください.画面の追加条件と,読み込みファイルの個数制限をそろえます.10個の作品は復元でき,11個の作品は元の表示を保ったまま拒否されることを確認します.上限を何か所にも直接書くより,1つの設定値から使う構成も検討してください.

評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. 上限を1つの設定値(例:LIMIT = 10)にまとめ,追加の条件と読み込みの個数制限の両方で使っている
  2. 9個から追加できて10個で止まり,取り消した後は再び追加できることを確かめている
  3. 10個の作品は復元でき,11個の作品は元の表示を保ったまま拒否されることを確かめている

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 上限に達したことを画面に文字で表示している
  • 上限の境界(9・10・11個)を,画面を使わない assert のテストにもしている

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

提出する作品

制作自由制作を提出する

制作26-1〜26-15で育てた自分の作品を,このカードのコード欄にまとめて提出用に仕上げてください.題材は自由です.最初から実行し直して,次の評価の目安の必須をすべて満たしているか確かめます.

評価の目安(10 段階)

必須(すべて満たして正しく動けば 8)

  1. 第23・24章のクラス(または第21章の辞書と関数)で図形などのデータを持ち,追加・取り消しなど状態を変える操作が2つ以上ある
  2. 作品データを version を含むJSONで保存し,読み込んだデータを検査してから復元できる(第25章)
  3. 空・上限などの境界を含む assert を3件以上残し,最初から実行し直しても通る(第22章)
  4. 冒頭のコメントに,目的の1文・操作方法・対応する範囲と制限を書いている(制作26-15の項目)

発展(必須に加えて 1 つ以上で 9,学んだ範囲を大きく超える作り込みで 10)

  • 他の人に試してもらった観察をもとに,操作の説明や表示を改善し,その理由を記録している
  • 完成例にない機能(選択して移動,複数の図形の種類,得点など)を,役割の分かるクラスや関数で加えている
  • 学習した範囲を大きく超える作り込み(複数の画面,独自の保存形式の版の移行など)をしている

必須が 1〜2 つ足りない → 7 / 動かない・未着手が複数 → 6

復習:虫食いで確かめる

コードの ____ を埋めてください.実行前に結果を予測し,実行後に問題文の条件と照合しましょう.assert は条件が成り立つかを調べ,成り立たないとエラーになります.

虫食い虫食い・復習 1 作品の大きさを変えられるようにする

一つの変数から正方形の四辺の長さを決めます.size を40から80へ変えると絵全体が大きくなることも確認してください.

fill_review_playground_1.py
from turtle import *
size = 40
for i in range(4):
    forward(____)
    left(90)
done()
虫食い虫食い・復習 2 図形に保存の形を任せる

Dot 自身が保存用の辞書を返します.to_data を呼んで,2個の点のデータ一覧を作ってください.

fill_review_playground_2.py
class Dot:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def to_data(self):
        return {"x": self.x, "y": self.y}
dots = [Dot(0, 0), Dot(30, 40)]
data = []
for d in dots:
    data.append(d.____())
assert data == [{"x": 0, "y": 0}, {"x": 30, "y": 40}]
print(data)
虫食い虫食い・復習 3 上限で追加を止める

点は3個までの作品です.3個あるときは追加せず False を返す条件を補ってください.

fill_review_playground_3.py
class Scene:
    def __init__(self):
        self.shapes = []
    def add(self, shape):
        if len(self.shapes) ____ 3:
            return False
        self.shapes.append(shape)
        return True
scene = Scene()
for i in range(3):
    scene.add(i)
assert scene.add(99) is False
assert len(scene.shapes) == 3
print(scene.shapes)
虫食い虫食い・復習 4 作品の初期状態を決める

前の描画を消し,かめを原点へ戻して右へ向けます.繰り返し実行しても同じ線になることを確認してください.

fill_review_playground_4.py
from turtle import *
____()
penup()
goto(____, ____)
setheading(0)
pendown()
forward(60)
done()
虫食い虫食い・復習 5 仕様をassertで確かめる

一行4個を3行並べる設計です.個数を計算し,仕様の12個と一致することを確かめてください.

fill_review_playground_5.py
rows = 3
columns = 4
count = rows ____ columns
assert count == ____
print("配置する図形:", count)
虫食い虫食い・復習 6 作品データを保存し復元する

作品名と配色をJSON文字列で往復させます.変換する関数を補い,辞書が元と一致することを確認してください.

fill_review_playground_6.py
import json
work = {"title": "三色の線", "colors": ["red", "green", "blue"]}
text = json.____(work, ensure_ascii=False)
restored = json.____(text)
assert restored == work
print(restored["title"])