CoderDojo 天白

CoderDojo天白の開催記録と技術的なメモ

Pythonでシェルピンスキーの三角形を描く

まえがき

CoderDojo天白を6年程度、運営してきて、Scratchをある程度、描けるようになって、つぎの段階として何をすればわからないとのことで卒業していく忍者も多いようです。Dojoとすれば、テキスト・プログラミングをと思っていましたが、何をすればいいかわからない。プロのプログラマーに聞いてもやりたいことによるということで、鶏と卵のような話になってしまうので困ります。

Dojoでは模様を描くのに興味を持った忍者に、とりあえずは、processingを勧めました。今でも熱心に取り組んでくれています。

その次に取り上げたのはUnityでした。楽しいゲームをつくるという観点からの授業をやりましが、どうも人が集まらなくて現在に至っています。

また、Pythonがわかりやすいよという声もありますが、昔、ちょっとやったときは遅い感じでもあり、魅力を感じませんでした。最近、pygameというのを知って、さらにpygame zeroというのを知って、ゲームに使えるのかなという気にもなって、ちょっとテストをしてみました。

実施内容

今回、実施したのは次のようなことです。

  1. プロジェクト: シェルピンスキーの三角形

  2. python はつぎの3種

  3. エディターはMuを用いました。

※ なお、参考としてScratchとprocessingを行ないました。

実施結果

Scratchの場合

プログラムは次のような感じになります。

f:id:whomeantan:20210204002406p:plain

再帰プログラムのいい例題だと思います。

結果は次のようになります。

f:id:whomeantan:20210202173556p:plain

ターボモードにすれば一瞬ですが、通常モードで一つ一つ描いていくので再帰の書き方がよくわかります。

これが今回の比較の基準になります。

Turtle Graphics の場合

プログラムは次のような感じになります。

from turtle import *

WIDTH = 600
HEIGHT = 600
Screen().bgcolor("blue")

speed(0)

kame = Turtle()
kame.shape("turtle")
kame.color("white")
kame.pensize(0.5)


def triangle(length, kaisuu):
    if kaisuu != 0:
        for i in range(3):
            kame.forward(length)
            kame.left(120)
            triangle(length / 2, kaisuu-1)


kame.penup()
kame.goto(-200, -200)
kame.pendown()

triangle(400, 5)  

ほとんど、Scratchの通りですね。

描画速度は亀が一つ一つ書いていくので遅くなります。Scratchの普通のモードで描いた感じです。

f:id:whomeantan:20210202202655p:plain

途中までで止めましたが、書き順がしっかりとわかります。

※ MuのモードはPythonのモードです。

pygame zeroの場合

プログラムは次のような感じになります。

import math

WIDTH = 600
HEIGHT = 600
x0 = 100
y0 = 500
theta = 0

def draw():
    screen.fill((0, 0, 255))
    draw_triangle(400, 8)


def draw_triangle(length, kaisuu):
    global x0, y0, theta
    if kaisuu != 0:
        for i in range(3):
            x1 = x0 + length * math.cos(math.radians(theta))
            y1 = y0 + length * math.sin(math.radians(theta))
            screen.draw.line((x0, y0), (x1, y1), "white")
            x0 = x1
            y0 = y1
            theta -= 120
            draw_triangle(length/2, kaisuu-1)

前に進むという命令がないので、次々に終点を計算して2点間の線を結んでいます。これもScratchと同じような流れで作れますね。

なお、120度を加えるのにラジアンでなく、角度で表して、sin,cosの中でラジアンに変更するほうが精度がいいようでした。

global を関数の中で再宣言するのにおどろきました。

また、kameが線を引くというのではなく、Screenに直接描くという雰囲気でした。

f:id:whomeantan:20210202211845p:plain

若干、立ち上がりに時間がかかりました。

※ Muのモードはpygame zeroで行います。

pygame の場合

プログラムは次のような感じになります。

import pygame, sys, math
from pygame.locals import *

pygame.init()

BLUE  = (0,0,255)
WHITE = (255,255,255)

DISPLAYSURF = pygame.display.set_mode((600,600))
DISPLAYSURF.fill(BLUE)
pygame.display.set_caption("TRIANGLE")
x0 = 100
y0 = 500
theta = 0

def draw_triangle(length, kaisuu):
    global x0, y0, theta
    if kaisuu != 0:
        for i in range(3):
            x1 = x0 + length * math.cos(math.radians(theta))
            y1 = y0 + length * math.sin(math.radians(theta))
            pygame.draw.line(DISPLAYSURF,WHITE, (x0,y0),(x1,y1))
            x0 = x1
            y0 = y1
            theta -= 120
            draw_triangle(length/2, kaisuu-1)

while True:
    draw_triangle(400,8)
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

ちょっと大げさな書き方もありますが、プログラムらしくなってきました。

結果は同じですが、上にTriangleというラベルもついています。終了条件もはっきりしています。zeroの場合は僕の勉強不足かもしれませんが・・・

f:id:whomeantan:20210202231719p:plain

※ MuのモードはPythonで行います。

processingの場合も参考につけます

プログラムはこんな感じです。

float x0 = 100;
float y0 = 400;
float x1, y1;
float theta = 0;

void setup(){
    size(600,500);
    background(0,0,255);
    stroke(255,255,255);
    smooth();
    draw_triangle(400,8);
}

void  draw_triangle(int length, int kaisuu){
    if (kaisuu != 0){
        for( int i = 0; i<3; i++){
            x1 = x0 + length * cos(radians(theta));
            y1 = y0 - length * sin(radians(theta));
            line(x0, y0, x1, y1);
            theta += 120;
            x0 = x1 ;
            y0 = y1 ;
            draw_triangle(length / 2, kaisuu-1);
        }
    }
}

まとめ

今迄、pythonは遅いと思っていたけれど、なんとかゲームにも使えるのではないかという気がしてきた。次回は簡単なゲームをつくってみたい。