いきなりですが次のコードを見てみましょう:
a(X):XXXXrXXXXa(sX)16byteで2重の正方形を回りながら描きますね.
a(r)
これを2倍関数により解消しても,実は短縮にはなりません.
w(X):XXこれだと17byteでかえってbyte数が増えてしまっています.
a(X):w(w(XX)r)la(sX)
a(r)
w(X):XrX
a(X):w(w(w(X))r)a(sX)
a()
再帰の一部ではなく,次のような状況ならどうするでしょうか?
ssssrssssこれならわざわざ2倍関数を定義する人は少ないと思います.
p:ssのようにすれば短縮になりますね.実は同じようなことを再帰の一部でも使うことができます.
pprpp
具体的には次のようなコードで1byteの短縮に成功しています.
(実は最初のコードと少し向きが違うものを描くのですが…見逃してください.)
a(X,Y):YrYa(sX,XXXX)まさに,「Y=XXXX」として,XXXXを他の文字で置いているのが分かりますよね.
a(r,)
他にもXYXやXllXなどを他の文字で置くことにより短縮につながることがあります.
もちろんn倍関数などを使うのが有利な場合もあるので,
(いつも書いているけど)色んな方法を念頭に置くようにしてください.
この方法にはいくつか注意点があります.これはこの方法を使うときの
リスクであるとともに,裏を返せば「この方法だからこそ書けるコード」に繋がる可能性もあります.
まずは,「何段階目か」がずれるということです.
先ほどのコードでは,再帰の「YrY」の部分はとして実行されるものは次のようになります:
1段階目:r2段階目のYに1段階目のXが代入されるため,1段階目の実行では1段階目のXは反映されていないのです.
2段階目:[rrrr]r[rrrr]
3段階目:[srsrsrsr]r[srsrsrsr]
4段階目:[ssrssrssrssr]r[ssrssrssrssr]
つまり1段階目のYは,ある意味で使われていないのです.実は
ここを有効利用することもできます(特別な初項の講でも説明する予定です).例えば
a(X,Y):YrYa(sX,XXXX)などと実行してみてください."sssrsss"が実行
a(r,sss)
1段階目:[sss]r[sss]と実行されていくのが分かると思います.初期位置を調整しながら
2段階目:[rrrr]r[rrrr]
3段階目:[srsrsrsr]r[srsrsrsr]
4段階目:[ssrssrssrssr]r[ssrssrssrssr]
次の注意点を述べましょう.例えば
a(X):XXrXXrXXrXa(sX)というコードを見てみましょう.「XXr」が多量に含まれるためにそこを文字で置いて
a()
a(X,Y):YYYXa(sX,XXr)としたくなる場面ですね.実はこれではズレてしまいます.
a(,)
このように中途半端に他変数Yに預けると,XそのものとYで成長速度に差が出るのです.
「わざと差をつける」ことで巧妙な短縮が出来る場面もあるのでテクニックとして
覚えておくとよいですが,慣れないうちは間違えやすいので気をつけてください.
なおこのことを(3倍関数などを使わず)解消するには,Xも成長速度を遅らせる方法があります.
a(X,Y,Z):YYYZa(sX,XXr,X)(なお,実は上のコードはa(X,Y):YYYXa(sX,XrX), a(,)を実行したものと同じになります.
a(,,)