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

繰り返しの入れ子

繰り返しを,さらに繰り返す.模様はここから生まれます.

前の章,正方形を描く繰り返しを覚えました.では その正方形を 10 個並べたいときはどうするでしょうか. 繰り返しのプログラムを 10 回書く — それでは元の木阿弥です.

答えは「繰り返しを,繰り返す」です. 正方形を描く繰り返しを,まるごと別の繰り返しの中に入れてしまいます. これを入れ子(ネスト)といいます. たった数行増えるだけで,絵は一気に模様らしくなります.

この章でできるようになること
  • 繰り返しの中に繰り返しを書き,同じ図形を何個も並べられる
  • 外側と内側のループ変数が,それぞれ何回変わるかを説明できる
  • 外側のループ変数を使って,1 個ずつ大きさや角度が変わる模様を描ける
  • 剰余演算子 %周期を作り,色や形を交互に変えられる
  • 二重の繰り返しを行と列と考えて,格子状・階段状に並べられる
  • printend を使って,文字や数をの形に並べられる
  • 繰り返しの回数から描く線の本数を見積もり,描きすぎを避けられる
今回いちばん大事なこと 今回のプログラムは,字下げが深くなります. 字下げが 1 段ずれただけで,まったく違う絵になります. うまくいかないときは,命令を疑う前に 各行の左端がそろっているかを見てください. この章で覚えることの半分は,そこです.

7.1 二重の繰り返し

7.1.1 窓を 4 つ並べる

正方形を 4 つ,向きを変えながら描いて「窓」を作ります. 正方形を描く繰り返しを, それを 4 回くり返す繰り返しの中に入れています.

window.py
from turtle import *

pensize(2)
pencolor("navy")

for j in range(4):          # 窓を 4 つ(外側)
    for i in range(4):      # 正方形を 1 つ(内側)
        fd(50)
        rt(90)
    rt(90)                  # 次の正方形の向きへ

ht()
done()
図 7.1 窓.同じ角を中心に,正方形を 90 度ずつ回して 4 つ描いた.

内側の for が正方形 1 つを描きます. 外側の for は,その「正方形を描く仕事」をまるごと 4 回くり返します. 間にある rt(90)内側の外・外側の中にあるので, 正方形 1 つを描き終わるたびに 1 回だけ実行されます.

7.1.2 外側と内側のループ変数

入れ子では,ループ変数が 2 つ登場します. 外側を j,内側を i とするのが昔からの習慣です (どちらも好きな名前で構いません). 外側が 1 回進むあいだに,内側は最後まで全部回ります. print で確かめましょう.

nest_print.py
for j in range(3):
    print("外側", j, "回目")
    for i in range(4):
        print("    内側", i)

print("ぜんぶ終わり")

コンソールをよく見てください.外側 0 回目 のあとに 内側 0・1・2・3 が並び,そのあとで 外側 1 回目 に進みます. つまり内側の中身は 3 × 4 = 12 回実行されます.

変わり方中身が実行される回数
外側 j0, 1, 2 とゆっくり進む3 回
内側 i0, 1, 2, 3 を外側 1 回ごとに繰り返す3 × 4 = 12 回
外側と内側の関係 時計に例えると,外側が長針,内側が短針…ではなく, 外側が「分」,内側が「秒」です. 秒が 0 から 59 まで一巡すると,分が 1 つ進みます. 入れ子の繰り返しは,これとまったく同じ動きをします.

7.1.3 字下げが構造を表す

入れ子になると,字下げは 2 段・3 段と深くなります. どの行がどの繰り返しに属するかは,字下げの深さだけで決まります.

字下げの深さと実行回数
for j in range(4):          # 深さ 0(どの繰り返しの外でもない)
    for i in range(4):      # 深さ 1(外側の中)
        fd(50)              # 深さ 2(内側の中)← 16 回実行
        rt(90)              # 深さ 2            ← 16 回実行
    rt(90)                  # 深さ 1(内側の外,外側の中)← 4 回実行
ht()                        # 深さ 0(全部終わってから)  ← 1 回実行
中かっこが無いということ かたまりの範囲を示すのは字下げだけです. かっこで囲むわけではないので,1 段ずれても機械は 「そういうプログラムなのだ」と思って,黙って別の絵を描きます. エラーが出ないぶん,かえって気づきにくいのです.
  • 字下げは半角スペース 4 つ.1 段深くなるごとに 4 つ増やす.
  • Tab キーを押せば 4 つ分入ります.手で数える必要はありません.
  • 思ったとおりの絵にならないときは,行の左端を縦に見てそろっているか確かめること.

7.1.4 入れ子と,ただ並べることのちがい

円弧を 2 つつなぐと,花びらが 1 枚できます. 花を描くには,その花びらを 6 回くり返す必要があります. つまり「円弧を描く繰り返し」を「花びらを描く繰り返し」の中に入れる,二重の入れ子です.

flower.py
from turtle import *

pensize(2)
pencolor("hotpink")

for j in range(6):          # 花びらを 6 枚(外側)
    for i in range(120):    # 1 つめの円弧(内側)
        rt(1)
        fd(1)
    rt(60)                  # 花びらの先で折り返す
    for i in range(120):    # 2 つめの円弧(内側)
        rt(1)
        fd(1)

ht()
done()
図 7.2 花.120 度の円弧 2 つで花びら 1 枚,それを 6 回.

次は,よくある間違いです.2 つめの円弧の字下げを忘れて, 外側の繰り返しのに出してしまいました. プログラムの見た目はほとんど同じなのに,結果はまるで違います.

図 7.3 正しい入れ子.花になる
図 7.4 2 つめの円弧を外に出してしまった場合

右は,1 つめの円弧だけを 6 回くり返したあとで, 2 つめの円弧を最後に 1 回だけ描いています. 「繰り返しを繰り返す」ためには, 繰り返したいものを,まるごと外側の中に入れる必要があります.

虫食い虫食い 7-A 窓を 4 つ

正方形を 4 つ並べて窓を作ります. 外側は何回まわせばよいでしょうか.また,1 つ描き終わるたびに 何度回れば次の正方形が別の向きになるでしょうか. ____ を 2 つ埋めてください.

fill5a_window.py
from turtle import *

pensize(2)
pencolor("navy")

for j in range(____):
    for i in range(4):
        fd(50)
        rt(90)
    rt(____)

ht()
done()

7.2 外側のループ変数で,1 個ずつ変える

同じ図形をただ並べるだけなら,入れ子の値打ちは半分です. 外側のループ変数 j を内側で使うと, 「1 個ずつ大きくなる」「1 個ずつ細かくなる」模様が作れます.

7.2.1 だんだん大きくなる正方形(貝殻)

shell.py
from turtle import *

pensize(2)
pencolor("saddlebrown")

rt(20)

for j in range(1, 11):          # j は 1, 2, 3, … 10
    for i in range(4):
        fd(10 * j)              # ← j 番目の正方形は 1 辺 10×j
        rt(90)
    rt(20)                      # 少し回してから次の正方形へ

ht()
done()
図 7.5 貝殻.正方形が少しずつ大きく,少しずつ回っていく.

ここで range(1, 11) と書いたのには理由があります. range(10) だと j が 0 から始まり, 1 個目の正方形の 1 辺が 10 × 0 = 0 になって消えてしまうからです. 1 から数えたいときは range(1, 11) と書きます.

やってみよう rt(20) の 20 を 15 や 30 に変えると,巻き方が変わります. 10 * j の 10 を 5 にすれば細く小さな貝殻になります. 数字を 1 つ変えるだけで別の模様になるのが,入れ子の面白さです.

7.2.2 だんだん細かくなる円(目玉)

前の章,円は fd(1)rt(1) を 360 回くり返せば描けました. この 曲がる角度そのものを j にすると, 大きさの違う円がいくつも描けます. 曲がる角度が大きいほど早く 1 周してしまうので,円は小さくなります.

eye.py
from turtle import *

pensize(1)
pencolor("navy")

for j in range(2, 11):              # 曲がる角度を 2 度から 10 度まで
    for i in range(0, 360, j):      # 合計 360 度になる回数だけ
        fd(1)
        rt(j)

ht()
done()
図 7.6 同じ場所から描き始めた,大きさの違う 9 個の円.

内側の range(0, 360, j) は「0 から 360 手前まで j 飛ばし」, つまり 360 ÷ j 回という意味です. 1 回に j 度ずつ曲がるので,合計はいつでもちょうど 360 度になります. 外側の変数が,内側の回数と角度の両方を決めている点に注目してください.

虫食い虫食い 7-B 貝殻の 1 辺

j 番目の正方形の 1 辺を,j の 10 倍に してください.____ に入るのは数ではなく, j を使ったです.

fill5b_shell.py
from turtle import *

pensize(2)
pencolor("saddlebrown")

rt(20)

for j in range(1, 11):
    for i in range(4):
        fd(____)
        rt(90)
    rt(20)

ht()
done()

7.3 あまり % で周期を作る

7.3.1 % は割り算のあまり

%剰余演算子といい,割り算のあまりを求めます. 7 % 3 は 1,8 % 2 は 0 です. これを i に対して使うと, 一定のリズム(周期)を作ることができます.

mod_print.py
print(7 % 3)
print(8 % 2)

for i in range(6):
    print(i, i % 2, i % 3)
i01234567
i % 201010101
i % 301201201

i % 20 と 1 が交互に, i % 30・1・2 が順番に現れます. i % 2 == 0 なら i は偶数, i % 2 == 1 なら奇数です.

7.3.2 i % 2 で交互に色を変える

繰り返しの中に if を書く形は,第 6 章でも使いました. 繰り返しの中の分岐も,りっぱな入れ子です. 今回は,その条件に % を使います.

alt2.py
from turtle import *

pensize(8)

for i in range(12):
    if i % 2 == 0:              # 偶数回目なら
        pencolor("crimson")
    else:                       # 奇数回目なら
        pencolor("royalblue")
    fd(60)
    bk(60)
    rt(30)

ht()
done()
図 7.7 12 本の線を,赤と青で交互に塗り分けた.

7.3.3 i % 3 で 3 色を回す

3 つ以上で回したいときは,elif を足します. i % 3 は 0・1・2 しか取らないので, ifelifelse の 3 つで足ります.

alt3.py
from turtle import *

pensize(8)

for i in range(18):
    if i % 3 == 0:
        pencolor("crimson")
    elif i % 3 == 1:
        pencolor("gold")
    else:
        pencolor("seagreen")
    fd(70)
    bk(70)
    rt(20)

ht()
done()
図 7.8 3 色が順ぐりに現れる.% 3 が周期を作っている.
ヒント 色を 4 色にしたければ i % 4 にして elif を 1 つ増やします. 「何個ごとに繰り返すか」が % の右の数, 「そのうちの何番目か」が比べる数です.

7.3.4 形そのものを交互に変える

if の中身を,色ではなく繰り返しそのものにすることもできます. 偶数回目は正方形,奇数回目は正三角形を描いてみましょう. for の中に if があり,その中にまた for がある, 三重の入れ子です.

sqtri.py
from turtle import *

pensize(2)
pencolor("darkslateblue")

pu()
goto(-170, -20)
pd()

for i in range(8):
    if i % 2 == 0:
        for j in range(4):      # 正方形
            fd(30)
            lt(90)
    else:
        for j in range(3):      # 正三角形
            fd(30)
            lt(120)
    pu()                        # 次の図形の位置へ
    fd(45)
    pd()

ht()
done()
図 7.9 四角と三角が交互に並ぶ.if の中に for が入っている.
虫食い虫食い 7-C 3 本ごとに色を変える

18 本の線を,3 色が順ぐりに現れるように塗り分けます. ____ を 2 つ埋めてください. 「何個ごとに繰り返すか」と「そのうちの何番目か」を考えます.

fill5c_three.py
from turtle import *

pensize(8)

for i in range(18):
    if i % ____ == 0:
        pencolor("crimson")
    elif i % 3 == ____:
        pencolor("gold")
    else:
        pencolor("seagreen")
    fd(70)
    bk(70)
    rt(20)

ht()
done()

7.4 二重の繰り返しで「表」を作る

7.4.1 行と列という考え方

入れ子でいちばんよく使うのが,格子状に並べる使い方です. 外側の繰り返しを行(よこの並び), 内側の繰り返しを列(たての並び)と考えます. 表計算ソフトのマス目や,カレンダーと同じ考え方です.

表を作るときの型
for row in range(行の数):
    for col in range(列の数):
        (row 行 col 列に何かを描く)

row(行)と col(列)は, ij の代わりによく使われる名前です. 意味のある名前を付けると,あとで読み返したときに分かりやすくなります. 位置は goto で計算します.

grid.py
from turtle import *

pensize(1)
pencolor("teal")

for row in range(5):                # 行:上から下へ 5 段
    for col in range(8):            # 列:左から右へ 8 個
        pu()
        goto(-160 + col * 40, 120 - row * 40)   # ← 位置を計算する
        pd()
        for k in range(4):          # 正方形を 1 つ
            fd(30)
            rt(90)

ht()
done()
図 7.10 5 行 8 列=正方形 40 個.三重の入れ子になっている.
意味
col * 40列が 1 つ進むごとに,右へ 40 ずらす
-160 + …左端の位置.画面の真ん中に来るように調整する
- row * 40行が 1 つ進むごとに,下へ 40 ずらす
120 - …上端の位置.y は上が大きいので,行が進むと引く
ヒント ずらす量(40)は,図形の大きさ(30)より少し大きくしておきます. 同じにすると図形どうしがぴったりくっつき, 小さくすると重なります.わざと重ねるのも模様の作り方の一つです.
虫食い虫食い 7-D 4 行 6 列の格子

4 行 6 列の格子に正方形を並べます. 列の数と,行が 1 つ進むときに下へずらす量(40)を ____ に入れてください.

fill5d_grid.py
from turtle import *

pensize(1)
pencolor("teal")

for row in range(4):
    for col in range(____):
        pu()
        goto(-120 + col * 40, 90 - row * ____)
        pd()
        for k in range(4):
            fd(30)
            rt(90)

ht()
done()

7.4.2 特定のマスだけ変える

rowcol が分かっているので, if で「この場所だけ」を選び出せます. row == colななめの対角線のマスです.

diagonal.py
from turtle import *

pensize(2)

for row in range(6):
    for col in range(6):
        pu()
        goto(-96 + col * 32, 96 - row * 32)
        pd()
        if row == col:              # ななめの位置なら
            pencolor("crimson")
        else:
            pencolor("silver")
        for k in range(4):
            fd(26)
            rt(90)

ht()
done()
図 7.11 row == col のマスだけ赤くした.

条件を (row + col) % 2 == 0 に変えると 市松模様(チェック柄)になります. % と行・列を組み合わせると,模様の幅が一気に広がります.

7.4.3 階段状に並べる

内側の繰り返しの回数そのものを,外側の変数で決めることもできます. for col in range(row): と書けば, 1 行目は 1 個,2 行目は 2 個…と増えていきます.

stairs.py
from turtle import *

pensize(2)
pencolor("seagreen")

for row in range(1, 7):             # 1 段目から 6 段目まで
    for col in range(row):          # ← row 個だけ並べる
        pu()
        goto(-150 + col * 34, 110 - row * 34)
        pd()
        for k in range(4):
            fd(28)
            rt(90)

ht()
done()
図 7.12 1 個・2 個・3 個…と増える階段.正方形は全部で 21 個.
ヒント 描かれる正方形の数は 1+2+3+4+5+6 = 21 個です. 内側の回数が毎回変わるので,「外側 × 内側」の単純な掛け算にはなりません. print(row, col) を入れて,順番を目で確かめてみてください.
虫食い虫食い 7-E 階段の個数

1 段目に 1 個,2 段目に 2 個…と並べます. 内側の繰り返しは何回まわせばよいでしょうか. ____ には数ではなく, 外側のループ変数の名前が入ります.

fill5e_stairs.py
from turtle import *

pensize(2)
pencolor("seagreen")

for row in range(1, 7):
    for col in range(____):
        pu()
        goto(-150 + col * 34, 110 - row * 34)
        pd()
        for k in range(4):
            fd(28)
            rt(90)

ht()
done()

7.4.4 文字と数を並べる — 九九の表

入れ子の繰り返しは,絵を描くためだけのものではありません. 行と列という考え方は,文字や数を並べてを作るときにも そのまま使えます.掛け算の九九の表を作ってみましょう.

そのために,print の書き方をひとつだけ覚えます. print はふつう,表示したあとに改行します. end=" " を付けると,改行する代わりに半角スペースを打ちます. こうすると,次の print同じ行の続きに表示されます.

書き方表示したあとにすること
print(x)改行する(次は下の行の頭から)
print(x, end=" ")半角スペースを打つ(次は同じ行の続きから)
print(x, end="")何もしない(すきまなく横に続ける)
print()何も表示せず,改行だけする
kuku.py
for row in range(1, 10):          # 1 の段から 9 の段まで(9 行)
    for col in range(1, 10):      # 1 倍から 9 倍まで(9 列)
        print(row * col, end=" ")
    print()                       # ← 1 行ぶん並べ終わったので改行する

print("おしまい")

row段(行)col何倍か(列)です. 内側の繰り返しが 1 行ぶんの数を横に並べ, それが終わったところで改行する — この繰り返しが 9 回で表になります.

print() をどこに書くか print() の字下げが,このプログラムの急所です.
  • 字下げ 4 つ(内側の外・外側の中) … 正解.1 行終わるごとに 1 回改行する.
  • 字下げ 8 つ(内側の中) … 数を 1 つ表示するたびに改行してしまい,81 行の縦 1 列になる.
  • 字下げなし(外側の外) … 全部並べ終わってから 1 回だけ改行するので,81 個が横 1 行に並ぶ.
3 とおりとも試してみてください. 7.1.3 で見た「字下げの深さ=実行回数」が,目で確かめられます.
虫食い虫食い 7-F 文字で直角三角形を作る

* を使って,次のような 10 行の直角三角形を表示します. ____ を埋めてください. 1 行目は 1 個,2 行目は 2 個…と増えていきます. 7.4.3 の階段と同じ考え方です.

出したい結果
*
**
***
****
(…10 行目まで)
fill5f_tri.py
for row in range(1, 11):
    for col in range(____):
        print("*", end="")
    print()

7.5 描きすぎに注意する

入れ子の繰り返しは,回数が掛け算で増えます. 外側 10 回・内側 10 回・その中で 4 本の線なら, 線は 10 × 10 × 4 = 400 本です. ここまでは一瞬ですが,うっかりすると何十万本にもなります.

プログラム計算引かれる線の本数
正方形 1 つ44 本
正方形を 10 個(7.1 の窓の形)10 × 440 本
5 行 8 列の格子(図 7.10)5 × 8 × 4160 本
10 行 10 列の格子10 × 10 × 4400 本
円(360 本)を 100 個100 × 36036000 本
円(360 本)を 500 個500 × 360180000 本 → 止まります
重くなったら,まず回数を疑う この教材の実行環境は,描画命令が 12 万個を超えるか, 実行が 10 秒を超えると自動的に止まり, 「無限ループになっていませんか」と知らせます.
  • 試すときは,まず回数を小さくして(range(3) など)形を確かめ,うまくいってから増やすこと.
  • ht() を入れ,速さを「とても速い」にすると表示が軽くなります.
  • while True: は絶対に書かないこと.ブラウザが固まり,実行を止められなくなります.ずっと動かし続けたいときは,第 10 章で習う ontimer を使います.
どこまでなら大丈夫か 逆に言えば,1 万本くらいまでなら平気です. 100 個の円(36000 本)も数秒で描けます. 人間が手で書くことを考えれば,途方もない量を一瞬でこなしているわけです. 「コンピュータの得意な仕事」とは,まさにこれのことです.

7.6 この章で出てきた書き方

書き方意味
for j in …: の中の for i in …:入れ子.外側 1 回につき,内側が最後まで回る
外側 n 回 × 内側 m 回中身は n × m 回実行される
fd(10 * j)外側のループ変数を使って,1 個ずつ変える
i % 22 で割ったあまり.0 と 1 が交互 = 偶数・奇数
i % 33 で割ったあまり.0・1・2 が順ぐりに現れる
iffor の中に書く繰り返しの何回目かによって,色や形を変える
for row in …: / for col in …:行と列.格子状に並べるときの型
goto(x0 + col * d, y0 - row * d)行と列の番号から位置を計算する.y は行が進むと引く
for col in range(row):内側の回数を外側の変数で決める(階段状)
print(x, end=" ")改行せずに横へ並べる.表を作るときに使う
print()改行だけする.内側の外・外側の中に置く

演習

「▶ この演習を開く」で右側に読み込み,それを発展させて作品にしてください. できあがったら「⤓ 保存」でファイルに保存して,手元に残しておきましょう. どの演習も入れ子の繰り返しを必ず使うことが条件です.

困ったときの手順 うまく動かないときは,回数を 2〜3 回に減らして実行してみてください. 形が小さくなるぶん,どこで思っていない動きをしているかがよく見えます. それでも分からなければ,速さを「とてもゆっくり」にしてかめを目で追いましょう.
演習演習 7-1 正方形を 10 個並べる

正方形を横に 10 個並べるプログラムを与えます.これをもとに, 並べ方・大きさ・色を変えて模様を作ってください. j を使って大きさを変える,j % 2 で色を交互にする, ななめに並べる — どれでもかまいません.

出発点:正方形 10 個
演習演習 7-2 正方形を 100 個並べる

10 行 10 列の格子に正方形を 100 個並べるプログラムを与えます. 行や列によって大きさ・色を変えるなどして,模様にしてください. rowcol の両方が使えることを思い出してください.

出発点:10 行 10 列の格子
演習演習 7-3 四角と三角を交互に並べる

格子の中で,四角形と三角形を交互に描くプログラムを与えます. 3 種類以上の図形を回す, 色も一緒に変えるなどして発展させてください. % 3% 4 を使えば,周期を変えられます.

出発点:四角と三角が交互に並ぶ格子
演習演習 7-4 貝殻のアレンジ

だんだん大きくなる正方形で貝殻を描くプログラムを与えます. 正方形を別の図形に変える回す角度や大きさの増え方を変えるなどして発展させてください. j を使えば,色をだんだん濃くすることもできます.

出発点の貝殻
演習演習 7-5 タイヤのアレンジ

四角形を少しずつ回しながら 45 個描いて,タイヤのような図を作ります. ずらす角度は 8 度(rt(98) は 90 + 8 の意味), 1 辺は 10 歩です.ホイールの模様を足す・中心に円を描く・ 本数や角度を変えるなどして発展させてください.

出発点のタイヤ
演習演習 7-6 ドラえもんを描く

入れ子の繰り返しだけで,ドラえもんの顔を描くプログラムを与えます. 使っているのは今回習ったことばかりです.

  • 顔・目のふち・鼻・鈴は,どれもfdlt を繰り返した円
  • 黒目は,7.2.2 の目玉とまったく同じ入れ子(曲がる角度を変えながら円を重ねる)
  • 口は,円を描く途中でpu()pd() を切り替えて下半分だけ残したもの
  • ひげは,外側のループ変数で開始位置と向きを変えた直線 3 本

このプログラムをもとに,独自のアレンジを加えてください. 色を変える,ほっぺを足す,首輪と鈴を付ける, 顔の形を自分の好きなキャラクターに作り変える — どれでもかまいません.

出発点のドラえもん
演習演習 7-7 キーボードを描く

3 行 10 列のキーを並べ,特定のキーだけ横長にするプログラムを与えます. キーの数・配置・大きさを変えて, 本物のキーボードらしくしてください. if の条件を増やせば,「このキーだけ色を変える」こともできます.

出発点のキーボード(右下だけ横長)
自由演習 7-8 入れ子で作品を描く

入れ子の繰り返しを使って,好きな絵や模様を描いてください. 演習 7-6 のドラえもんは,円を何重にも重ねて目を作り, 繰り返しでひげを引いているだけでした. 同じように,身近なものを繰り返しだけで表現してみましょう.

  • 二重以上の入れ子を必ず使うこと
  • 外側のループ変数を内側で1 回は使うこと(大きさ・角度・色のどれかを変える)
  • % を使った周期か,for の中の if1 か所以上使うこと
  • 先頭にコメントで,題名・氏名・日付を書くこと
  • 描く線が多くなりすぎないよう,回数を見積もってから実行すること
ヒント ネタに困ったら,花(7.1.4)の花びらの数を変える, 目玉(7.2.2)を 2 つ並べて顔にする, 格子(7.4.1)のマスの中身を % で選ぶ, 階段(7.4.3)をピラミッドにする,あたりから試してみてください.
発展演習 7-9 素数を見つける

ここまでの演習は,すべてでした. 最後に,入れ子の繰り返しを計算に使ってみます. 素数とは,1 と自分自身でしか割り切れない 2 以上の整数のことです. 2, 3, 5, 7, 11, 13, 17, 19 … と続きます.

第 6 章の 6.9.4 で,1 つの数が素数かどうかを フラグを使って調べました.出発点のプログラムはその形です. 今度はそれを繰り返しの中に入れて, 2 から 50 までの素数をぜんぶ見つけてください.

  1. 外側の繰り返しで,調べたい数 num を 2 から 50 まで動かす.
  2. 内側の繰り返しで,num を 2 から num - 1 まで順に割ってみる.
  3. 1 回でも割り切れたら,フラグを False にする.
  4. 内側が終わったところでフラグを調べ,True のままなら num を表示する.
どこで旗を立て直すか フラグを True に戻す場所が急所です. is_prime = True を外側の繰り返しのに書くと, 一度 False になったきり戻らず,4 以降が 1 つも表示されません. 調べる数が変わるたびに旗を立て直す必要があります.
余裕があれば 発展 150200 にしてみてください. 表示が横に長くなるので,print(num, end=" ") を使うと見やすくなります.
発展 2:内側の繰り返しは, num - 1 まで調べなくても答えは変わりません. どこまで調べれば十分か考え,range を書き換えてください. 速くなったかどうかは,表示される個数が同じままかで確かめます.

まとめ

  • 繰り返しの中に繰り返しを書けるのが入れ子外側が 1 回進むあいだに,内側は最後まで回る
  • 中身が実行される回数は外側 × 内側.回数は掛け算で増える.
  • どの行がどの繰り返しに属するかは,字下げの深さだけで決まる.1 段ずれると,エラーも出ないまま別の絵になる.
  • 外側のループ変数を内側で使うと,1 個ずつ大きさや角度が変わる模様ができる(貝殻・目玉).
  • % は割り算のあまり.i % 2 で交互,i % 3 で 3 つ周期.if と組み合わせて色や形を変える.
  • 外側を,内側をと考えると,格子状に並べられる.内側の回数を外側の変数にすれば階段状になる.
  • 行と列の考え方は文字の表にも使える.print(x, end=" ") で横に並べ,1 行ぶん終わったところで print() して改行する.
  • 入れ子は絵だけのものではない.外側で調べる数を,内側でその数を調べる手順を回せば,素数を見つけるようなアルゴリズムが書ける(演習 7-9).
  • 入れ子は描きすぎに注意.まず少ない回数で試し,形が決まってから増やす.while True: は使わない(動かし続けるのは第 10 章の ontimer).

次の回では,かめを増やしますTurtle() と書くと,かめが何匹でも生まれます. 1 匹ずつ名前をつけて,別々の場所・別々の色で動かせるようになります. 今回の入れ子とはちがう,登場人物が何人もいるプログラムの書き方です.