特殊な2倍関数

Herbertは,4つの移動方向を持つという意味で,
4という数は少し特別です.例えば特定の動作を4回繰り返し,
さらにはそれをさらに向きをかえて4回繰り返すなどは
そこそこ頻繁に要求されるように思います.

4倍すべきものが何かの2倍だったりすることも多く,
4倍したいけど2倍関数を用意しておく方が賢い場面はしばしばあります.
実際,m(X):XXXX,m(p)m(X):XX,m(m(p))では
後者の方が少ないんですよね.4倍を3回やると4倍関数の方が良いので
一概には何とも言えませんが,小回りが利く2倍関数は重要です.


いきなりですが,田の字を描く次のコードを見てみましょう.

w(X):XX
w(w(w(w(sr))r))

4倍したものを,向きを変えてさらに4倍しています.

この動きとほぼ同じ動きを,同byte数の別のコードでも書くことができます:

w(X):XrX
w(w(w(w(s))r))

動き終わった際の向きが違います("r"が足りない)が,同じ経路を辿ります.
2倍関数に方向転換を織り交ぜてあるため,関数の定義自体は1byte余分ですが,
実行ラインで1byteの得をしており,合計で同じbyte数のコードになっています.


なお,「2倍関数に方向転換を混ぜる」という発想でw(X):XXrなどの関数を
定義するという発想もありそうですが,この関数で同経路を辿るとより多くの
bytes数を必要とします.実はXXrrXXなどの関数は,
「4倍を作る」のには向いていません."r"の位置を少し変えただけで
大きく性質が変わって不思議な感じがするかもしれませんね.
これについては変数変換の講でも触れようと考えています.

逆に言うと今回の2倍関数w(X):XrXは4倍操作との相性が良いです.
より一般的に,w(X):XpXの形の2倍関数は4倍操作との相性が良いです.
具体的には,w(w(X))と2回合成すると,

w(w(X))=XpXpXpX

となって,"Xp"の4倍からpだけ足りないものが出てきます.
w(X):XrX,w(w(w(w(s))r))というコードで,田を描くことや
元の向きと変わったことの理由が分かるのではないかと思います.
XlXやXrXとして使うことがやはり多いですが,XsXなどの2倍関数が
活きることもあるかもしれませんね.


特殊な2倍関数を用いても,結局普通の2倍関数と同byteのコードになりました.
したがって結局この新しい2倍関数は役に立たない……わけではありません.
他の部分で,普通の2倍関数よりも得を出来れば良いのです.
最後に1つコードを紹介しましょう.

w(X):XrX
a(X):w(w(w(w(XX))r))a(w(s)lX)
a()

Editなどで動かしてみてください.他の方法で20byteで書けるでしょうか?


今回は2回繰り返しという項目でXrXという補助関数を紹介しましたが,
単純な繰り返し以外でも,良い補助関数を用意することで
得が出来る場面は結構あります.大幅な更新よりも,最後の
1byteを詰めるときに使う程度だと思いますが….
規則が少なく根気強くなぞるような問題でも,
「良い補助関数の利用」という視点は研究しがいがありそうです.


戻る inserted by FC2 system