Pythonのタートル・グラフィックス(3):クローンkameによる複雑再帰

「Turbo Graphics」(安齋利洋・伊吹龍著;1987年)にはもう少し複雑なkameの再帰描画の例が載っている。プログラムをなぞってPythonで書くと以下のようになる:


#coding: utf-8

import turtle

def sugata( center, size):
    for i in range(6):
        painter = center.clone()
        painter.fd(size)
        painter.rt(120)
        painter.fd(size)
        center.rt(60)

def kame( position, size):
    sugata( position, size)
    if size > 10:
        position.fd(size/2)
        kame(position, size/2)
        position.bk(size)
        kame(position, size/2)

    
if __name__ == '__main__':
    
    turtle.clearscreen()
    position = turtle.Turtle()
    position.ht()
    position.lt(90)
    kame( position, 200)

描画は以下のようになる:

kameの再帰描画

ご覧のように再帰の描画がずれたものになっている。

このずれの原因として考えられるものはオブジェクトを関数に渡す仕様がTurboPascalとPythonとで異なることにあるように思われた。そこで

def kame( positionT, size):
position = positionT.clone()

として関数の中で実引数が影響を受けないようにした。結果の描画は以下のようになる:

kameの再帰描画

これで期待した通りになったが、描画のアルゴリズムを変えてクローンを使わないことにしたい。

Pythonのタートル・グラフィックス(2):kameの単純再帰描画

Pythonのタートル・グラフィックス(1)で採り上げたKameの単純な再帰プログラムを考える。プログラムは以下のようなものである:


#coding: utf-8

import turtle

def sugata( center, size):
    for i in range(6):
        painter = center.clone()
        painter.fd(size)
        painter.rt(120)
        painter.fd(size)
        center.rt(60)

def kame( position, size):
    sugata( position, size)
    if size > 10:
        kame(position, size/2)
    
if __name__ == '__main__':
    
    turtle.clearscreen()
    position = turtle.Turtle()
    position.ht()
    position.lt(90)
    kame( position, 200)

実行結果の描画

kame2の描画

期待した結果である。

稲の「穂刈」と「根刈」

稲の刈り入れの季節である。今では刈り入れは稲の根元から刈り取る「根刈」である。

「栽培植物と農耕の起源」(中尾佐助著)の中でこの「根刈」と対比して「穂刈」を紹介している。原始的な農業では「穂刈」が一般的である。それは穂の脱落性(触れると落ちる)と出穂期(いっせいに穂がでるかどうか)の性質が、脱落性があり、出穂期が揃っていないからである。脱落性がなくなり出穂期がいっせいになるような改良がされると収穫方法も「穂刈」から「根刈」に移行する。

日本でも米の収穫は奈良時代までは「穂刈」で、平安時代になると「根刈」に移行したと言われている。

 

ノルウェーが締約国会議へ:NATO加盟国で初

今日の新聞の記事のタイトルである。

ノルウェー政府は来年3月開催予定の核兵器禁止条約締約国会議にオブザーバー参加をすることを明らかにした。北大西洋条約機構(NATO)の加盟国が会議への参加を表明するのは初めての由。

同国内では政府が条約に署名するよう求める声が高まっている。2019年の調査では有権者の78%が政府は条約に署名すべきたと回答。

ノルウェーでは政権交代が実現。中道左派・労働党と中央党の少数連立政権が誕生。この政府による参加表明である。

Pythonのタートル・グラフィックス(1):kameによるカメの描画

LibreLogoに関するブログを書いていたらPythonのタートル・グラフィックスことが気になった。

書架を見たら「Turbo Graphics」(安齋利洋・伊吹龍著;1987年)という昔使った本が目についた。これはTurbo Pascalを使ったグラフィックスの本である。この中にタートル・グラフィックスの例題が沢山あるので今回はこれらをPythonのタートル・グラフィックスで書いてみた。なるべく忠実に例題をなぞるようにした。

例題1:kame


#coding: utf-8

import turtle

def sugata( center, size):
    for i in range(6):
        painter = center.clone()
        painter.fd(size)
        painter.rt(120)
        painter.fd(size)
        center.rt(60)

def kame( position, size):
    sugata( position, size)
    
if __name__ == '__main__':
    
    turtle.clearscreen()
    position = turtle.Turtle()
    position.ht()
    position.lt(90)
    kame( position, 200)

多少気になったのは以下の部分である:

painter = center.clone()

Pascalでは単なる代入文でpainter=centerとなっている。Pythonでは代入文によるオブジェクトの代入はできない。copyモジュールのcopyメソッドを使ってみたが描画の一部が消えてしまう。deepcopyではTkinterのエラーがでる。Pythonのタートル・グラフィックのドキュメントにあったclone()で期待した通りの描画が得られた。clone()とcopyメソッドの相違は不明。

【結果の描画】

kame

なお描画ではカメ印(?)は隠してある。

Pythonでマクロ:LibreLogoで日本語プログラミング(2)

もう一つ実例を考える。

【実例2】


TO sugata nagasa
  REPEAT 2 [
    FORWARD nagasa
    LEFT 120 ]
  HOME
END

TO kame nagasa
  kakudo = 0
  REPEAT 6 [
    sugata nagasa
    kakudo = kakudo + 60
    RIGHT kakudo  ]
END

PENCOLOR “black”
HOME
kame 200

日本語化すると:


やるべきこと sugata nagasa
  繰り返し 2 [
    前へ nagasa
    左へ120 ]
  定位置へ
記述終わり

やるべきこと kame nagasa
  kakudo = 0
  繰り返し 6 [
    sugata nagasa  ;やるべきことsugata実行
    kakudo = kakudo + 60
    右へ kakudo  ]
記述終わり

ペンの色 “black”
定位置へ
kame 200 ;やるべきことkame実行

HOMEは「定位置へ」とした。インデントを使うと少し見やすくなる。

【結果の描画】

カメの描画

Pythonでマクロ:LibreLogoで日本語プログラミング

こんなプログラムを考える:


TO draw length  n
  IF n  = 0 [ 
    STOP ]
  angle = 60
  FORWARD length * n
  LEFT angle
  draw length n-1
  RIGHT 2 * angle
  draw length n-1
  LEFT angle
  BACK length * n
END

PENCOLOR “black”
draw 20 5
HOME
PENCOLOR “red”
draw 22 5

大文字のみの単語はLibreLogoの既約語である。この既約語を日本語で表現する。
例えば以下の様にしてみた:


やるべきこと draw length  n
  もしも n  = 0 [ 
    実行終了 ]
  angle = 60
  前へ length * n
  左へ angle
  draw length n-1
  右へ 2 * angle
  draw length n-1
  左へ angle
  後へ length * n
記述終わり

ペンの色 “black”
draw 20 5  ;やるべきことdrawの実行
定位置へ
ペンの色 “red”
draw 22 5 ;やるべきことdrawの実行

TO(やるべきこと)、END(記述終わり)あたりが難しい。プログラミングで使われている英単語は短くそれ自身では符牒のようなものだ。日本語化ではそれに捉われず多少冗長でも機能が明確になるような語句にするとよいと思った。

Pythonでマクロ:LibreLogoで再帰関数を実行する

LibreOfficeのWriter(文書処理)は一つの機能としてタートル・グラフィックスのためのプログラミング環境を提供している。それがLibreLogoである。文書処理の中にプログラミング環境を提供するという発想が面白い。コンピュータ・プログラミングの敷居を低めることができるかもしれない。LOGOに似た言語が使える。LibreLogoの詳細はここにある。

早速使ってみる。再帰関数が動くか確かめた。以下が使った再帰関数の一例である。

【再帰関数】


TO draw length  n
  IF n  = 0 [ STOP ]
  angle = 60
  FORWARD length * n
  LEFT angle
  draw length n-1
  RIGHT 2 * angle
  draw length n-1
  LEFT angle
  BACK length * n
END

draw 20 5

TO draw length nからENDまでが再帰関数の定義である。大文字ばかりの単語はLibreLogoの既約語である。これには日本語が使える。

【実行結果】

タートル・グラフィックス(中央にいるのがカメ)

LibreLogoで再帰処理ができることが解った。

Pythonでマクロ:AnimatedImageControlを使ってみる

Libreofficeのダイアログ画面上で一組の画像をアニメーションのように自動的に順次見せるAnimatedImageControlを使ってみた。

このAnimatedImageControlを使ったBasic言語による雛形はここにある。これをPythonに翻訳した。注意点は:

  • insertImageSet(0, 画像ファイルパスの配列)というメソッドがある。Basic言語では画像ファイルパスの配列にはそのまま配列名を書く。Pythonでは画像ファイルパスの配列としてリストやタプルで構成することができるが、リストではダメでタプルで作ったものを使う。
  • インポートしたモジュールで定義されている定数を実引数に使うメソッド、例えばsetPosSize(10, 10, 1000, 900, モジュール定義の定数)。Basic言語ではcom.sun.star.awt.PosSize.POSSIZEのように階層構造をそのまま書く。Pythonではunoモジュールで定義されいる関数を使う。つまりuno.getConstantByName(“com.sun.star.awt.PosSize.POSSIZE”)

【マクロ】


#coding: utf-8
import uno
import screen_io as ui
import unohelper

def python_macro_clipart_anim(*arg):
#
#シート
  doc = XSCRIPTCONTEXT.getDocument()
  sheet = doc.Sheets[0]
  #データのある行数を調べる
  sRange = sheet.getCellRangeByName("A1")
  sCursor=sheet.createCursorByRange(sRange)
  sCursor.collapseToCurrentRegion()
  MaxDataRow = sCursor.Rows.Count-1
  ui.Print(MaxDataRow)
  items=[]
  imageURLs=[]
  for  i in range(MaxDataRow):
    item = sheet.getCellByPosition(0, i+1 ).String
    filePath = sheet.getCellByPosition(1, i+1 ).String
    #ui.Print(item)
    #ui.Print(filePath)
    items.append(item)
    imageURLs.append(uno.systemPathToFileUrl(filePath))
  imageURLsT=tuple(imageURLs)
#
#ダイアログ
  ctx = XSCRIPTCONTEXT.getComponentContext()
  smgr = ctx.getServiceManager()
  dialogM = smgr.createInstance('com.sun.star.awt.UnoControlDialogModel')
  # Size of DialogM
  dlgWth = 500
  dlgHgt = 400
  dialogM.Width = dlgWth
  dialogM.Height = dlgHgt
  dialogM.Title = "クリップアート・アニーション"
#ダイアログの生成とモデルの登録
  dialog = smgr.createInstance('com.sun.star.awt.UnoControlDialog')
  dialog.setModel(dialogM)
#
#
  animCtrlModel = smgr.createInstance('com.sun.star.awt.AnimatedImagesControlModel')
  animCtrlModel.insertImageSet(0, imageURLsT)
  animCtrlModel.StepTime = 1000		
  animCtrlModel.AutoRepeat = False
  animCtrlModel.ScaleMode = 1
#アニメーション・コントロールの登録
  animateCtrl = smgr.createInstance('com.sun.star.awt.AnimatedImagesControl')
  animateCtrl.setModel(animCtrlModel)
#
  dialog.addControl("animated", animateCtrl)
  POSSIZE = uno.getConstantByName("com.sun.star.awt.PosSize.POSSIZE")
  animateCtrl.setPosSize(10, 10, 1000, 900, POSSIZE)
#
#窓の生成そしてこの窓をダイアログ画面として使う
  window = smgr.createInstance('com.sun.star.awt.Toolkit')
  dialog.createPeer(window,None)		# None : OK / none : NG
#
  animateCtrl.startAnimation()

  dialog.execute()
  dialog.dispose()

属性StepTime=1000で個々画像を一秒間表示するはずだがこの値を変えて表示時間に変化はない。また属性AutoRepeat = Falseで一組の画像の表示は一度のはずだが繰り返し表示される。

粟(アワ)と吉備(キビ)そしてMillet

紀元前4000年ごろの金石併用時代のウクライナ周辺の考古学の本(英文)を読んでいると出土した陶器の破片に穀物の種による圧痕があり当時の栽培植物が推定できるという記述によく遭遇する。その栽培植物の一つにMillet(英語)がある。このMilletは英和辞書では①アワ(粟)、②キビ(吉備)となっている。併記されている学名がPanicum sativumとなっていることからこの植物はキビであることがわかる。

キビはインド原産であるが、アワは中央アジア、インド亜大陸などが原産地となっていてキビ以上に人類の食料として重要であったことが示唆されている、古代中国では北の地方ではアワが主食であった由。「米」という漢字も本来はアワを示す文字であったといわれている。米は華南のものであった。西から来た「米」が粟だったのかもしれない。